I really need an asyncio compatible getkey() so I can
async def stuff():
await getkey()
So when the coroutine stuff hits the await our loop stops the task, and continues on another one.
I am new to coding but there sure is such a thing somewhere?
If not, it is possible to build such a coroutine or not?
The getkey() could return the pressed key value in any form.
But it should have cbreak and noecho on (Don't wait for enter and Don't print the pressed key).
(clarification, no real need to continue read.)
please help me^^ I know, that this way of doing it seems unusual. Curses running in it's own thread would be the right way to go. But I can use curses only for displaying.. also I am really new to coding.. and I have no time to look into this threading thing:/ I just need my 100 lines to work fluently really fast and also only once :!
If you don't want to actually wait for the keypress, one way is to use a thread to detect the keypress:
from threading import Thread
import curses
key_pressed = False
def detect_key_press():
global key_pressed
stdscr = curses.initscr()
key = stdscr.getch()
key_pressed = True
def main():
thread = Thread(target = detect_key_press)
thread.start()
while not key_pressed:
print('Hello world\r')
curses.endwin()
main()
It's not exactly nice to use global variables, but it's a quick way to do it.
Here's a solution using keyboard instead of curses:
import keyboard
import time
from threading import Thread
key_pressed = False
def detect_key_press():
global key_pressed
while not keyboard.is_pressed('q'):
pass
key_pressed = True
def main():
thread = Thread(target = detect_key_press)
thread.start()
while not key_pressed:
print("Waiting for keypress...")
time.sleep(1)
main()
Starts a thread inside main that waits for keypress
Related
(Python 3.8.3)
I am using two python threads right now, one that has a while True loop
import threading
def threadOne():
while True:
do(thing)
print('loop ended!')
t1=threading.Thread(threadOne)
t1.start()
And another that checks for a ctrl+r input. When recieved, I need the second thread to tell the first thread to break from the while loop. Is there a way to do this?
Note that I cannot change the loop to 'while Break == False' as do(thing) waits for user input, but i need this to be interrupted.
The recommended way is to use threading.event (You can combine this with event.wait if you want to sleep in that thread too however as you are waiting for a user event, probably dont need that).
import threading
e = threading.Event()
def thread_one():
while True:
if e.is_set():
break
print("do something")
print('loop ended!')
t1=threading.Thread(target=thread_one)
t1.start()
# and in other thread:
import time
time.sleep(0.0001) # just to show thread_one keeps printing
# do something for little bit and then it break
e.set()
EDIT: To interrupt the thread while it's waiting for user input you can send SIGINT to that thread and and it will raise KeyboardInterrupt which you can then handle. Unfortunate limitation of python, including python3, is that signals to all threads are handled in the main thread so you need to wait for the user input in the main thread:
import threading
import sys
import os
import signal
import time
def thread_one():
time.sleep(10)
os.kill(os.getpid(), signal.SIGINT)
t1=threading.Thread(target=thread_one)
t1.start()
while True:
try:
print("waiting: ")
sys.stdin.readline()
except KeyboardInterrupt:
break
print("loop ended")
So I have this small program (using Linux):
import getch
while True:
print("Hello World!")
key = getch.getch()
if key == 'q':
break
So all it does is wait for the user to hit a key, and they displays "Hello World!" to the console. However, is there a way so that I can continuously display "Hello World!" to the console, and the only way to get it to end is if the user presses the "q" key?
This question is similar to this one, but it's in C++.
My first thought was to look up threading, however, I tried all the threads I could find and none of them worked. Then I came across the Global Interpreter Lock (GIL), and it supposedly prevents "multiple native threads from executing Python bytecodes at once."
Then I tried to use multiprocessing, but it still didn't work for me. This is how far I got using it:
import multiprocessing
import getch
def test1():
print("Hello World!")
def test2():
key = getch.getch()
if key == 'q':
exit()
while True:
p1 = multiprocessing.Process(target=test1, args=())
p2 = multiprocessing.Process(target=test2, args=())
p1.start()
p2.start()
p1.join()
p2.join()
Am I missing something here? Or is there another way in which I can do something while also waiting for getch()? Or do I have to write this in another language that supports multithreading like C++?
Thanks
I was not able to install fetch, probably because I am on Windows at the moment, but you can implement what you want (However, is there a way so that I can continuously display "Hello World!" to the console, and the only way to get it to end is if the user presses the "q" key?) the following way:
import time
from threading import Thread
def another_thread():
while True:
time.sleep(2)
print("Working...\n")
def main_thread():
while True:
x = input("Press a key: \n")
if x == "q":
break
if __name__ == '__main__':
# create another Thread object
# daemon means that it will stop if the Main Thread stops
th = Thread(target=another_thread, daemon=True)
th.start() # start the side Thread
main_thread() # start main logic
I'm trying to share the class instance/object variables with other processes that I start within it, since I need to run multiple function at the same time, to record macros from the keyboard & mouse and re-play them latter at the same timing.
I see that it's possible to use multiprocessing.Manager, but i'm using concurrent.futures.ThreadPoolExecutor. is there a similar function there?
I wrote the code below now to clarify. The actual code has a setState function for settings the recording state and such, and the key that's pressed doesn't get passed. Also, the actual code obviously has a listener for the key presses and mouse moves, the getKey and getMove functions should be the ones appending to the list. The problem in this case is that the recording variable can't be accessed from the second process that should start recording moves once the "Insert" key is pressed. A function in concurrent that's similar to Manager in multiprocessing would solve it, but i'm not sure what it's called or to use it.
from concurrent.futures import ThreadPoolExecutor as Executor
import time
class recMacros(object):
def __init__(self):
self.recording = False
self.lastKey = None
self.lastMove = None
self.mouseMoves = []
self.keyPresses = []
self.runMacros()
def getTime(self):
return time.time()
def getKey(self):
#return keyboard listener last key pressed
return "W"
def getMove(self):
#return keyboard listener last key pressed
return "W"
def recMoves(self):
while True:
while self.recording:
mouseMove = self.getMove()
if mouseMove != self.lastMove:
self.mouseMoves.append((mouseMove, self.getTime()))
self.lastMove = mouseMove
def recPresses(self):
while True:
keyPress = self.getKey()
if keyPress == "Insert":
self.recording = True
elif keyPress == "End":
self.recording = False
elif self.recording and keyPress != self.lastKey:
self.keyPresses.append((keyPress, self.getTime()))
self.lastKey = keyPress
else:
print("Error")
def recMacros(self):
with Executor(max_workers=2) as e:
e.submit(recPresses)
e.submit(recMoves)
if __name__ == "__main__":
recMacros()
I'd appreciate some quick direction since i'm in a rush. Thanks in advance
#user2357112 supports Monica
Here's the code I used to test the timing, to verify that ThreadPoolExecutor is like a process to comes to running the functions in parallel:
from concurrent.futures import ThreadPoolExecutor
import time
def printTime():
print(f"Time: {time.time()}\n")
def runPro():
with ThreadPoolExecutor(max_workers=3) as e:
for i in range(3):
e.submit(printTime)
runPro()
If you want to save something in a variable that every process can use, you can use queue.
Import queue
import queue
Create a shared variable
shared_var = queue.Queue(maxsize=0)
where maxsize is the maximum that can be saved in this queue
Edit shared variable in any process
shared_var.put(item)
Get the things in the variable
variable = shared_var.get()
There is a lot more you can do with queue, see the documentation.
essentially my program listens for keystrokes and if it sees the "up" arrow pushed it starts printing the word test using a while loop that relies on "flag" being true. I would like the program to stop when the down key is pressed but I am unable to make that happen. I don't get any errors, it just doesn't stop.
Here is the code:
from pynput.keyboard import Key, Listener
flag = False
def doit():
while flag:
print("test")
def released(key):
global flag
if key == Key.up:
flag = True
doit()
elif key == Key.down:
print("stopped")
flag = False
with Listener(on_release=released) as listener:
listener.join()
When I press the down arrow "stopped" doesn't get printed so it seems like the if statement isn't being used at all. How can I fix this?
You're trying to do two things at once:
Listen for keyboard input
Do whatever doit() is supposed to do.
The following program starts doit() on a separate thread and thus allows the main-thread to continue listening for keystrokes.
from pynput.keyboard import Key, Listener
from threading import Thread
import time
flag = False
thread = None
def doit():
while flag:
print("test")
time.sleep(0.5)
def released(key):
global flag, thread
if key == Key.up:
flag = True
thread = Thread(target = doit)
thread.start()
elif key == Key.down:
print("stopped")
flag = False
if thread.is_alive():
thread.join()
with Listener(on_release=released) as listener:
listener.join()
thread.start() does not block execution, as doit() would. Only when calling thread.join() will the main-thread block until the thread is done. Notice that this depends on the main-thread setting flag = False, and without that, the thread might continue infinitely, and the main-thread would thus wait forever when calling thread.join().
There are a number of these kinds of problems that arise when stepping into the world of multithreading.
everytime when running this program, I hear my cpu fan is boosting. I suspected the busy waiting while loops in the code is the cause. I wonder how a real programmer will do to optimize this?
from multiprocessing import Process, Queue
import threading
class PThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
#view leave will set this event
self.event = threading.Event()
def run(self):
while 1:
if not self.event.is_set():
print 'run'
else:
break
def server_control(queue):
while True:
try:
event = queue.get(False)
except:
event = None
if event == 'DETECTED':
print 'DETECTED'
t = PThread()
t.start()
elif event == 'LEAVE':
print 'Viewer_left'
t.event.set()
t.join()
elif event == 'QUIT':
break
q=Queue()
p = Process(target=server_control, args=(q,))
p.start()
p.join()
If a thread needs to wait for an event, it should sleep until the event occurs, rather than busy-waiting. Your event object has a wait() method that can be used to accomplish that. Call it, and it won't return until some other thread has called set() on the event (or the timeout elapses, if you specify one). In the meantime, the thread uses no CPU.
The multiprocessing module has a clone of threading's event object
from multiprocessing import Process, Event
Instead of use a Queue. You should declare event of interest in your main and pass them to other process
In your case:
detected = Event()
leave = Event()
exit = Event()
Process(target=server_control, args=(detected, leave, exit))
and finally check if the event is fired or wait in your loop
You might make the loop a bit less tight by adding a time.sleep(0) in the loop to pass the remainder of the quantum to another thread.
See also: How does a threading.Thread yield the rest of its quantum in Python?