while building a script that can be toggled to spam. I encountered the following problem. first is the normal functioning version of the script:
import keyboard
import threading
def spam_this():
status = 0
while True:
if keyboard.is_pressed("F9") and status == 0:
status = 1
event.wait(1)
if keyboard.is_pressed("F9") and status == 1:
status = 0
event.wait(1)
while status == 1:
if keyboard.is_pressed("F9") and status == 1:
status = 0
event.wait(1)
print("test")
event = threading.Event()
threading.Thread(target=spam_this).start()
the script above works perfectly. however, when I change the line print("test")
to keyboard.write("test")
. the script breaks.
import keyboard
import threading
def spam_this():
status = 0
while True:
if keyboard.is_pressed("F9") and status == 0:
status = 1
event.wait(1)
if keyboard.is_pressed("F9") and status == 1:
status = 0
event.wait(1)
while status == 1:
if keyboard.is_pressed("F9") and status == 1:
status = 0
event.wait(1)
keyboard.write("test")
event = threading.Event()
threading.Thread(target=spam_this).start()
this version of the script with the keyboard.write()
function can be initiated with the implimented toggle key "F9", but when I try to toggle off the switch by pressing "F9" again, it does not stop like the print("test")
version of itself.
note: I am not sure how to word this problem in the title. I use the term "blocked" because the effect is similar to what blocking method like time.sleep()
would do when trying to create a while True:
loop with a toggle.
CodePudding user response:
keyboard
may run own code also in thread
and there can be conflict between two threads. Python uses GIL
to run only one thread at a time - so when your thread is running then it may block thread which should write text on screen. Code works better if I use even.wait(0.1)
after write()
so Python can switch threads and send text on screen. If you use longer value then it also work but if you press key very fast then it may stil run write
or wait
and it can't check is_pressed("F9")
and not stop it - you should see it if you use event.wait(1)
after write
There is also other problem - it may write last text after pressing key and it should use break
to exit while
and skip write
import threading
import keyboard
def spam_this():
status = 0
while True:
if keyboard.is_pressed("F9") and status == 0:
status = 1
event.wait(1)
if keyboard.is_pressed("F9") and status == 1:
status = 0
event.wait(1)
while status == 1:
if keyboard.is_pressed("F9") and status == 1:
print('stop')
status = 0
event.wait(1)
break
keyboard.write("test")
event.wait(0.1)
event = threading.Event()
threading.Thread(target=spam_this).start()
But I would reduce it to
import threading
import keyboard
def spam_this():
print('start spam_this')
status = False
while True:
if keyboard.is_pressed("F9"):
status = not status
print('status:', status)
event.wait(0.1)
if status is True:
keyboard.write("test")
event.wait(0.1)
event = threading.Event()
threading.Thread(target=spam_this).start()
But it has another problem - if you keep pressed key longer time then it will switch status
many times. I added print('status:', status)
to show it.
I was thinking to use keyboard.add_hotkey
like this
import threading
import keyboard
# global variable
status = False
def spam_this():
print('start: spam_this')
while True:
if status is True:
keyboard.write("test")
event.wait(0.1)
def test():
global status
status = not status
print('change:', status)
event.wait(0.5)
event = threading.Event()
threading.Thread(target=spam_this).start()
keyboard.add_hotkey("F9", test)
keyboard.wait()
but when you keep pressed key then system may start sending the same key again.
I didn't test keyboard.on_press_key()
- maybe it would resolve it.
Doc: keyboard
CodePudding user response:
import threading
import keyboard
# global variable
status = False
def spam_this():
print('start: spam_this')
while True:
if status is True:
print("test")
keyboard.write("test")
event.wait(0.1)
def test(event=None):
global status
status = not status
print('change:', status)
event = threading.Event()
keyboard.add_hotkey("F9", test)
#alternatively:
#keyboard.on_key_press("F9", test)
threading.Thread(target=spam_this).start()
there are a few modifications that has been made to @furas's answers.
for the
test
function, a parameterevent=None
was added, otherwise thekeyboard.on_press_key
will pass theF9
key-pressed-event to the test function, which results in atypeError
.in the
test
function, theevent.wait()
was removed due to an error, and upon testing, thekeyboard.on_press_key
andkeyboard.add_hotkey
function does have inbuilt delays, so as long as theF9
key was not HELD down, the inbuilt delays are more than enough.regardless of whether using
on_key_press
oradd_hotkey
, the thread should be initialized AFTER the desired "hotkey method" is called. otherwise the thread will block the main loop of the python script.(this part I cannot explain why, it was just trial and error leading to this conclusion.)the
keyboard.wait()
was removed, because this function was not used.
NUMBER 1 and 3 ARE THE MOST IMPORTANT CHANGES (for the people who doesn't want to read through the minor bits)