How can I capture a key press (key logging) in Linux?
For Windows exist pyHook library but I dont know how to do it in Linux.
You can use pyxhook:
#!/usr/bin/env python
import pyxhook
def OnKeyPress(event):
print (event.Key)
if event.Ascii == 32:
exit(0)
hm = pyxhook.HookManager()
hm.KeyDown = OnKeyPress
hm.HookKeyboard()
hm.start()
sudo apt-get install python-xlib
https://github.com/JeffHoogland/pyxhook
#!/usr/bin/env python
import pyxhook
import time
#This function is called every time a key is presssed
def kbevent( event ):
#print key info
print event
#If the ascii value matches spacebar, terminate the while loop
if event.Ascii == 32:
global running
running = False
#Create hookmanager
hookman = pyxhook.HookManager()
#Define our callback to fire when a key is pressed down
hookman.KeyDown = kbevent
#Hook the keyboard
hookman.HookKeyboard()
#Start our listener
hookman.start()
#Create a loop to keep the application running
running = True
while running:
time.sleep(0.1)
#Close the listener when we are done
hookman.cancel()
Related
def on_press(key):
if key == keyboard.Key.media_play_pause: #to identify paly & pause
print("status got changed")
if key == keyboard.Key.media_next: #to identify forword cammand track
print("Next track started")
if key == keyboard.Key.media_previous: #to identify privous cammand track
print("Previous track started")
def stetaupdate ():
global tapdflag
if (tapdflag == 0)
tapdflag = 1
with keyboard.Listener(on_press=on_press) as listener: #thredding
listener.join()
t = threading.Thread(target = stetaupdate)
This code works fine to detect play and pause events in Windows, but I am using the same code in Linux, and it is missing alternate events for play and pause with earbuds, but next and previous events were working fine.
I'm building a rudimentary autocomplete for my work, and it was doing fine, until I ran into this problem.
See example
import threading
from pynput import keyboard
from pynput.keyboard import Controller
controll = Controller()
def on_press(key):
if(key == keyboard.Key.alt_l):
controll.type("RIGHT !!!")
if(key == keyboard.Key.delete or key == keyboard.Key.enter):
return False
def handleKey():
x = input('INPUT> ')
print(x)
handle = threading.Thread(target=handleKey)
handle.start()
controll.type("RIGHT !!!")
with keyboard.Listener(
on_press=on_press) as listener:
listener.join()
When you press alt, you will see the output with the wrong string;
It must be [2] RIGHT !, but it was pressed [2]ight
But note that this only happens with the method call inside the event.
Is this a known issue? Am I using it wrong? I'm really confused
I believe that only with python3 and pip3 install pynput, this will make the example work
Tested with Windows 10
I've had a similar issue when trying to press a key while listening to a key. By my experience it is next to impossible. I have even tried to use other libraries' press functions such as pyautogui and keyboard inside of the pynput on_press function.
def on_press(key):
if key = keyboard.Key.esc:
return False
else:
if len(words) > i:
# p = keyboard.KeyCode.from_char(words[i])
pyautogui.press(word[i]) // also used keyboard.press(word[i])
i += 1
else:
keyboard.Controller.press(keyboard.Key.space)
with keyboard.Listener(on_press=on_press, suppress=True) as listener:
listener.join()
I feel like since the press action and the listen action are in different threads the program has to finish one before the other. At least that is what I gathered as I also have not found a solution to this. I also tried putting the press line after the listener.join() like this:
def on_press(key):
if key != keyboard.Key.esc:
return True
with keyboard.Listener(on_press=on_press, suppress=True) as listener:
listener.join()
if len(words) > i:
# p = keyboard.KeyCode.from_char(words[i])
pyautogui.press(words[i])
i += 1
else:
keyboard.Controller.press(keyboard.Key.space)
However, this did not solve the issue either because the program finished after listening to one input and then pressing words[i] once.
Please let me know if you find something. However I may not be able to comment bc of low reputation.
I had a similar issue as well, and something like this worked for me (on Ubuntu 20.04):
from pynput import keyboard
import threading
from time import sleep
event_queue = []
event_to_callback = {
# put your own key-to-function mapping here
# keyboard.KeyCode.from_char('c') : deal_with_c
}
def process_events():
while True:
for c in event_queue:
event_to_callback[c]()
event_queue.clear()
sleep(0.2)
keyboard.Listener(on_press=lambda k: event_queue.append(k)).start()
threading.Thread(target=process_events, args=()).start()
This decouples the listener's thread from the controller's thread; any callbacks that invoke pynput.keyboard.Controller methods will now be executed on a separate thread, different from the one of the listener.
I am trying to find a way to detect a keypress and then run a method depending on what key it is.
I can already do this with Tkinter. But what I can't do is detect the keypress while the window is in the background. I will be running this program in the background while I play a game. I need it to be able to detect inputs while I'm in the game.
Is there any way I can do this with Tkinter or something else? Preferably I would like to not have to download anything external as I would like to distribute this to some other people.
pyHook seems like it would work well for this (mentioned by furas)
from pyHook import HookManager
from win32gui import PumpMessages, PostQuitMessage
class Keystroke_Watcher(object):
def __init__(self):
self.hm = HookManager()
self.hm.KeyDown = self.on_keyboard_event
self.hm.HookKeyboard()
def on_keyboard_event(self, event):
try:
if event.KeyID == keycode_youre_looking_for:
self.your_method()
finally:
return True
def your_method(self):
pass
def shutdown(self):
PostQuitMessage(0)
self.hm.UnhookKeyboard()
watcher = Keystroke_Watcher()
PumpMessages()
I suggest not to use pyHook anymore, because it's an old, not maintained library (last updated in 2008)
Alternatively there are many other libraries, which are actively maintained for example pynput:
from pynput.keyboard import Key, Listener
def on_press(key):
print('{0} pressed'.format(key))
def on_release(key):
print('{0} release'.format(key))
if key == Key.esc:
return False
with Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
keyboard can be an another alternative which may be worth considering.
Too get all the properties from your key press event. you can do the following
import pythoncom, pyHook
def OnKeyboardEvent(event):
print('MessageName:',event.MessageName)
print('Message:',event.Message)
print('Time:',event.Time)
print('Window:',event.Window)
print('WindowName:',event.WindowName)
print('Ascii:', event.Ascii, chr(event.Ascii))
print('Key:', event.Key)
print('KeyID:', event.KeyID)
print('ScanCode:', event.ScanCode)
print('Extended:', event.Extended)
print('Injected:', event.Injected)
print('Alt', event.Alt)
print('Transition', event.Transition)
print('---')
# return True to pass the event to other handlers
return True
# create a hook manager
hm = pyHook.HookManager()
# watch for all mouse events
hm.KeyDown = OnKeyboardEvent
# set the hook
hm.HookKeyboard()
# wait forever
pythoncom.PumpMessages()
Now know all the details of the key press and do operation on top of this.
pressing 's' would look like this
MessageName: key down
Message: 256
Time: 449145375
Window: 2558060
WindowName: "file name"
Ascii: 115 s
Key: S
KeyID: 83
ScanCode: 31
Extended: 0
Injected: 0
Alt 0
Transition 0
See pynput.
def on_release(key):
global running
if key == keyboard.Key.esc:
running = False;
running = True
listener = keyboard.Listener(on_release=on_release)
# run listener in background so that the while loop gets executed
listener.start()
while running
print("running some code")
listener.stop()
I was playing around with info I can get from key presses and mouse events in python and everything seems to work except when I quit the program I get this error.
runtime error R6031 - Attempt to initialize the CRT more than once. This indicates a bug in your application.
Here is my code not that it only happens when I press 'q' and the program quits.
import pythoncom, pyHook, sys
def OnMouseEvent(event):
# called when mouse events are received
print 'MessageName:',event.MessageName
print 'Message:',event.Message
print 'Time:',event.Time
print 'Window:',event.Window
print 'WindowName:',event.WindowName
print 'Position:',event.Position
print 'Wheel:',event.Wheel
print 'Injected:',event.Injected
print '---'
return True
def OnKeyboardEvent(event):
print "Message Name: ", event.MessageName
print 'Message:',event.Message
print 'Time:',event.Time
print 'Window:',event.Window
print 'WindowName:',event.WindowName
print 'Ascii:', event.Ascii, chr(event.Ascii)
print 'Key:', event.Key
print 'KeyID:', event.KeyID
print 'ScanCode:', event.ScanCode
print 'Extended:', event.Extended
print 'Injected:', event.Injected
print 'Alt', event.Alt
print 'Transition', event.Transition
print '---'
if chr(event.Ascii) == 'q':
sys.exit()
return True
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.MouseDown = OnMouseEvent
hm.HookKeyboard()
hm.HookMouse()
pythoncom.PumpMessages()
Thanks in advance for the help!
You have to "unhook" the hooks that you created to do a proper exit.
To terminate the "pythoncom.PumpMessages()" ever-lasting-loop:
if chr(event.Ascii) == 'q':
ctypes.windll.user32.PostQuitMessage(0)
The following code works correctly on Windows 7 with Python 2.7.6.
I haven't yet figured out how to make it work under Python 3.4, but I'll be back when I know!
import pythoncom, pyHook
import ctypes
import sys
def OnMouseEvent(event):
# called when mouse events are received
print('MessageName:', event.MessageName)
print('Message:', event.Message)
print('Time:', event.Time)
print('Window:', event.Window)
print('WindowName:', event.WindowName)
print('Position:', event.Position)
print('Wheel:', event.Wheel)
print('Injected:', event.Injected)
print('---')
return True
def OnKeyboardEvent(event):
print("Message Name: ", event.MessageName)
print('Message:', event.Message)
print('Time:', event.Time)
print('Window:', event.Window)
print('WindowName:', event.WindowName)
print('Ascii:', event.Ascii, chr(event.Ascii))
print('Key:', event.Key)
print('KeyID:', event.KeyID)
print('ScanCode:', event.ScanCode)
print('Extended:', event.Extended)
print('Injected:', event.Injected)
print('Alt', event.Alt)
print('Transition', event.Transition)
print('---')
if chr(event.Ascii) == 'q':
ctypes.windll.user32.PostQuitMessage(0)
return True
print("")
print('Python version:')
print((sys.version))
print("")
hm = pyHook.HookManager() # create a hook manager
hm.MouseAll = OnMouseEvent # watch for all mouse events
hm.HookMouse() # set the hook
hm.KeyDown = OnKeyboardEvent # watch for "OnKeyboardEvent"
hm.HookKeyboard() # set the hook
pythoncom.PumpMessages()
# if you reached this point you have terminated the program correctly!
# flush and close any open files etc.
hm.UnhookMouse()
hm.UnhookKeyboard()
print("")
print("The end of Mouse and KBD test!")
print("")
LushIsTheLanguage's answer does not solve the error.
The error comes on 64 bit Python installations, not 32 bit.
It is caused by HookMouse, if that is disabled then the error disappears.
So, it's a bug in PyHook/HookMouse for 64 bit Python installations. The quickest solution is to switch to 32 bit Python.
The suggestion of LushIsTheLanguage has partly solved one problem I was facing for long time. I have embedded python interpreter in one multithreaded C code with GTK. I could run my *.py script (with pyHook imported in it) from the GTK based GUI only for first time. Next time when I used to run it the full code used to crash. Without pyHook imported scripts I could run any number of times from my GUI.
Now after calling hm.UnhookMouse() and hm.UnhookKeyboard() at the end of the python script I can run it more that one time from my GUI. However still it is crashing after four or five times.
In my *.py script I am not using "pythoncom.PumpMessages()", rather I am using while loop with "pythoncom.PumpWaitingMessages()", so that I can break it once any key is pressed.
key_scn_code = -1
while key_scn_code < 0:
time.sleep(0.05)
if os.name == 'nt':
pythoncom.PumpWaitingMessages()
my callback for keyboard-events is something like the following
def kbevent_callback( key_event ):
global key_scn_code
key_scn_code = key_event.ScanCode
return True
I have checked it in Win-7 64-bit (python 2.7 32-bit) and Linux 64-bit (using pyxhook) with python 2.7. Both have similar problem. Does any one have any suggestion.
I am trying to make the most simple pythong code that will respond when a button is pressed on a joystick. I used code from several different examples and I still cannot get it to work. The following code will not dispatch the event when I press the trigger (or any button for that matter)
import pygame
joy = []
def handleJoyEvent(e):
if e.type == pygame.JOYBUTTONDOWN:
str = "Button: %d" % (e.dict['button'])
if (e.dict['button'] == 0):
print ("Pressed!\n")
else:
pass
def joystickControl():
while True:
e = pygame.event.wait()
if (e.type == pygame.JOYBUTTONDOWN):
handleJoyEvent(e)
# main method
def main():
pygame.joystick.init()
pygame.display.init()
for i in range(pygame.joystick.get_count()):
myjoy = pygame.joystick.Joystick(i)
myjoy.init()
joy.append(myjoy)
# run joystick listener loop
joystickControl()
# allow use as a module or standalone script
if __name__ == "__main__":
main()
I assume you've tried leaving off the if and just printing str?
Your joystick might also not be working properly. Does it work in other programs?
If you are using linux you might need to install a joystick driver. For Windows, check the device manager.