Threaded global keyboard events
up vote
0
down vote
favorite
I'm creating a PyQt Application. The main core/logic of the program runs in a separate loop I've created on a new thread. The core needs to be listening for defined hotkeys that will in turn trigger some functionality. I've removed all the logic and just made a dummy test scenario, as I'm really looking for feedback/help on structure/architecture. I'm very new to all of this.
I created a Keyboard class that also runs in its own thread, where you can register functions that will get called when a key is pressed.
import threading
from win32 import win32api
import win32con
import pythoncom
import pyHook
class Keyboard(threading.Thread):
def __init__(self):
super().__init__()
self.hook_manager = pyHook.HookManager()
self.hook_manager.KeyDown = self.on_keyboard_event
self._callbacks =
self.is_running = False
def stop(self):
self.is_running = False
self.hook_manager.UnhookKeyboard()
def run(self):
self.is_running = True
self.hook_manager.HookKeyboard()
while self.is_running:
pythoncom.PumpWaitingMessages()
def press(*args):
for arg in args:
win32api.keybd_event(arg, 0, 0, 0)
def release(*args):
for arg in args:
win32api.keybd_event(arg, 0, win32con.KEYEVENTF_KEYUP, 0)
def register_callback(self, f):
self._callbacks.append(f)
def on_keyboard_event(self, event):
print(event.KeyID)
for callback in self._callbacks:
callback(event)
return True
Now the core of the application. It has two main functions: it needs to switch between when running and the second one needs to run for a set amount of time then revert back to the first. The way I've handled this switching and looping seems really bad.
import time
class ThreadedTask(threading.Thread):
MODE_ONE = 0
MODE_TWO = 1
def __init__(self):
super().__init__()
self.is_running = False
self.processing_mode = 0
self.x = 0
self.keyboard = Keyboard()
self.keyboard.register_callback(self.key_pressed)
self.keyboard.start()
def stop(self):
self.is_running = False
def run(self):
self.is_running = True
while self.is_running:
if self.processing_mode == ThreadedTask.MODE_ONE:
self.function_one()
elif self.processing_mode == ThreadedTask.MODE_TWO:
self.function_two()
def function_one(self):
print("function_one")
y = self.x + 2
if y == 4:
self.processing_mode = 1
self.x = 0
time.sleep(0.3)
def function_two(self):
timeout = time.time() + 5
while self.processing_mode == ThreadedTask.MODE_TWO and time.time() < timeout:
print("function_two")
time.sleep(0.3)
self.processing_mode = 0
def key_pressed(self, event):
self.x = 2
And lastly, I feel like I'm going to encounter race conditions, what if the Keyboard calls the key_pressed function which modifies the value of x
while function_one
is trying to access x
. I know very little about threading, this is the first time I've tried it. The above code runs fine in my tests, but I read that race conditions are unpredictable, so that it running fine doesn't necessarily mean there isn't a problem.
To run the program:
task = ThreadedTask()
task.start()
python python-3.x multithreading thread-safety
add a comment |
up vote
0
down vote
favorite
I'm creating a PyQt Application. The main core/logic of the program runs in a separate loop I've created on a new thread. The core needs to be listening for defined hotkeys that will in turn trigger some functionality. I've removed all the logic and just made a dummy test scenario, as I'm really looking for feedback/help on structure/architecture. I'm very new to all of this.
I created a Keyboard class that also runs in its own thread, where you can register functions that will get called when a key is pressed.
import threading
from win32 import win32api
import win32con
import pythoncom
import pyHook
class Keyboard(threading.Thread):
def __init__(self):
super().__init__()
self.hook_manager = pyHook.HookManager()
self.hook_manager.KeyDown = self.on_keyboard_event
self._callbacks =
self.is_running = False
def stop(self):
self.is_running = False
self.hook_manager.UnhookKeyboard()
def run(self):
self.is_running = True
self.hook_manager.HookKeyboard()
while self.is_running:
pythoncom.PumpWaitingMessages()
def press(*args):
for arg in args:
win32api.keybd_event(arg, 0, 0, 0)
def release(*args):
for arg in args:
win32api.keybd_event(arg, 0, win32con.KEYEVENTF_KEYUP, 0)
def register_callback(self, f):
self._callbacks.append(f)
def on_keyboard_event(self, event):
print(event.KeyID)
for callback in self._callbacks:
callback(event)
return True
Now the core of the application. It has two main functions: it needs to switch between when running and the second one needs to run for a set amount of time then revert back to the first. The way I've handled this switching and looping seems really bad.
import time
class ThreadedTask(threading.Thread):
MODE_ONE = 0
MODE_TWO = 1
def __init__(self):
super().__init__()
self.is_running = False
self.processing_mode = 0
self.x = 0
self.keyboard = Keyboard()
self.keyboard.register_callback(self.key_pressed)
self.keyboard.start()
def stop(self):
self.is_running = False
def run(self):
self.is_running = True
while self.is_running:
if self.processing_mode == ThreadedTask.MODE_ONE:
self.function_one()
elif self.processing_mode == ThreadedTask.MODE_TWO:
self.function_two()
def function_one(self):
print("function_one")
y = self.x + 2
if y == 4:
self.processing_mode = 1
self.x = 0
time.sleep(0.3)
def function_two(self):
timeout = time.time() + 5
while self.processing_mode == ThreadedTask.MODE_TWO and time.time() < timeout:
print("function_two")
time.sleep(0.3)
self.processing_mode = 0
def key_pressed(self, event):
self.x = 2
And lastly, I feel like I'm going to encounter race conditions, what if the Keyboard calls the key_pressed function which modifies the value of x
while function_one
is trying to access x
. I know very little about threading, this is the first time I've tried it. The above code runs fine in my tests, but I read that race conditions are unpredictable, so that it running fine doesn't necessarily mean there isn't a problem.
To run the program:
task = ThreadedTask()
task.start()
python python-3.x multithreading thread-safety
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I'm creating a PyQt Application. The main core/logic of the program runs in a separate loop I've created on a new thread. The core needs to be listening for defined hotkeys that will in turn trigger some functionality. I've removed all the logic and just made a dummy test scenario, as I'm really looking for feedback/help on structure/architecture. I'm very new to all of this.
I created a Keyboard class that also runs in its own thread, where you can register functions that will get called when a key is pressed.
import threading
from win32 import win32api
import win32con
import pythoncom
import pyHook
class Keyboard(threading.Thread):
def __init__(self):
super().__init__()
self.hook_manager = pyHook.HookManager()
self.hook_manager.KeyDown = self.on_keyboard_event
self._callbacks =
self.is_running = False
def stop(self):
self.is_running = False
self.hook_manager.UnhookKeyboard()
def run(self):
self.is_running = True
self.hook_manager.HookKeyboard()
while self.is_running:
pythoncom.PumpWaitingMessages()
def press(*args):
for arg in args:
win32api.keybd_event(arg, 0, 0, 0)
def release(*args):
for arg in args:
win32api.keybd_event(arg, 0, win32con.KEYEVENTF_KEYUP, 0)
def register_callback(self, f):
self._callbacks.append(f)
def on_keyboard_event(self, event):
print(event.KeyID)
for callback in self._callbacks:
callback(event)
return True
Now the core of the application. It has two main functions: it needs to switch between when running and the second one needs to run for a set amount of time then revert back to the first. The way I've handled this switching and looping seems really bad.
import time
class ThreadedTask(threading.Thread):
MODE_ONE = 0
MODE_TWO = 1
def __init__(self):
super().__init__()
self.is_running = False
self.processing_mode = 0
self.x = 0
self.keyboard = Keyboard()
self.keyboard.register_callback(self.key_pressed)
self.keyboard.start()
def stop(self):
self.is_running = False
def run(self):
self.is_running = True
while self.is_running:
if self.processing_mode == ThreadedTask.MODE_ONE:
self.function_one()
elif self.processing_mode == ThreadedTask.MODE_TWO:
self.function_two()
def function_one(self):
print("function_one")
y = self.x + 2
if y == 4:
self.processing_mode = 1
self.x = 0
time.sleep(0.3)
def function_two(self):
timeout = time.time() + 5
while self.processing_mode == ThreadedTask.MODE_TWO and time.time() < timeout:
print("function_two")
time.sleep(0.3)
self.processing_mode = 0
def key_pressed(self, event):
self.x = 2
And lastly, I feel like I'm going to encounter race conditions, what if the Keyboard calls the key_pressed function which modifies the value of x
while function_one
is trying to access x
. I know very little about threading, this is the first time I've tried it. The above code runs fine in my tests, but I read that race conditions are unpredictable, so that it running fine doesn't necessarily mean there isn't a problem.
To run the program:
task = ThreadedTask()
task.start()
python python-3.x multithreading thread-safety
I'm creating a PyQt Application. The main core/logic of the program runs in a separate loop I've created on a new thread. The core needs to be listening for defined hotkeys that will in turn trigger some functionality. I've removed all the logic and just made a dummy test scenario, as I'm really looking for feedback/help on structure/architecture. I'm very new to all of this.
I created a Keyboard class that also runs in its own thread, where you can register functions that will get called when a key is pressed.
import threading
from win32 import win32api
import win32con
import pythoncom
import pyHook
class Keyboard(threading.Thread):
def __init__(self):
super().__init__()
self.hook_manager = pyHook.HookManager()
self.hook_manager.KeyDown = self.on_keyboard_event
self._callbacks =
self.is_running = False
def stop(self):
self.is_running = False
self.hook_manager.UnhookKeyboard()
def run(self):
self.is_running = True
self.hook_manager.HookKeyboard()
while self.is_running:
pythoncom.PumpWaitingMessages()
def press(*args):
for arg in args:
win32api.keybd_event(arg, 0, 0, 0)
def release(*args):
for arg in args:
win32api.keybd_event(arg, 0, win32con.KEYEVENTF_KEYUP, 0)
def register_callback(self, f):
self._callbacks.append(f)
def on_keyboard_event(self, event):
print(event.KeyID)
for callback in self._callbacks:
callback(event)
return True
Now the core of the application. It has two main functions: it needs to switch between when running and the second one needs to run for a set amount of time then revert back to the first. The way I've handled this switching and looping seems really bad.
import time
class ThreadedTask(threading.Thread):
MODE_ONE = 0
MODE_TWO = 1
def __init__(self):
super().__init__()
self.is_running = False
self.processing_mode = 0
self.x = 0
self.keyboard = Keyboard()
self.keyboard.register_callback(self.key_pressed)
self.keyboard.start()
def stop(self):
self.is_running = False
def run(self):
self.is_running = True
while self.is_running:
if self.processing_mode == ThreadedTask.MODE_ONE:
self.function_one()
elif self.processing_mode == ThreadedTask.MODE_TWO:
self.function_two()
def function_one(self):
print("function_one")
y = self.x + 2
if y == 4:
self.processing_mode = 1
self.x = 0
time.sleep(0.3)
def function_two(self):
timeout = time.time() + 5
while self.processing_mode == ThreadedTask.MODE_TWO and time.time() < timeout:
print("function_two")
time.sleep(0.3)
self.processing_mode = 0
def key_pressed(self, event):
self.x = 2
And lastly, I feel like I'm going to encounter race conditions, what if the Keyboard calls the key_pressed function which modifies the value of x
while function_one
is trying to access x
. I know very little about threading, this is the first time I've tried it. The above code runs fine in my tests, but I read that race conditions are unpredictable, so that it running fine doesn't necessarily mean there isn't a problem.
To run the program:
task = ThreadedTask()
task.start()
python python-3.x multithreading thread-safety
python python-3.x multithreading thread-safety
edited 11 mins ago
Jamal♦
30.2k11115226
30.2k11115226
asked 4 hours ago
kainev
311
311
add a comment |
add a comment |
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208800%2fthreaded-global-keyboard-events%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown