boppreh / keyboard Goto Github PK
View Code? Open in Web Editor NEWHook and simulate global keyboard events on Windows and Linux.
License: MIT License
Hook and simulate global keyboard events on Windows and Linux.
License: MIT License
I have noticed that the number pad keys have the same scan code as other keys. This is a problem because I cannot distinguish the difference between pressing arrow down and pressing "2." I also do not seem to be able to distinguish when number lock is pressed.
keyboard
currently maps certain numpad keys to the same key code as other function keys. Examples are num *
and print screen
, num 6
and right
, num 9
and page up
, etc.
When I call press_and_release('print screen')
, instead of copying the screen to the clipboard, I get a *
character. When I call press_and_release('num 8')
, I get an up-arrow keypress instead. (Note that if I use keypad 8
it prints an 8 as expected.)
Could you clarify how this behavior should work? (Below I've included the output of the _os_keyboard.to_scan_code
dict for your reference.)
{u"'": (40, False),
u'+': (78, False),
u',': (51, False),
u'-': (12, False),
u'.': (52, False),
u'/': (53, False),
u'0': (11, False),
u'1': (2, False),
u'2': (3, False),
u'3': (4, False),
u'4': (5, False),
u'5': (6, False),
u'6': (7, False),
u'7': (8, False),
u'8': (9, False),
u'9': (10, False),
u';': (39, False),
u'<00>': (84, False),
u'=': (13, False),
u'[': (26, False),
u'\\': (43, False),
u']': (27, False),
u'`': (41, False),
u'a': (30, False),
u'alt': (56, False),
'alt gr': 541,
u'b': (48, False),
u'backspace': (14, False),
u'break': (70, False),
u'c': (46, False),
u'caps lock': (58, False),
u'ctrl': (29, False),
u'd': (32, False),
u'delete': (83, False),
u'down': (80, False),
u'e': (18, False),
u'end': (79, False),
u'enter': (28, False),
u'esc': (1, False),
u'f': (33, False),
u'f1': (59, False),
u'f10': (68, False),
u'f11': (87, False),
u'f12': (88, False),
u'f13': (124, False),
u'f14': (125, False),
u'f15': (126, False),
u'f16': (127, False),
u'f2': (60, False),
u'f3': (61, False),
u'f4': (62, False),
u'f5': (63, False),
u'f6': (64, False),
u'f7': (65, False),
u'f8': (66, False),
u'f9': (67, False),
u'g': (34, False),
u'h': (35, False),
u'help': (86, False),
u'home': (71, False),
u'i': (23, False),
u'insert': (82, False),
u'j': (36, False),
u'k': (37, False),
u'l': (38, False),
u'left': (75, False),
u'left windows': (91, False),
u'm': (50, False),
'menu': (93, False),
u'n': (49, False),
u'num *': (55, False),
u'num +': (78, False),
u'num -': (74, False),
u'num /': (53, False),
u'num 0': (82, False),
u'num 1': (79, False),
u'num 2': (80, False),
u'num 3': (81, False),
u'num 4': (75, False),
u'num 5': (76, False),
u'num 6': (77, False),
u'num 7': (71, False),
u'num 8': (72, False),
u'num 9': (73, False),
u'num del': (83, False),
u'num enter': (28, False),
u'num lock': (69, False),
u'o': (24, False),
u'p': (25, False),
u'page down': (81, False),
u'page up': (73, False),
u'pause': (69, False),
'print screen': (55, False),
u'q': (16, False),
u'r': (19, False),
u'right': (77, False),
u'right alt': (56, False),
u'right ctrl': (29, False),
u'right shift': (54, False),
u'right windows': (92, False),
u's': (31, False),
u'scroll lock': (70, False),
u'shift': (42, False),
u'space': (57, False),
u'sys req': (84, False),
u't': (20, False),
u'tab': (15, False),
u'u': (22, False),
u'up': (72, False),
u'v': (47, False),
u'w': (17, False),
u'x': (45, False),
u'y': (21, False),
u'z': (44, False)}
Certain applications with low-level functionality (like Citrix) check the scan code for keyboard events as well as the virtual key code. If the scan code isn't set, they will miss certain keys like the arrow keys (though other keys will work fine).
I'm running into this issue with the current release of keyboard
. I'll submit a pull request in a bit.
I'm writing an application where the user can define their own global hotkeys. The interface for this is: they click a button, it says "press the key you want", they press it.
This was slightly more complicated to accomplish using "keyboard" than I expected it to be. Here is some simplified example code:
import keyboard
my_key = None
def record_key(event):
global my_key
if event.event_type == keyboard.KEY_DOWN:
my_key = event.scan_code
print "select a hotkey"
callback = keyboard.hook(record_key)
while my_key is None:
pass
keyboard.unhook(callback)
print "selected key code: " + str(my_key)
def fn():
print "you pressed it"
keyboard.hook_key(int(my_key), keydown_callback=fn)
while True:
pass
Am I missing something that makes this simpler? I expected to find something like, say, "keyboard.read_key()" that blocks until they press a key and returns what key they pressed.
I also found it surprising that if I don't cast my_key to int on that third-to-last line, I receive an error like
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\keyboard\_generic.py", line 23, in invoke_handlers
if handler(event):
File "C:\Python27\lib\site-packages\keyboard\__init__.py", line 350, in handler
if not matches(event, key):
File "C:\Python27\lib\site-packages\keyboard\__init__.py", line 139, in matches
normalized = _normalize_name(name)
File "C:\Python27\lib\site-packages\keyboard\_keyboard_event.py", line 215, in normalize_name
raise ValueError('Can only normalize string names. Unexpected '+ repr(name))
ValueError: Can only normalize string names. Unexpected 30L
(30L is what it says if I press 'a', since its scancode is 30)
Shouldn't the library be able to receive a scancode back as the same kind of datatype it gave to me?
(I'm using the scancode and not the name because the name is reported as "unknown" for many some keys, and incorrectly for others. like my left ctrl and left alt both show as having "right" in their name instead of left)
Python27\lib\site-packages\keyboard\mouse.py", line 5, in
import keyboard.winmouse as os_mouse
ImportError: No module named winmouse
When I use the function keyboard.record()
or when I try to make a hook using keyboard.on_press()
, it simply don't detect the pressed keys.
The keyboard.write()
function works fine.
On Windows 10, the same code seems to work fine.
P.S.: I ran the code as superuser
Iam trying to set .press() setup, without lucky.
I want something like that, when I prest alt+g then holds down F8 key until I press 'esc'
Is that possible?
Is it possible to simulate using these keys I don't have a multimedia keyboard actually attached? How would I go about finding the code to send? I currently am using an AutoHotKey script for it but would love to replace it with a python script instead.
EDIT: I'm on Windows.
On this this laptop (Lenovo Thinkpad T440s, no external keyboard, running Arch Linux), no matching keyboards are founds, so I get ImportError: No keyboard files found (/dev/input/by-path/*-event-kbd).
My /dev/input/by-path
directory has only:
lrwxrwxrwx 1 root root 10 Aug 6 22:40 pci-0000:00:14.0-usb-0:8:1.0-event -> ../event13
lrwxrwxrwx 1 root root 9 Aug 6 22:40 platform-pcspkr-event-spkr -> ../event5
lrwxrwxrwx 1 root root 9 Aug 6 22:40 platform-thinkpad_acpi-event -> ../event4
by-id
is just one:
lrwxrwxrwx 1 root root 10 Aug 6 22:40 usb-J30E9SCWZ_Integrated_Camera-event-if00 -> ../event13
xinput list
reports:
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ SynPS/2 Synaptics TouchPad id=11 [slave pointer (2)]
⎜ ↳ TPPS/2 IBM TrackPoint id=12 [slave pointer (2)]
⎣ Virtual core keyboard id=3 [master keyboard (2)]
↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
↳ Power Button id=6 [slave keyboard (3)]
↳ Video Bus id=7 [slave keyboard (3)]
↳ Sleep Button id=8 [slave keyboard (3)]
↳ Integrated Camera id=9 [slave keyboard (3)]
↳ AT Translated Set 2 keyboard id=10 [slave keyboard (3)]
↳ ThinkPad Extra Buttons id=13 [slave keyboard (3)]
The AT Translated Set 2 keyboard
(id 10) is the one that shows activity on xinput test 10
.
xinput list-props 10
:
Device 'AT Translated Set 2 keyboard':
Device Enabled (139): 1
Coordinate Transformation Matrix (141): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000
Device Product ID (260): 1, 1
Device Node (261): "/dev/input/event0"
Is there any way this library can hook into the keyboard on this system? Let me know if I can give any more details!
Hi, me again :-)
Got me a Linux laptop and trying to really use the lib on it, because of course, no AutoHotKey...
Unfortunately I can't get it to run a two-line test example (import keyboard, define one abbreviation).
With Python 2.7 it bombs:
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
self.run()
File "/usr/lib/python2.7/threading.py", line 754, in run
self.__target(*self.__args, **self.__kwargs)
File "/home/fpp/python/PyHotKey/keyboard/__init__.py", line 114, in listen
_os_keyboard.listen(self.queue)
File "/home/fpp/python/PyHotKey/keyboard/_nixkeyboard.py", line 111, in listen
build_device()
File "/home/fpp/python/PyHotKey/keyboard/_nixkeyboard.py", line 106, in build_device
device = aggregate_devices('kbd')
File "/home/fpp/python/PyHotKey/keyboard/_nixcommon.py", line 145, in aggregate_devices
uinput = make_uinput()
File "/home/fpp/python/PyHotKey/keyboard/_nixcommon.py", line 48, in make_uinput
uinput.read = lambda n: Queue().get()
AttributeError: 'file' object attribute 'read' is read-only
With Python3.5 there is no exception but no abbreviation expanding either...
This is on XUbuntu 16.04, running the script as root in xterm and testing in Mousepad.
Anything I'm doing wrong ?...
This library advertises python 2 compatibility but it looks like the latest release had zero testing on python 2, since it doesn't work at all.
I tried setting up travis-ci to run keyboard's test suite on python 2 and 3, and got it working pretty easily. Check it out: https://github.com/Hyphenated-integrations/keyboard/commits/master
https://travis-ci.org/Hyphenated-integrations/keyboard
When I revert the recent fix to the py2 issue, the py2 travis build fails! Cool! I don't know why it times out rather than giving an error message, but that's not a huge deal. It still means the code is broken.
travis-ci is free for open source projects, so: consider doing this officially to help make fewer bad releases?
Hi,
This pure-python, cross-platform lib is quite impressive. It could help a lot on workstations where adding stuff is severely restricted (ie no pip, etc.).
One thing I'm looking for is to reproduce (at least partly) the abbreviation expansion functionality found in Autohotkey (among others).
This replaces text patterns as you type, without hotkeys (ie., type 'tm" followed by space and its gets replaced by a trademark symbol for example).
I have not been able to do this using the add_hotkey method (which is probably normal).
Could there be a way to achieve it using the lower-level functions ?
TIA,
fp
Hi every one ! smart-useful-complete pure python ctypes project ! Wow !
Here are a few errors I got.
Your skills are definitely higher than mine, but here are a few notes, with "a fresh view".
A few tunings, and you will Hit mY keYbOarD !
Hope it helps.
Regards, Stanislas.
# THE FILE:
import keyboard
# version is recent keyboard-master, lundi 13 février 2017, 16:42:31
# console is the notepad++ python console,
# an instance of scintilla editor, as any other editor buffer, supports print.
# This is a UTF-8-BOM, Windows file, on winxp sp3.
def end_bye():
keyboard.unhook_all()
console.write('keyboard.unhook_all')
# succes
keyboard.press_and_release('shift+s, space')
# succes
keyboard.write('The quick brown fox jumps over the lazy dog.')
# sucks
keyboard.add_hotkey('Space', lambda: console.write('space was pressed') )
# sucks
keyboard.wait('a')
# EOF
# THE ERRORS OUTPUT:
keyboard.add_hotkey('Space', print, args=['space was pressed'])
SyntaxError: invalid syntax ^
keyboard.add_hotkey('Space', lambda: print 'space was pressed' )
SyntaxError: invalid syntax ^
keyboard.wait('a')
Traceback (most recent call last):
File "...\hk\keyboard_test.py", line 36, in <module>
keyboard.wait('a')
File "C:\Python27\lib\site-packages\keyboard\__init__.py", line 652, in wait
wait()
File "C:\Python27\lib\site-packages\keyboard\__init__.py", line 639, in wait
return q.get(timeout=1)
File "C:\Python27\Lib\Queue.py", line 177, in get
self.not_empty.wait(remaining)
File "C:\Python27\Lib\threading.py", line 355, in wait
remaining = endtime - _time()
KeyboardInterrupt
the script has properly stopped running,
but has printed "€€" , once at the caret position at which the script was launched, and then randomly through several other opened files in the notepad++ editor ... all along the same error.
let's talk about "€" later ...
in: _keyboard_event.py :
canonical_names = { ...,
'num add': '+',
'num plus': '+',
'num minus': '+', # oops
'num sub': '-' ,
And in: _winkeyboard.py, from_virtual_key={... 0xbb: ('=', False),
doesn't seem to exist , mapped to : _keyboard_event.py canonical_names = { ..., 'equal': '=', ... }
?
Other implementation use this k:v on a different purpose: watch for the alt-key-pressed
state of a key, in the case of UI menus handling with a &MenuItem shortcut mapping.
There is an implementation of these crossed mappings between vk and ascii
representation in the "PythonWin" source code on github,and a shorter version too with fewer mappings.
Yet their mapping is incomplete, as it has a contextual purpose.
Yours aims to be wider, so nice !
Their logic is to parse vk as"ascii_not_shifted +-" (+-shifted)
to be sure to end with no ambiguity (function parse_key_name(name)).
Ex: outputs of test2() in keycodes.py:
Alt+/ -> 191,19 -> Shift+Alt+: '/' is detected as 'shift'+':'
\ -> 56,15 -> Ctrl+Alt+_ it couldn't match an event as 'alt-gr'+'_' ...
Also it separates the users logic from the implementation logic :
a silly example:
I want to set up a hk with the '/'
symbol for my purpose, not the ':'
symbol.
I think (hope) most people type'shift+:'
without the intent to press this specific combination, they do because "this is the way it is to get '/'
", from the reptilian cognitive layer, almost like walking.
Though, 'ctrl+/'
would be meaningful, ex. as an application hotkey, where the / holds the aim, however we do access to it. It is 'shift+:'
, you know it, could you hold that for my higher-level-of-abstraction ... ?
And this way, I am sure that both symbols will be available, as they should not
be mutually exclusive, every char will be safe and glad to serve our most exquisite desires !
the "alternate-engraving" key and WM_SYSKEYDOWN :
in _winkeyboard.py,
line~~300, ... alt_gr_scan_code = 541 # ???
line~~121, WM_SYSKEYDOWN = 0x104 # Used for ALT key
watch the results I get from a view on the events broadcasting :
it is true for ( 'ctrl' , 'alt' , 'e' ), not for ( 'alt-gr' , 'e' ), on my winxp sp3
I don't see that as an inconsistency, just the complexity to be able to input more symbols than the number of keys we have on our keyboards. As the alt
key served the UI menus fisrt, it is a way to have a kind of alternate-alt, that shares only a part of it's business with it's left sister, not as the ctrl
and shift
keys do, and usable with one finger only !!!
The more I used it, the more I loved that key. I was doing maths outside of latex : Autohothey was a big help to map contextually all my keys to utf-8 Greek and math symbols on alt-gr/ctrl+alt
!
Then giving the users two different methods of input, one for the left-handlers, one for the others ( 'alt-gr' | 'ctrl'+'alt' ) over-adds to the complexity.
By the way, your unicode implementation is a really consistent piece of code to study, as it is still a pain for me to have a large view on it, a really, really nice good help.
Thanks a lot for the lesson .
VK_CONTROL 0x11
VK_MENU 0x12 : alt menu because it first gave access to menus,
# note from WinUser.h :
# VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys.
# Used only as parameters to GetAsyncKeyState() and GetKeyState().
# No other API or message will distinguish left and right keys in this way.
# not so simple in fact ... alt-gr is the exception :
VK_LMENU 0xA4 : alt
VK_RMENU 0xA5 : alt-gr in the vk perspective, BUT NOT IN MESSAGING :
it gets broacasted as 'alt'+'mod_ctrl'
and 'ctrl'+'mod_alt' yields the same result, as "€"
You can get a ?clear view of the mechanism in the exemples below:
two ways to get the Euro symbol '€' ( bad news for me, European : some have "the easy way" to make some, and convert it to '$' or '£' as fast as they can, far away from my home, under some coconut-tree ... ;-).
the details are below_below.
1) typed ( 'alt-gr', 'e' ) 2) typed ( 'ctrl' , 'alt' , 'e' )
event: event:
kd ctrl NO MOD_KEY syskd MOD_KEY is VK_MENU 0x12, alt
kd alt NO MOD_KEY kd ctrl (+ mod_alt )
kd E kd E
ch € ch €
ku E ku E
sysku MOD_KEY is VK_CONTROL 0x11 sysku MOD_KEY is VK_MENU 0x12, alt
ku alt (+ mod_ctrl ) ku ctrl (+ mod_alt )
with a hotkeys dict like:
MOD_ALT = 1 ; MOD_CONTROL = 2
# key_k = 75 # fires on:
my_hks = { 0 : ( 75, MOD_ALT ), # 'alt+k'
1 : ( 75, MOD_ALT+MOD_CONTROL ) } # 'ctrl+alt+k' and 'alt-gr+k'
with hotkeys we don't care about checking the events details ... but it's far less powerful than what you are setting up on chars only, unicode included ! a blessing !
( 'alt-gr', 'e' )
to print the '€' euro sign :<messages created-by="Winspector"> <!-- 99.99% filtered ... -->
<message>
<name>WM_KEYDOWN</name>
<posted />
<time>16:26:50.0468</time>
<parameters>
<parameter>Virtual Key: VK_CONTROL</parameter> ctrl NO MOD_KEY
</parameters>
</message>
<message>
<name>WM_KEYDOWN</name>
<posted />
<time>16:26:50.0468</time>
<parameters>
<parameter>Virtual Key: VK_MENU</parameter> alt NO MOD_KEY
</parameters>
</message>
<message>
<name>WM_KEYDOWN</name>
<posted />
<time>16:26:50.0515</time>
<parameters>
<parameter>Virtual Key: E</parameter> E
</parameters>
</message>
<message>
<name>WM_CHAR</name>
<posted />
<time>16:26:50.0515</time>
<parameters>
<parameter>wParam: 0x000020ac</parameter> €
<parameter>lParam: 0x20120001</parameter>
</parameters>
</message>
<message>
<name>WM_KEYUP</name>
<posted />
<time>16:26:50.0718</time>
<parameters>
<parameter>Virtual Key: E</parameter> E
</parameters>
</message>
<message>
<name>WM_SYSKEYUP</name>
<posted />
<time>16:26:51.0046</time>
<parameters>
<parameter>wParam: 0x00000011</parameter> MOD_KEY VK_CONTROL 0x11
<parameter>lParam: 0xe01d0001</parameter> ???
</parameters>
</message>
<message>
<name>WM_KEYUP</name>
<posted />
<time>16:26:51.0046</time>
<parameters>
<parameter>Virtual Key: VK_MENU</parameter> alt (+ mod_ctrl )
</parameters>
</message>
( 'ctrl' , 'alt' , 'e' )
<message>
<name>WM_SYSKEYDOWN</name>
<posted />
<time>15:30:54.0406</time>
<parameters>
<parameter>wParam: 0x00000012</parameter> MOD_KEY VK_MENU 0x12 alt
<parameter>lParam: 0x20380001</parameter>
</parameters>
</message>
<message>
<name>WM_KEYDOWN</name>
<posted />
<time>15:30:54.0406</time>
<parameters>
<parameter>Virtual Key: VK_CONTROL</parameter> ctrl (+ mod_alt )
</parameters>
</message>
<message>
<name>WM_KEYDOWN</name>
<posted />
<time>15:30:55.0046</time>
<parameters>
<parameter>Virtual Key: E</parameter> E
</parameters>
</message>
<message>
<name>WM_CHAR</name>
<posted />
<time>15:30:55.0046</time>
<parameters>
<parameter>wParam: 0x000020ac</parameter> €
<parameter>lParam: 0x20120001</parameter>
</parameters>
</message>
<message>
<name>WM_KEYUP</name>
<posted />
<time>15:30:55.0218</time>
<parameters>
<parameter>Virtual Key: E</parameter> E
</parameters>
</message>
<message>
<name>WM_SYSKEYUP</name>
<posted />
<time>15:30:55.0328</time>
<parameters>
<parameter>wParam: 0x00000012</parameter> MOD_KEY VK_MENU 0x12 alt
<parameter>lParam: 0xc0380001</parameter>
</parameters>
</message>
<message>
<name>WM_KEYUP</name>
<posted />
<time>15:30:55.0328</time>
<parameters>
<parameter>Virtual Key: VK_CONTROL</parameter> ctrl (+ mod_alt )
</parameters>
</message>
It is a pretty old freeware app from gipsysoft that runs fine under my winxp sp3. I didn't try it on a more recent system.
All the download links seem to be dead and it is a real pity / shame, as it is a really cool stuff, that mimics the Spy++ of Microsoft, aviable only with the commercial versions of VisualStudio.
I didn't use it for years, and that Alt-Gr
stuff was bothering, so I gave an eye with it. I knew I would keep such a cool-stuff in some safe place, and could find the setup file of Winspector in a backup. I was lucky to get it a few years ago, from an Autohotkey forum. Those AHK addicts are deeply into the WinApi automation, and this tool was a must to peek into that complexity ... If you want, you can get it from my google-drive as a zipped file and happily watch your system events .... Note that the result of key-event-viewer.html are slightly different : it is handling Alt-Gr
and Ctrl+Alt
the same, and it is NOT THE REALITY : it doesn't report the WM_SYSKEYDOWN generated ! Winspector does ... unless that difference, we wouldn't need to ask ourselves such silly questions ... !
Winspector is poorely documented, so here is "a-short-how-to" :
Select a window, rightckick the item highlighted in the list, get "Messages" --> Messages_window
: has an icon "traffic light"
: pauses events capture on/off, an icon "save"
... saves to xml.
Right click Messages_window
, get "Edit message filter", put the kept event in the right-side list. Be carefull: the msgs outputs will be filtered in the Messages_window
, but it doesn`t apply filter to the results in memory, and it saves ALL events it catches : events captured during 3 key-press is already a big quantity of msgs, so, if you play with it, be sure to produce as few mouse moves and breathings as you can, be a good boy : mind the "traffic light"
, saving xml may look like hanging for freezing ? no, it just can be processing a huge xml file ... Enjoy !
# a quick filter script for the Large xml file :
import xml.etree.ElementTree as ET
file_in = "messages3.xml" # same dir as script_file
file_out = "filtered_"+file_in
tree = ET.parse(file_in) # ASCII or use ET.XMLParser(enc...)
root = tree.getroot()
filter = [ 'WM_SYSKEYDOWN' ,
'WM_KEYDOWN' ,
'WM_CHAR' ,
'WM_KEYUP' ,
'WM_SYSKEYUP'
]
for message in root.findall('message'):
name = message.find('name').text
if name not in filter:
root.remove(message)
tree.write('filtered_messages.xml') # Result to an XML File
Once again, thank you for your this shared work and may the Force be with you ...
Do you think an OS X port would be possible?
Right now all events report after-the-fact. It should be possible to suppress keys, keeping them from being processed by applications down the line. This allows users to create global hotkeys without affecting the focused application, for example.
This is possible in Windows, but would require moving the hotkey processing back into the hook.
Linux seems to be trickier. Maybe relying on X, like https://github.com/alols/xcape ?
Finally, extreme care must be taken to not introduce input lag. Because all hotkeys will be processed in the main thread, blocking the event they analyze, it would be too easy to add precious milliseconds to every key press, which is not acceptable.
Right now the library doesn't care about dead keys at all. In Linux their status is known, but quickly stripped and ignored. In Windows there's no mention.
This may cause problems when trying to write text, because the library will try to use those keys as regular keys and the output will be jumbled.
May not be easy to implement on Windows.
An event.is_dead
attribute would be nice too.
PS: this still better than some other libraries that simply break dead keys while they are running... Looking at you, pyHook.
hi, i am python newbie, and is very dificult to me understand how to run this program, so, i create a executable file on linux called k3y like this
#!/usr/bin/python
# coding: latin-1
import keyboard
# Press PAGE UP then PAGE DOWN to type "foobar".
keyboard.add_hotkey('page up, page down', lambda: keyboard.write('foobar'))
keyboard.add_hotkey('ctrl+q', quit)
keyboard.add_hotkey('ctrl+alt+enter, space', u'some_callback')
keyboard.add_abbreviation('tm', u'™')
keyboard.add_abbreviation('3n', u'el3ctron')
so, i executed on my command line ./k3y
it runs showing no error,
but when i do some abreviation (for example writting in another window 3n), or pressing some hot key ('page up, page down') nothing happens! i do not know if i am doing something wrong. :(
The requirement of root access won't work for a large number of applications.
I didn't look through what made that a requirement, but it looks like ensure_root
is littered all over the code base for a posix environment.
Somewhat related - I wasn't able to setup a virtualenv properly because of this requirement.
Linux already has this.
Device information is not included in the hook we are using, which complicates things. Raw Input seems to provide this, but it doesn't include the virtual key codes we use to map most of the key names and keypad status.
There should be some kind of device information on event.device
.
Note: https://github.com/me2d13/luamacros seems to do this.
Would you be interested in an X-based global hotkey capture? I wrote (most of) one in an effort to make a global-hotkey-library before I found this project. It has a dependency on python-xlib, but that's preferable to having to run as root. Root mode could still be used as a fallback if the xlib package isn't available, still keeping the "zero dependency" guarantee.
Obviously, my code would need to be adapted to your architecture, but I don't think that should be too hard.
When adding a hot-key with Alt Gr and a character, an exception is thrown.
Example:
keyboard.register_hotkey('alt gr+.', my_callback)
Exception occurs when pressing keys:
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\keyboard\_generic.py", line 23, in invoke_handlers
if handler(event):
File "C:\Python27\lib\site-packages\keyboard\__init__.py", line 283, in handler
unexpected = not any(matches(event, part) for part in steps[state.step])
File "C:\Python27\lib\site-packages\keyboard\__init__.py", line 283, in <genexpr>
unexpected = not any(matches(event, part) for part in steps[state.step])
File "C:\Python27\lib\site-packages\keyboard\__init__.py", line 149, in matches
return matched_name or _os_keyboard.map_char(normalized)[0] == event.scan_code
File "C:\Python27\lib\site-packages\keyboard\_winkeyboard.py", line 444, in map_char
scan_code, shift = to_scan_code[name]
TypeError: 'int' object is not iterable
'alt gr,.' isn't working ,too.
I found out that the configration map used to find scan-codes, does not return a tuple with Shift-Flag:
from_scan_code[alt_gr_scan_code] = ['alt gr', 'alt gr']
to_scan_code['alt gr'] = alt_gr_scan_code
finally:
tables_lock.release()
The following modification worked for me:
to_scan_code['alt gr'] = alt_gr_scan_code, False
Currently it's possible to distinguish the side of the received events, but not generate events for specific sides. This should be fixed.
Example program
import keyboard
import time
import logging
BINDS = []
BINDS.append(keyboard.add_hotkey("win", lambda: logging.error("pressed")))
while True:
time.sleep(1)
Result when pressing win key
Exception in thread Thread-1:
Traceback (most recent call last):
File "/home/mblizniak/repos/i3-pyswitch/3rd-party/kb/_nixkeyboard.py", line 94, in listen
name = to_name[(scan_code, tuple(sorted(pressed_modifiers)))]
KeyError: (125, ())
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner
self.run()
File "/usr/lib/python3.5/threading.py", line 862, in run
self._target(*self._args, **self._kwargs)
File "/home/mblizniak/repos/i3-pyswitch/3rd-party/kb/__init__.py", line 79, in listen
_os_keyboard.listen(self.queue)
File "/home/mblizniak/repos/i3-pyswitch/3rd-party/kb/_nixkeyboard.py", line 96, in listen
name = to_name[(scan_code, ())]
KeyError: (125, ())
Hi there, having a weird issue here: Once I start a fullscreen game on my Windows VM that uses synergy to broadcast mouse and keyboard to the second monitor which runs the Host Linux system, my small python script I use for push to talk has a slight issue.
Normally I can use the hook to safely get the key pressed every time, no matter where the mouse is at or which window on which system is focused. The keypresses when the game has started still work on the windows vm (where the keyboard and mouse are connected at) but once I move the mouse to the other screen they stop working. This is the simple script I use (client and server, using UDP):
https://gist.github.com/Keridos/28fb408df82cae3b6b259e05f666b314
Basically, when I use add_hotkey to register a hotkey, I would expect it to receive the event and stop it from being passed over.
Although I'm not sure if its an issue, but I can't find anything about it in the README.
I'm running my program with sudo
Initailly I've gotten such result:
FileNotFoundError: [Errno 2] No such file or directory: '/root/.Xauthority'
then after creating empty .Xauthority file for root
Xlib.xauth: warning, no xauthority details available
Callbacks I've added arent executed when I press the keys.
Clearly some description of the issue is missing in the readme.
And here's how I'm using the llibrary:
https://github.com/mibli/i3-pyswitch/blob/feature/daemon/src/i3switch/input.py
I'm trying to register a global hotkey, and if that fails, ask the user if they want to abort or continue regardless. However, the add_hotkey function doesn't throw an exception. Instead, an exception is thrown in a different thread.
Example:
import keyboard
try:
keyboard.add_hotkey('ctrl+select', print, args=('foo',))
except:
print('ERROR')
else:
print('SUCCESS')
Output:
SUCCESS
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib64/python3.5/threading.py", line 914, in _bootstrap_inner
self.run()
File "/usr/lib64/python3.5/threading.py", line 862, in run
self._target(*self._args, **self._kwargs)
File "/usr/lib/python3.5/site-packages/keyboard/__init__.py", line 114, in listen
_os_keyboard.listen(self.queue)
File "/usr/lib/python3.5/site-packages/keyboard/_nixkeyboard.py", line 111, in listen
build_device()
File "/usr/lib/python3.5/site-packages/keyboard/_nixkeyboard.py", line 105, in build_device
ensure_root()
File "/usr/lib/python3.5/site-packages/keyboard/_nixcommon.py", line 163, in ensure_root
raise ImportError('You must be root to use this library on linux.')
ImportError: You must be root to use this library on linux.
This behaviour is undesirable for obvious reasons, and there doesn't seem to be a workaround.
Using Python2.7(32bits) on W10(64bits).
The following is ok :
keyboard.press('s')
The following raises an exception :
keyboard.press('shift+s')
File "Z:\Eclipse\GamepadToKey\src\key_manager.py", line 25, in joy_set_button
keyboard.press(buttons_tab[button])
File "Z:\Eclipse\GamepadToKey\src\keyboard_init.py", line 509, in press
send(combination, True, False)
File "Z:\Eclipse\GamepadToKey\src\keyboard_init_.py", line 501, in send
os_keyboard.press(to_scan_code(key))
File "Z:\Eclipse\GamepadToKey\src\keyboard_init.py", line 479, in to_scan_code
scan_code, modifiers = _os_keyboard.map_char(_normalize_name(key))
File "Z:\Eclipse\GamepadToKey\src\keyboard_winkeyboard.py", line 244, in map_char
raise ValueError('Character {} is not mapped to any known key.'.format(repr(character)))
ValueError: Character 'shift' is not mapped to any known key.
Bug or Windows limitation ?
Linux gives this wonderfully detailed mapping of all dead keys and what happens when you combine them with different letters. But the library completely ignores it.
Supporting dead keys would give more accurate get_typed_strings
and write
.
It looks like there is an issue in _keyboard_event.py with canonical_names
mapping "win" to "windows". In the to_scan_code
dictionary, there is only "left windows" and "right windows".
Traceback (most recent call last):
File "C:\Python34\lib\site-packages\keyboard_generic.py", line 23, in invoke_handlers
if handler(event):
File "C:\Python34\lib\site-packages\keyboard_init_.py", line 255, in handler
unexpected = not any(matches(event, part) for part in steps[state.step])
File "C:\Python34\lib\site-packages\keyboard_init_.py", line 255, in
unexpected = not any(matches(event, part) for part in steps[state.step])
File "C:\Python34\lib\site-packages\keyboard_init_.py", line 132, in matches
return matched_name or _os_keyboard.map_char(name)[0] == event.scan_code
File "C:\Python34\lib\site-packages\keyboard_winkeyboard.py", line 431, in map_char
return -media_name_to_vk(name), []
File "C:\Python34\lib\site-packages\keyboard_winkeyboard.py", line 437, in media_name_to_vk
raise ValueError('Key name {} is not mapped to any known key.'.format(repr(name)))
ValueError: Key name 'windows' is not mapped to any known key.
Traceback (most recent call last):
File "C:\Python34\lib\site-packages\keyboard_winkeyboard.py", line 428, in map_char
scan_code, shift = to_scan_code[name]
KeyError: 'windows'
Code used:
keyboard.add_hotkey('win+comma', lambda e: keyboard.send('volume down'))
Running this code:
import keyboard
keyboard.add_hotkey('f4', lambda: print('f4'))
keyboard.add_hotkey('f5', lambda: print('f5'))
keyboard.add_hotkey('f6', lambda: print('f6'))
keyboard.wait('esc')
Results in the following in the stderr:
Permission denied (/dev/input/by-path/platform-i8042-serio-0-event-kbd). You must be sudo to access global events.
Also the callbacks are never executed.
Let me know if I can give more details.
I noticed strange behaviour in hotkey action finish. The example script i used:
#!python3
import keyboard
import threading
typing = False
def HookCallback(kbd_event: keyboard.KeyboardEvent):
global typing
print("Are programly typed: " + str(typing) + ", key: "+ kbd_event.name + ", event: " + kbd_event.event_type)
def hkAction():
global typing
typing = True
print("Starting to typing...")
keyboard.write("hello world!")
typing = False
print("Ended typing.")
keyboard.hook(HookCallback)
keyboard.register_hotkey('f7', hkAction)
keyboard.wait()
After you press F7, it will type pogrammatically the hello world!
text, but also you will see the hook that prints the variable typing value which is always false, but it should be true when its pogrammatically types the hello world!
text, how can this be solved? Are the hotkey action and hooks are queuing?
udp:
I also tried to set hook and register hotkey on different threads but got same result.
Hi, when can we use this library with mouse support? Looking forward to use it. Thanks.
The source ZIP in PyPI doesn't include the file CHANGES.md, which makes setup.py
fail in the following line:
last_version = re.search('(\d+(?:\.\d+)+)', open('CHANGES.md').read()).group(1)
Hi and thanks for this useful library!
I've been evaluating it for a while and everything works perfectly until today when I tried it without a keyboard attached (as I will use it).
ImportError: No keyboard files found (/dev/input/by-path/*-event-kbd).
Must I have a keyboard attached or is there anything I can do to get around it?
Caps lock, num lock, scroll lock are all toggle modifiers, so if their state is unexpected at the start of the program it'll never be fixed. There should be a way to poll their actual status.
This may be expanded to include other modifiers, so the library starts more ready.
This may require update the functions that handle modifier keys, to take into account 'toggle' keys too.
I had some problems getting keyboard events and found out that the problem was caused by these lines (nixkeyboard.py, line 65):
paths = glob('/dev/input/by-path/*-event-kbd')
print(paths)
if paths:
device = EventDevice(paths[0])
This code assumes that there's only one input device matching *-event-kbd
. If there are multiple matches, it selects the first. However, there are three matches on my machine:
paths = ['/dev/input/by-path/pci-0000:00:14.0-usb-0:3.2.1:1.1-event-kbd', # ???
'/dev/input/by-path/pci-0000:00:14.0-usb-0:3.2.1:1.0-event-kbd', # usb keyboard
'/dev/input/by-path/platform-i8042-serio-0-event-kbd'] # laptop keyboard
I tested that the second device is my usb keyboard and the third device is the keyboard of my laptop. I don't know about the first device.
I think the library should read input from all keyboard input devices (or even better, allow the user to specify which devices to read from). What do you think?
Linux doesn't seem to emit any events for multimedia keys. In Windows they were already weird because of their null scan code, but in Linux literally nothing happens.
This should be fixed somehow.
Importing the package doesn't work on my machine (Ubuntu 16.04):
Traceback (most recent call last):
File "/home/canyon/git/keyboard_fork/test.py", line 1, in <module>
import keyboard
File "/home/canyon/git/keyboard_fork/keyboard/__init__.py", line 1, in <module>
from .keyboard import *
File "/home/canyon/git/keyboard_fork/keyboard/keyboard.py", line 8, in <module>
from. import nixkeyboard as os_keyboard
File "/home/canyon/git/keyboard_fork/keyboard/nixkeyboard.py", line 49, in <module>
assert is_keypad_regular == is_keypad_shifted
AssertionError
The assertion fails at keycode 55. This is the relevant output of dumpkeys --keys-only
:
...
keycode 55 = KP_Multiply
altgr keycode 55 = Hex_C
shift alt keycode 55 = Hex_C
altgr shiftl keycode 55 = Hex_C
shift alt shiftl keycode 55 = Hex_C
altgr shiftr keycode 55 = Hex_C
shift alt shiftr keycode 55 = Hex_C
altgr shiftl shiftr keycode 55 = Hex_C
shift alt shiftl shiftr keycode 55 = Hex_C
altgr ctrll keycode 55 = Hex_C
shift alt ctrll keycode 55 = Hex_C
altgr shiftl ctrll keycode 55 = Hex_C
shift alt shiftl ctrll keycode 55 = Hex_C
altgr shiftr ctrll keycode 55 = Hex_C
shift alt shiftr ctrll keycode 55 = Hex_C
altgr shiftl shiftr ctrll keycode 55 = Hex_C
shift alt shiftl shiftr ctrll keycode 55 = Hex_C
...
I'm not sure if this could be causing the issue, but I'm using the German keyboard layout.
EDIT: the import works fine if comment the assertion line.
This simple line of code causes big problems on my system:
keyboard.add_hotkey('up', lambda: print("Registered."))
("up" may be substituted with "up arrow", "down", "down arrow", "left", "left arrow", "right", or "right arrow" to get the same result).
After running this, pressing the specified arrow key works as expected and calls the callback. Pressing literally any other key on the keyboard, however, raises an error with the following traceback:
Traceback (most recent call last):
File "C:\Python36-32\lib\site-packages\keyboard\_generic.py", line 23, in invoke_handlers
if handler(event):
File "C:\Python36-32\lib\site-packages\keyboard\__init__.py", line 296, in handler
unexpected = not any(matches(event, part) for part in steps[state.step])
File "C:\Python36-32\lib\site-packages\keyboard\__init__.py", line 296, in <genexpr>
unexpected = not any(matches(event, part) for part in steps[state.step])
File "C:\Python36-32\lib\site-packages\keyboard\__init__.py", line 152, in matches
return matched_name or _os_keyboard.map_char(normalized)[0] == event.scan_code
File "C:\Python36-32\lib\site-packages\keyboard\_winkeyboard.py", line 447, in map_char
raise ValueError('Key name {} is not mapped to any known key.'.format(repr(name)))
ValueError: Key name 'up' is not mapped to any known key.
On further inspection, this seems to be because the key names in to_scan_code
are localized (wtf, Windows?). It seems to be issue #12 coming back to bite you again! I suppose you fixed the ability to add keys with localized key names - just not without every other key breaking. 😉
 File "c:\GG-Python\WingProj\hupai\kbhit.py", line 5, in
import keyboard
File "C:\GG-Python\Anaconda\Lib\site-packages\keyboard__init__.py", line 1, in
from .keyboard import *
File "C:\GG-Python\Anaconda\Lib\site-packages\keyboard\keyboard.py", line 8, in
import keyboard.winkeyboard as os_keyboard
ImportError: No module named winkeyboard
I'm using the keyboard.hook function and certain keys like "ñ", "ç", "´", " ' ", "¡" and "º" are not getting recognize. Also when you input something like shift+. it recognizes something like left shift and . instead of : . Is there a way to change that?
Great job on the code btw, pyhook is a mess.
Hi, thanks for this useful library. I wrote a script to google the selected text when pressing the hot keys. After running it in root privileges, instead of opening my default web browser, it opens another one.
I added some codes to the script to drop the root privileges. Then the script worked perfectly.
uid = pwd.getpwnam('my_user_name')[2]
os.setuid(uid)
But it is possibly not a good idea to enter my user name. So is there another way to achieve this?
Any release date for mouse event generation support ?
When I try to define a hotkey "alt+shift+c", I get the following message:
('Error in keyboard hook: ', AttributeError("'list' object has no attribute 'clear'",))
I'm not immediately sure where this error is originating from, but it looks like the _keys_suppressed
list in the KeyTable
object in _suppress.py
doesn't have a clear()
method (perhaps it should be a set
instead of a list
?)
As mentioned in a thread about a different issue:
When I run this program:
import keyboard
def info(event):
print (event.name + ", " + str(event.scan_code) + ", " + event.event_type)
keyboard.hook(info)
keyboard.wait("esc")
and press left alt, I see "left alt, 56, down" as expected. When I release left alt, I see
left alt, 56, up
left alt, 56, down
left alt, 56, up
When I press and release right alt, I see:
left alt, 56, down
left alt, 56, up
I went looking for someplace else to test my keyboard events, and found https://w3c.github.io/uievents/tools/key-event-viewer.html
When I press and release left alt and then right alt in this tool, it looks like this:
http://i.imgur.com/FNNKpZn.png
It's not showing either problem.
I was slightly surprised that it was reporting my numlock status in this other tool. I tried turning off numlock to see if that made any difference to my "keyboard" problem. It didn't.
Windows 8.1
Tested on Python 2.7.13 and 3.6.0
keyboard 0.9.12
Submitting this as a potential future enhancement. I will continue to research/experiment on my end.
On Windows, keyboard-specific events can be identified using a combination of the RawInput and KeyboardHook APIs. This has the limitation of not capturing system shortcuts like Win+D or Alt+Tab.
I understand that CTRL+C will terminate the thread, but I would like to quit both GTK and keyboard with the same function. Did I miss something?
Right now if a user plugs or unplugs a keyboard on Linux the library won't realize. Specially now that Linux correctly reports the device id, it should be possible to update hardware changes.
Windows gives this for free.
Hi, thanks for this library, I'm trying to make use of it to create a simple custom hotkey "alias". I'm on a MacBook Air running Linux (Gentoo).
import keyboard
import time
keyboard.clear_all_hotkeys()
keyboard.add_hotkey('win+c', lambda: keyboard.send('ctrl+c'))
keyboard.add_hotkey('win+v', lambda: keyboard.send('ctrl+v'))
keyboard.add_hotkey('win+l', lambda: keyboard.send('ctrl+l'))
keyboard.add_hotkey('win+e', lambda: keyboard.send('ctrl+l'))
while True:
time.sleep(10)
On the script above, win+l
and win+e
are calling the same keyboard hotkey but only win+e
works. I'm hitting those hotkeys on Chrome browser.
If I change those mappings to a debugger output:
keyboard.add_hotkey('win+c', lambda: print('ctrl+c'))
keyboard.add_hotkey('win+v', lambda: print('ctrl+v'))
keyboard.add_hotkey('win+l', lambda: print('ctrl+l'))
keyboard.add_hotkey('win+e', lambda: print('ctrl+l'))
I do see the output on the console. Do you have any idea what could be cause these events to not be correctly processed by chrome?
P.S.: I don't think it's relative to Chrome, as the same hotkeys don't work on other applications (e.g. termite).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.