I'm working with wxPython, the Python bridge to wxWidgets, so I guess a wxWidgets user could reply. I'm playing with the KeyEvent class and since I'm testing my code on other platforms and other keyboards, I've made an incredible (to me) discovery: other keyboard layouts don't seem to be very well supported.
Here's what I mean: if you run the demo (KeyEvents.py in my case) and press on random letters, with a QWERTY keyboard, everything works. Switch to another layout, things still work... somewhat. Right now I have an AZERTY keyboard mostly used in France, so when I press the a key (which is on the English position of the q) a 'a' is reported. So far so good. But if I press a é (a key which is on the English 2 key), a 2 is reported. Reading the documentation didn't exactly help me to figure out what is going on. Is that a kind of mistake no one has noticed since wx is out? I would guess and hope not, but better late than never I guess.
To be more technical still, the KeyDown and KeyUp events have this problem. I have an AZERTY kleyboard, I press on the 2 key, and a 2 is reported, whereas a é is written on screen. Admittedly, the Char event does report a é, but, if I understood correctly, a Char event is not triggered in any context a KeyDown event is triggered. Perhaps I missed something here and perhaps that's the solution for me and international users.
Thanks in advance for your reply,
Char event is not triggered in any context a KeyDown event is
triggered.
False.
Due to each country has its own keyboard layout, wxWidgets sends two events when a key is pressed: One (key event) is the somewhat hardware code for that key; the other (char event) is the "translated" code, normally a Unicode point, but an ASCII code if you disabled Unicode support.
Keyevent is useful if you just want to do something on key-down or key-up events. If working with chars, then use only char event.
Related
I'm making a key press overlay for rhythm games. How would I go about obtaining keyboard inputs outside of the Python window's focus?
I would assume you would use the keyboard module, but I can't find any documentation on it other than how to have it record and simulate key presses. Upon importing it and looking at possible functions, I see that there are some that appear to have the functionality of getting keys down/up. I have no idea how to use them though. I'm not sure if I'm even on the right track with the keyboard module but maybe one of you guys know.
My use case
I need to know when a (specific) key is pressed and held down. The use case after detection is fairly easy. When the key is released, send a signal to stop the callback (which I know already).
Desired behavior
Here is a rough scheme of how the algo looks like:
def the_callback():
if key_held == the_hotkey:
someObj.start() # this class Obj works totally well so no issues here on
elif key_released == the_hotkey:
someObj.stop()
else:
# we don't care. continue looking for Keyboard events
# here any kinda listener or just a loop which passes events to the callback
I should mention that any kinda listener which blocks the execution is okay as it will run in its own thread (already running pynput.keyboard.Listener in a thread so not a problem)
What I've tried
I used pynput and its pynput.keyboard.Listener to detect key-presses and invoke callbacks accordingly but I couldn't make that work to detect when a key is HELD down.
the current solution looks roughly like:
# not real code. just rough scheme
def on_pressed(key):
if key == my_hotkey:
if running_already: # this part works well already
obj.stop()
else:
obj.start()
else:
# we don't care
with pynput.keyboard.Listener(on_press=on_pressed) as listener:
listener.join() # blocking call until SystemExit, `return False` from callback or `listener.stop()`
I have a very strong feeling that I can make this work by adding on_release=another_callback_that_handles_releases (available within pynput.keyboard.listener).
Perhaps by storing the last known pressed keystroke, and checking if the key released was the same as the hotkey which was pressed earlier but I'm not sure how would I go about it and can that even work?
Then I decided to give keyboard (different lib) a go.
I wrote the below code for the same which can detect keys being held down. This below code achieves almost nearly what I want:
import keyboard as kb, time
while 1:
while kb.is_pressed('q'):
print('Key is held')
time.sleep(0.5) # sleep added just to stop it from spamming the stdout
else:
print('No it\'s Not')
time.sleep(0.5)
The issue with this solution is, it's not very well suited for OSX and Ubuntu. And it has some issues working with special keys. Moreover, I have the hotkey stored as pynput.keyboard.Key.f7 (for eg) or pynput.keyboard.KeyCode(char='s') # for character keys and these enums have different values than what keyboard uses to scan key IDs (using keyboard.hook()).
The final question
How should I go about detecting a key being HELD down. I'd prefer to achieve this using pynput as the rest of the code base uses it but 'keyboard is fine too.
Again I have a feeling that using on_press=a_callback and on_release=another_callback this might be achieved but I'm not entirely sure about it. Lastly, the solution is preferred to be cross platform (I'm fine with using three different functions depending on value of platform.system()).
How would you go about achieving it?
EDIT-1
HERE is what I wrote as an attempt (and MCVE) after suggestion by Isak. This works almost perfectly with just 1 flaw. And that is that it doesn't listen to keypresses right from the program start.
It takes some time for some unknown reason before it starts to actually detect any keypress. Good thing is that once it detects the keypress for the first time, it works flawlessly.
What am I missing there?
Try to check for the key_pressed event on the specific key until the event becomes key_released. So when you detect a click on the key you execute your code and when it detects the release of that key the code stops
I figured out why My Approach was taking a lot of time to initialize before starting the Listener. It was because of the while loop which didn't have any time.sleep() calls and it was probably messing with the system (although I wouldn't expect that to happen as it runs in its own thread but probably the while loop doesn't release the GIL as it's just in the loop doing literally nothing without any sort of delay).
I just added time.sleep(0.2) inside the while loop (the outer one). Any delay would do as that would release the GIL for some time and the Listener thread would be processed and made active.
Edit: Accepting the answer by Isak as accepted as that is the correct approach.
Good morning,
I am using Python's 3.8 pynput (in windows 10) to get each time the character entered (in system level) and then the unicode of this character.
from pynput import keyboard
def on_press(key):
if key == keyboard.Key.esc: #if button escape is pressed close the program
listener.stop()
else: #if button escape is not pressed get the unicode code of the button-char pressed
unicode_code = ord(getattr(key, 'char', '0'))
print("The unicode is ",unicode_code)
print("The char entered is",chr(unicode_code))
controller = keyboard.Controller()
# Collect events until released
with keyboard.Listener(on_press=on_press) as listener:
listener.join()
The problem I am facing is that when I change my keyboard to greek (with shift+alt), it keeps the unicodes of the english language and not the greek ones.
You can see the screenshot attached to understand better.
What to do to overcome this problem?
No, you aren't getting English unicode codes. You are getting unicode representation of codes returned by the keyboard. They will be the same no matter what language is chosen because keyboard layer is designed to always return same codes for same keys (by their location and/or meaning on querty/quertz or other HID compliant keyboards) if possible. What you are doing in your code is essentially reverting the process done by pynput which converts the keyboard code using char()/unichar() function. Think about it: is there a greek representation of e.g. F11 key?
I cannot remember whether pynput has higher-level inputs support or not, although I think it does. and that it should be possible to get directly what you want
What you have to do is either to find another attribute (if there is one, I am not pynput specialist) containing the character sent to the input field, or check the current keyboard language and appropriately map the codes returned. You can also try playing with codepages using the codecs module. Worst case scenario would include snatching the character directly from the GUI's input field. But that would be very inelegant, bruteforc-ish and simply the shouldn't do it thing if not strictly necessary. There are other methods for getting input from the OS - like directly linking to its event input system or kernel using built-in libraries through ctypes, wintypes, Cocoa/Carbon on Mac or GTK on Linux.
Try using pynput version 1.1.7, it works there. It is broken after 1.4 and in between these two it works, but changing the layout with the windows shortcut while the program is running, isn't working 70% of the time, meaning Windows just doesn't change the language. Alternatively, you can work around it in newer verisons by trying this solution, that converts the characters in real time if you don't care about performance. I have opened an issue for it to be fixed in the repo's github.
I would like to make a program for displaying some information and help (like it is sometimes done at libraries or in other public places). So basically some information screen. The problem is I would like to prevent the user from exiting the program and scrolling up, to see what others typed.
I would like to do that without importing big libraries like Pygame. There are plenty of modules for automatic mouse movement and and mouse clicks, but almost no modules for detecting it. If you know some please write them here. I am using Windows 10 and 7.
Try pynput. It's a bit fiddly to use when capturing, but can capture keyboard and mouse and also emit both.
This answer doesn't really answer the question asked in the title:
However it might answer the use case that you describe:
I don't have a windows computer at hand for testing:
but perhaps this could work:
import os
os.system('cls')
# now rewrite the lines, that a user is allowed to see.
Theoretically cls is supposed to clean the windows screen buffer and you wouldn't see any history and it should be impossible to scroll back.
I think most other solutions would quickly become complicated or could be circumvented by a user with some combinations of key presses and mouse movements.
However you had to explicitely rewrite whatever you want to keep on the display.
I'm developing translation software for Linux using Python. I'm looking for a way to get the key pressed event. When an english letter key is pressed, I wan the pressed key to be assigned to a variable.
I've tried googling and reading various articles, but haven't had any luck so far.
Using Pygame, you care about the Pygame.KEYDOWN keyboard event. You can see how to use it in the pygame example aliens.py.