I want to have a loop running that will print "Hello" and when I press "K" it stops printing but it doesn't end the program, then when I press "K" again it starts printing again.
I tried this(using the keyboard module):
import keyboard
running = True
while running == True:
print("hello")
if keyboard.is_pressed("k"):
if running == True:
running = False
else:
running = True
but when I press the button it just ends the program and that's not what I'm trying to do. I understand why it ends but I don't know how to make it not end. How can I do that?
import keyboard
running = True
display = True
block = False
while running:
if keyboard.is_pressed("k"):
if block == False:
display = not display
block = True
else:
block = False
if display:
print("hello")
else:
print("not")
Maybe something like that:
import keyboard
running = True
stop = False
while !stop:
if keyboard.is_pressed("k"):
running = !running # Stops "hello" while
if keyboard.is_pressed("q"):
stop = !stop # Stops general while
if running:
print("hello")
You could use a handler for the keypress, which sets an event that the main thread can then test for periodically, and wait if required.
(Note that there are two types of events here, the keypress event and the setting of the running, so these should not be confused.)
from threading import Event
from time import sleep
import keyboard
hotkey = 'k'
running = Event()
running.set() # at the start, it is running
def handle_key_event(event):
if event.event_type == 'down':
# toggle value of 'running'
if running.is_set():
running.clear()
else:
running.set()
# make it so that handle_key_event is called when k is pressed; this will
# be in a separate thread from the main execution
keyboard.hook_key(hotkey, handle_key_event)
while True:
if not running.is_set():
running.wait() # wait until running is set
sleep(0.1)
print('hello')
import sys
import keyboard
from time import sleep
running = True
while running:
if keyboard.is_pressed("k"):
sleep(1)
elif keyboard.is_presed('Esc'):
sys.exit()
else:
print("hello")
I didnt test it, so please give me feedback
I think the right way is flushing the buffer, because the previous solutions may print more. This works for windows, for Linux, you should refer to Python read a single character from the user
import time
import subprocess
import sys
import msvcrt
printing = True
while (1):
# Try to flush the buffer
while not msvcrt.kbhit() and printing:
print("hello")
doit = msvcrt.getch().decode('utf-8')
if doit=="k":
printing = not printing
print("stop/start")
if doit == 'q':
break
This is the output of this code:
Please note that, if you add print("stop/start") in Adrian Melon's program, you can see his program prints several time "hello" after 'k' is pressed until the buffer will be empty.
import keyboard
running = True
display = True
block = False
while running:
if keyboard.is_pressed("k"):
print("stop/start")
if block == False:
display = not display
block = True
else:
block = False
if display:
print("hello")
else:
pass
This is the output of #Adrian-Melon program:
import keyboard
running = True
display = True
block = False
while running:
if keyboard.is_pressed("space"):
if block == False:
display = not display
block = True
else:
block = False
if display:
print("hello")
else:
input("Press Enter to continue...")
if block == False:
display = not display
block = True
You can use this to stop and start again.
Related
I'm writing a script for game, i need to bind some key for pressing right click for three times. I can do it, but if i will use it in game i can press WASD or something else when i using hotkey and it doesn't work.
My code here :
import keyboard
import mouse
import time
iswork = False
def work():
global iswork
if iswork:
iswork = False
print("Script deactivated")
else:
iswork = True
print("Script activated")
keyboard.add_hotkey("F4",work)
def RRR():
if iswork :
for i in range(3):
mouse.right_click()
time.sleep(0.05)
bind = input("Bind for Right - Right - Right :")
#keyboard.add_hotkey(bind,RRR)
while iswork:
if keyboard.is_pressed("x") and len(keyboard._pressed_events) >= 1:
RRR()
elif keyboard.is_pressed("x"):
RRR()
while True :
count = 0
i'm initiating to python code and I need help :
How can I do a condition , if on the terminal , there is written like " {name} has said HEY " ?
Like if someone say HEY ( if it came out of the terminal ) , how I can transform it to a condition ?
Like " if HEY == on terminal "
print("Someone has said say !!!")
( I want to do this but with true python , Idk how to do It)
It looks like there is a similiar question answered at Looping until a specific key is pressed
I modified the code in the one I linked to modify a variable each time a key is was pushed in a specific order. I didn't make it where it had to be consecutive but after "h","e",&"y" are type in that order, it will stop with a printed message. There are a lot of ways to do this but this was the easiest way to show you that it can be done.
import keyboard
import time
import threading
class main:
def __init__(self):
# Create a run variable
self.run = True
# Start main thread and the break thread
self.mainThread = threading.Thread(target=self.main)
self.breakThread = threading.Thread(target=self.breakThread)
self.mainThread.start()
self.breakThread.start()
phrase = 'None'
def breakThread(self):
print('Break thread runs')
# Check if run = True
while True and self.run == True:
if keyboard.is_pressed('h'):
phrase = 'h'
if keyboard.is_pressed('e') and (phrase=='h'):
phrase = 'he'
if keyboard.is_pressed('y') and (phrase=='he'):
self.newFunction()
phrase = 'None'
break
def main(self):
print('Main thread runs')
# Also check if run = True
while not keyboard.is_pressed('esc') and self.run == True:
print('test')
time.sleep(2)
# Break like this
if keyboard.is_pressed('esc'):
break
print('test')
time.sleep(2)
def newFunction(self):
self.run = False
print('Password accepted')
print('You are in the new function!')
program = main()
I need to design a script that uses the top portion of the terminal as output where some lines are printed after each second in an infinite loop, and the bottom portion keeps taking user input and also printing them in the above portion (among the regular periodic outputs).
In other words, I need to design a sort of shell.
I tried multithreading with the naive approach like this:
#!/usr/bin/python3
from math import acos
from threading import Thread
from random import choice
from time import sleep
from queue import Queue, Empty
commandQueue = Queue()
def outputThreadFunc():
outputs = ["So this is another output","Yet another output","Is this even working"] # Just for demo
while True:
print(choice(outputs))
try:
inp = commandQueue.get(timeout=0.1)
if inp == 'exit':
return
else:
print(inp)
except Empty:
pass
sleep(1)
def inputThreadFunc():
while True:
command = input("> ") # The shell
if command == 'exit':
return
commandQueue.put(command)
# MAIN CODE
outputThread = Thread(target=outputThreadFunc)
inputThread = Thread(target=inputThreadFunc)
outputThread.start()
inputThread.start()
outputThread.join()
inputThread.join()
print("Exit")
But as obviously expected, the output lines merge with the input lines as the user keeps typing.
Any ideas?
As discussed in comments, used curses library.
Update
used two subwin for input and output
#!/usr/bin/python3
import curses
from math import acos
from threading import Thread
from random import choice
from time import sleep
from queue import Queue, Empty
commandQueue = Queue()
stdscr = curses.initscr()
stdscr.keypad(True)
upperwin = stdscr.subwin(2, 80, 0, 0)
lowerwin = stdscr.subwin(2,0)
def outputThreadFunc():
outputs = ["So this is another output","Yet another output","Is this even working"] # Just for demo
while True:
upperwin.clear()
upperwin.addstr(f"{choice(outputs)}")
try:
inp = commandQueue.get(timeout=0.1)
if inp == 'exit':
return
else:
upperwin.addch('\n')
upperwin.addstr(inp)
except Empty:
pass
upperwin.refresh()
sleep(1)
def inputThreadFunc():
while True:
global buffer
lowerwin.addstr("->")
command = lowerwin.getstr()
if command:
command = command.decode("utf-8")
commandQueue.put(command)
lowerwin.clear()
lowerwin.refresh()
if command == 'exit':
return
# MAIN CODE
outputThread = Thread(target=outputThreadFunc)
inputThread = Thread(target=inputThreadFunc)
outputThread.start()
inputThread.start()
outputThread.join()
inputThread.join()
stdscr.keypad(False)
curses.endwin()
print("Exit")
Old Solution
I've edited your example to use getch insted of input
#!/usr/bin/python3
import curses
import datetime
from math import acos
from threading import Thread
from random import choice
from time import sleep
from queue import Queue, Empty
INFO_REFRESH_SECONDS = 1
commandQueue = Queue()
buffer = list() # stores your input buffer
stdscr = curses.initscr()
stdscr.keypad(True)
def outputThreadFunc():
outputs = ["So this is another output","Yet another output","Is this even working"] # Just for demo
info = choice(outputs), datetime.datetime.now()
while True:
if datetime.datetime.now() - info[1] > datetime.timedelta(seconds=INFO_REFRESH_SECONDS):
# refresh info after certain period of time
info = choice(outputs), datetime.datetime.now() # timestamp which info was updated
inp = ''
buffer_text = ''.join(buffer)
try:
command = commandQueue.get(timeout=0.1)
if command == 'exit':
return
inp = f"\n{command}"
except Empty:
pass
output_string = f"{info[0]}{inp}\n->{buffer_text}"
stdscr.clear()
stdscr.addstr(output_string)
stdscr.refresh()
if inp:
# to make sure you see the command
sleep(1)
def inputThreadFunc():
while True:
global buffer
# get one character at a time
key = stdscr.getch()
curses.echo()
if chr(key) == '\n':
command = ''.join(buffer)
commandQueue.put(command)
if command == 'exit':
return
buffer = []
elif key == curses.KEY_BACKSPACE:
if buffer:
buffer.pop()
else:
buffer.append(chr(key))
# MAIN CODE
outputThread = Thread(target=outputThreadFunc)
inputThread = Thread(target=inputThreadFunc)
outputThread.start()
inputThread.start()
outputThread.join()
inputThread.join()
stdscr.keypad(False)
curses.endwin()
print("Exit")
The simplest solution is to use two scripts; One, a server that prints the output, and the other, a client that sends the user's input to the server. Then you can use a standard solution like tmux to open the two scripts in two panes.
The two are merging because of the way the terminal writes to the output. It collects outputs in a buffer, and when the time is right it outputs everything at once. An easy fix would be to use a '\n' before each actual statement so that each new output is on a separate line.
#!/usr/bin/python3
.
.
.
if inp == 'exit':
return
else:
print("\n", inp) # CHANGE OVER HERE
.
.
.
command = input("\n> ") # CHANGE OVER HERE
if command == 'exit':
return
.
.
.
print("Exit")
Beware that since two threads are running in parallel, the next output will print before you are done typing and pressing enter to the input (unless you can type really fast and have really fast reflexes). Hope this answers your question!
The goal of this script is to make a switch and let the user toggle it ON and OFF with a key press, and when the switch is ON, the script should execute a loop that print a message in the terminal. In another words, The goal is to repeatedly print a message when the switch is ON
Here is what i have tried:
import keyboard
import time
switch = 0 # The switch variable
def check_start():
global start
if keyboard.is_pressed("F5") and start == 0: # If F5 is pressed, turn ON print message loop
switch = 1
print(switch)
time.sleep(0.1) # This is to prevent the user toggling the switch too fast
if keyboard.is_pressed("F5") and start == 1: # If F5 is pressed again, turn OFF print message loop
switch = 0
print(switch)
time.sleep(0.1)
def print_name(): # If the switch is ON, it should print two seperate message with a 10 seconds interval
if start == 1:
print("start")
time.sleep(10)
print("end")
while True:
check_start()
print_name()
Here is the output of the script:
1
start
end
start
end
0
1
start
end
0
Now here's the problem:
The user cannot turn off the switch while the print loop is in progress. For example the user cannot turn off the script if the message "end" has not printed, the user can ONLY turn off the switch exactly after "end" has printed, and if the user has missed the opportunity to turn off the switch, he must wait 10 more seconds to turn it off. What i expected is the user can toggle On and OFF anytime s/he wishes to.
Is this possible to do in without importing too much module?
you can put an if condition inside your loop to do a break at a specific key
ex:
if keyboard.is_pressed("F5") and start == 1:
break
this would exit your infinite loop, although a more elegant code would work like this:
def check_start():
global start
if keyboard.is_pressed("F5") and start == 0:
#DO stuff
return True
if keyboard.is_pressed("F5") and start == 1:
#DO stuff
return False
while check_start():
print_name()
Here is a cleaner, more reliable approach using keyboard's built-in add_hotkey method.
Below is a simple program to toggle printing of the current timestamp.
import keyboard as kb
from datetime import datetime as dt
global print_flag
print_flag = False
def toggle_print():
global print_flag
print_flag = not print_flag
kb.add_hotkey('d', toggle_print)
while True:
timestamp = dt.now()
if print_flag:
print(timestamp)
everything works except the next song doesn't play after the first is finished.
import os, random
from pygame import mixer
from pynput import keyboard
startup = 0
pause = 0
volume = 0.5
def Picker():
global startup
global volume
startup += 1
if startup > 1:
ThisSong = random.choice(os.listdir("C:\\Users\\...\\Music"))
NextSong = random.choice(os.listdir("C:\\Users\\...\\Music"))
ThisSong = NextSong
if ThisSong != NextSong:
mixer.init()
mixer.music.load("C:\\Users\\...\\Music" + ThisSong)
mixer.music.play(0)
mixer.music.set_volume(volume)
while mixer.music.get_busy():
def on_press(key):
global pause
global volume
if key == keyboard.KeyCode(char='-'):
volume -= 0.1
if volume < 0.1:
volume = 0.1
mixer.music.set_volume(volume)
if key == keyboard.KeyCode(char='='):
volume += 0.1
if volume > 1:
volume = 1
mixer.music.set_volume(volume)
if key == keyboard.KeyCode(char='['):
pause += 1
if pause == 1:
mixer.music.pause()
pause = 2
if pause == 3:
mixer.music.unpause()
pause = 0
with keyboard.Listener(on_press=on_press) as listener: listener.join()
else:
Picker()
else:
pass
Picker()
Picker()
screenshot of code
I can't get it to work, i'm very new to python so i'm probably missing something
obvious
Before starting: Thx #JGreenwell for copying the code.
Ok, so first, I’ll help you clean your code.
Things that are wrong
Having all that ThisSong and NextSong things: It won’t get saved when you restart Picker(). Either just have ThisSong, or place the ThisSong and NextSong assignment with the volume and pause variables:
.
pause = 0 # this is a problem! Next point
volume = 0.5
ThisSong = random.choice(...)
NextSong = random.choice(...)
The pause variable should be a boolean (True/False) and the pausing code should be like this:
.
pause = not pause
if pause:
# pause
else:
# unpause
Also, it would ideally be called paused
on_press and the Listener declaration should be outside the while loop, because otherwise they just keep being declared every time it loops. Then you should import time and put time.sleep(500) or something like that in the while loop, so that it doesn’t check every fraction of second.
As for the next song not playing, I don’t really know, but I’d suggest entering Picker() in the shell after the program has run (python -i script.py from CMD, IDLE leaves you in a shell by default). I would also suggest really following recommendation #3 as having them in the loop may break the loop and stop it from finishing. Most importantly, I would ask you to debug your code by adding print in every step of your code:
print(1)
if something:
print(2)
etc...
And seeing where it blocks
P.S.: The random dots are because you can’t have code in lists, so I had to exit the list.
Working solution, incase anyone else has the same problem as me in the future :)
from pygame import mixer
from pynput import keyboard
import threading
import random
import os
paused = 0
def player():
song = random.choice(os.listdir("C:\\users\\...\\desktop\\music"))
mixer.init()
mixer.music.load("C:\\users\\...\\desktop\\music\\" + song)
mixer.music.play(0)
while mixer.music.get_busy():
pass
else:
player()
def main():
t = threading.Thread(target = player, name = 'thread1', args = ())
t.start()
main()
def on_press(key):
global paused
if key == keyboard.KeyCode(char='['):
paused = not paused
if paused:
mixer.music.pause()
else:
mixer.music.unpause()
with keyboard.Listener(on_press=on_press) as listener: listener.join()