I use a Raspberry Pi via SSH from my Windows 7 and I build a robot. If you press an arrow, it will move. I detect the key with TkInter module, but it needs a graphic environment. So if I am only in an SSH terminal, it can't run. Is there some module which can detect keys and doesn't need a window?
This is the exact use case sshkeyboard library. It does not require a graphic environment or window, and is simple to use: simply pip install sshkeyboard and:
from sshkeyboard import listen_keyboard
def press(key):
if key == "up":
print("up pressed")
elif key == "down":
print("down pressed")
elif key == "left":
print("left pressed")
elif key == "right":
print("right pressed")
listen_keyboard(on_press=press)
It will detect all arrows, print the detections to terminal.
You can also detect releasing keys with a on_release=... parameter which works the exact same way as on_press.
i have not tried it, but a quick search has shown up this:
example
github source
which is essentially a linux implementation of pyhook (windows only)
so to use it:
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
I want to detect if a keypress was executed programmatically (not by user's physical press). Is there any way to do this?
import mouse
import keyboard
import time
keyboard.press("a")
if keyboard.is_pressed('a'):
print ("pressed")
I assume 'is_pressed' in the code above only detects actual input from user hence it wouldn't show print ("pressed"). All I could come up with to solve this is the code below which works just fine for my intention but I want to know if there's a better optimized way.
import mouse
import keyboard
import time
keyboard.press("a")
keyboard_a = True
keyboard.press("b")
keyboard_b = True
if keyboard_a:
print ("a pressed")
if keyboard_b:
print ("b pressed")
It is not possible to distinguish between key press events that are triggered programmatically and those that are triggered by user input. The same is true for readchar, msvcrt, or keyboard libraries.
So, the library provides a way to detect and respond to key press events, regardless of their origin. Hence, your approach with a flag is good.
I don't know your precise aim, but maybe you would prefer to use send and a register event like this
import keyboard
import threading
is_programmatic = False
# Define a function to be called when a specific key is pressed
def on_key_press(keyEvent):
global is_programmatic
if keyEvent.name == 'a':
if is_programmatic:
print("Key press event triggered programmatically")
else:
print("Key press event triggered by user input")
is_programmatic = False
# Register listener
keyboard.on_press(on_key_press)
# Start keyboard listener
keyboard.wait()
# or start a thread with the listener (you may want to sleep some seconds to wait the thread)
thread = threading.Thread(target=keyboard.wait)
thread.start()
and to issue the event
is_programmatic = True
keyboard.send("a")
You can create a list and store pressed keys in that list. You can find if a key is pressed by searching that list.
import keyboard
key_pressed = []
keyboard.press("a")
key_pressed.append("a")
keyboard.press("b")
key_pressed.append("b")
keyboard.press("c")
key_pressed.append("c")
#check if a specific key is pressed
if "a" in key_pressed:
print ("a pressed")
Print all pressed keys:
for key in key_pressed:
print(key,'pressed')
Print the last pressed key:
print(key_pressed[-1])
You can also create a class to make it easier to use:
import keyboard
class CustomKeyboard():
def __init__(self):
self.pressed_keys = []
def press(self, key):
keyboard.press(key)
self.pressed_keys.append(key)
def is_pressed_programmatically(self, key):
if key in self.pressed_keys:
return True
return False
Then use it like this:
kb = CustomKeyboard()
kb.press('a')
kb.press('b')
print("did a pressed programmatically?:")
print(kb.is_pressed_programmatically('a'))
print("did z pressed programmatically?:")
print(kb.is_pressed_programmatically('z'))
and here is the output:
is a pressed programmatically?: True
is z pressed programmatically?: False
I want m_listener to start only when I press f6
and if I clicked F7, it stopped.
f6 it again to continue.
My issue is that when I click f7 it totally stops the listener and on_x_y_click never run again if i clicked f6
import pynput
import easygui
from pynput import *
def on_x_y_click(x, y, button, pressed):
print((x, y, button, pressed))
def on_release(key):
print(key)
if key == keyboard.Key.f6:
m_listener.join()
elif key == keyboard.Key.f7:
m_listener.stop()
elif key == keyboard.Key.esc:
# Stop listeners
m_listener.stop()
return False
# Collect events until released
with keyboard.Listener(on_release=on_release) as k_listener, \
mouse.Listener(on_click=on_x_y_click) as m_listener:
k_listener.join()
m_listener.join()
In the documentation, there doesn't seem to be any functionality to do this directly.
However, you can fairly easily implement this yourself by simply setting a flag and ignoring events when that flag is set:
from pynput import *
b_ignore_mouse_events = False
def on_x_y_click(x, y, button, pressed):
if b_ignore_mouse_events:
return
print((x, y, button, pressed))
def on_release(key):
global b_ignore_mouse_events
print(key)
if key == keyboard.Key.f6:
b_ignore_mouse_events = False
elif key == keyboard.Key.f7:
b_ignore_mouse_events = True
# Collect events until released
with keyboard.Listener(on_release=on_release) as k_listener, \
mouse.Listener(on_click=on_x_y_click) as m_listener:
k_listener.join()
m_listener.join()
Some notes about this:
Using global variables is often bad in larger applications, it seems fine for this simple script though.
Currently, the listeners are not stopped immediately when <ESC> is pressed.
Instead, you need to press a mouse button again because the mouse listener thread is waiting for the next key to be pressed and doesn't notice that it was stopped until that happens.
I just removed that part of the code because it did not function correctly. If you need that, you can ask another question about that (after searching for a solution yourself).
I have got a keyboard with a non-working windows key.
I tried to fix it with Python if I press the > key, the program will press the windows key, but it's not working.
Here's the code:
import msvcrt
import pyautogui
while True:
if msvcrt.kbhit():
key_stroke = msvcrt.getch()
if key_stroke == b'>':
pyautogui.press('super')
print(key_stroke)
Can anyone help me? Thanks
To press ">" you need to press two keys "shift" + ".", when you release the "." key you registered ">" being a keystroke. but till that time you have not released the "shift" key.
In a nutshell when you execute pyautogui.press('super') in line 7, you are already pressing the "shift" key and then sending the "super" key command.
Solution to your problem is simple, release the "shift" key before sending the pyautogui.press('super') cmd.
The below code will resolve your problem.
Please install pynput package first (pip install pynput). Documentation for pynput
Solution - 1 (Modifying your code)
import msvcrt
import pyautogui
from pynput import keyboard
kb = keyboard.Controller()
while True:
if msvcrt.kbhit():
key_stroke = msvcrt.getch()
if key_stroke == b'>':
kb.release(keyboard.Key.shift)
pyautogui.press('super')
print(key_stroke)
Solution - 2 (This will give you more control over your keyboard events)
To exit from the shell press the "Esc" key.
from pynput import keyboard
kb = keyboard.Controller()
def on_press(key):
try:
print('alphanumeric key {0} pressed'.format(
key.char))
except AttributeError:
print('special key {0} pressed'.format(
key))
def on_release(key):
print('{0} released'.format(
key))
if hasattr(key, 'char') and key.char == ">":
kb.release(keyboard.Key.shift)
kb.press(keyboard.Key.cmd)
kb.release(keyboard.Key.cmd)
if key == keyboard.Key.esc:
# Stop listener
return False
# Collect events until released
with keyboard.Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
# ...or, in a non-blocking fashion:
listener = keyboard.Listener(
on_press=on_press,
on_release=on_release)
listener.start()
If you want to remap keys in python, the keyboard module is what you are looking for.
Please install keyboard package first (pip install keyboard). Documentation
The remap_hotkey function does exactly what you need.
keyboard.wait blocks the execution of the code until a key is pressed.
import keyboard
keyboard.remap_hotkey("Shift+.", "windows")
while True:
keyboard.wait()
Note that "Shift+." may change depending on your keyboard layout.
I am making a snake game which requires the player to press the WASD keys without stopping the game process to to get input from player. So I can't use input() for this situation because then the game stops ticking to get input.
I found a getch() function which immediately gives input without pressing enter, but this function also stops game ticking to get input like input(). I decided to use threading module to get input via getch() in different thread. The problem is that getch() isn't working while in different thread and I'm not sure why.
import threading, time
from msvcrt import getch
key = "lol" #it never changes because getch() in thread1 is useless
def thread1():
while True:
key = getch() #this simply is almost ignored by interpreter, the only thing it
#gives is that delays print() unless you press any key
print("this is thread1()")
threading.Thread(target = thread1).start()
while True:
time.sleep(1)
print(key)
So why getch() is useless when it is in thread1()?
The problem was that you're creating a local variable key inside thread1 instead of overwriting the existing one. The quick-and-easy solution would be to declare key to be global inside thread1.
Finally, you should consider using locks. I don't know if it's necessary or not, but I'd imagine weird things could happen if you try and write a value to key in the thread while printing it out at the same time.
The working code:
import threading, time
from msvcrt import getch
key = "lol"
def thread1():
global key
lock = threading.Lock()
while True:
with lock:
key = getch()
threading.Thread(target = thread1).start()
while True:
time.sleep(1)
print(key)
I tried using getch but it didn't work for me... (win7 here).
You can try using tkinter module // but I still can't make it running with threads
# Respond to a key without the need to press enter
import tkinter as tk #on python 2.x use "import Tkinter as tk"
def keypress(event):
if event.keysym == 'Escape':
root.destroy()
x = event.char
if x == "w":
print ("W pressed")
elif x == "a":
print ("A pressed")
elif x == "s":
print ("S pressed")
elif x == "d":
print ("D pressed")
else:
print (x)
root = tk.Tk()
print ("Press a key (Escape key to exit):")
root.bind_all('<Key>', keypress)
# don't show the tk window
root.withdraw()
root.mainloop()
As Michael0x2a says you may try using library made for game-making - pygame or pyglet.
#EDIT #Michael0x2a:
Are you sure your code works?
Whatever I press it always prints the same key.
#EDIT2:
Thanks!
I was wondering how do I get a key pressed in python
I tried doing:
import msvcrt as keys
while True:
key = keys.getch()
if key == "a":
print("You have pressed a")
Does anyone know how to fix it?
This might help you:
import msvcrt
while True:
if msvcrt.kbhit() and msvcrt.getch() == chr(97): # chr(97) = 'a'
print("You have pressed a")
Note: your code and my code won't work in many Python IDE's! You need to execute the python file, e.g. in a command window.