New to python and wanting to write an app for a Raspberry Pi, but wanting to develop it on my computer first without having to assemble all the buttons, so I was thinking just using a keyboard in replace of buttons would work. But I can't seem to find a good solution for looping a script and watching for keyboard input at the same time.
Specifically, I am trying to run a loop that checks the status of buttons. If any button goes on, it will turn on a shared device. If that button then goes off it will turn off the shared device after a certain time period unless any other button is on. However, if in the time period that the button goes off, but the device has not shut down, another button goes on, the device will not shut down.
I was thinking this would be easier to develop using a keyboard and the numbers 1-8 for the 8 buttons I would have connected to the Pi.
If I use
x = input()
The script stops and waits for an input, but I need it to continue to run in the background.
So I tried with with the keyboard module
import keyboard
import time
while True: #
try:
if keyboard.is_pressed('q'): #
print("you pressed q")
except:
print("no key")
currenttime = time.time()
print (f'the new time is {currenttime}' )
time.sleep(1)
But it only accepts the keyboard input sometimes. Like not while it is sleeping, which I'm using as an example of if the script was busy doing other things.
I found this code searching around
from pynput import keyboard
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 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()
Aside from the security issues, it grabs the keyboard input but I don't know where to put my loop.
I also played around a bit with tkinter, but since I'm not trying to build a GUI, this didn't seem like the right path.
I'd recommend looking into event binding: https://www.geeksforgeeks.org/python-binding-function-in-tkinter/
Related
I'm using the python pynput module to send emulated keypresses to my computer. I've tried it also with pyautogui, but either case has a problem: I'm trying to detect my own keypresses simulatneously, and my program is detecting the pynput emulated keypresses as well, with no way of filtering them.
from pynput.keyboard import Key, Listener, Controller
keyboard = Controller()
def write(word):
global keyboard,typing
keyboard.type(word)
def on_press(key):
global curword
key = str(key).replace("'","")
if key.isalpha():
write("hello") #when it detects a letter being pressed, it writes hello
def on_release(key):
pass
with Listener(on_press=on_press,on_release=on_release) as listener:
listener.join() #detects keypresses
Essentially, I'm trying to make a code that just autocompletes words when I type them, but when the program 'writes' the word out, the pynput listener detects the controller typing and creates an infinite loop.
It just doesnt work i get an error saying
AttributeError: 'Controller' object has no attribute 'is_pressed'
Code:
from pynput.mouse import Button, Controller
from pynput.keyboard import Key, Controller
from pynput.keyboard import Controller
from pynput import mouse
from pynput import keyboard
keyboard = Controller()
while True:
if keyboard.is_pressed('u'):
keyboard.press('w')
keyboard.release('w')
Can someone help me out!
pynput has special class Listener to catch pressed keys. It runs in thread and it doesn' need while True so it doesn't block main code.
Press ESC to stop it.
from pynput.keyboard import Key, Controller, Listener
def on_press(key):
print('{} pressed'.format(key))
#print(dir(key))
try:
if key.char == 'u':
keyboard.press('w')
keyboard.release('w')
except Exception as ex:
print(ex)
def on_release(key):
print('{} release'.format(key))
if key == Key.esc:
# Stop listener
return False
# --- main ---
keyboard = Controller()
listener = Listener(on_press=on_press, on_release=on_release)
listener.start()
# ... other code ...
listener.join()
BTW:
If you want global macros/hotkeys in system and use Linux then you could use special program AutoKey for this. It is created with Python and it is has GUI to create macros/script/etc.
If you want global macros/hotkeys in system and use Windows you could rather use popular AutoHotKey
If you want to create macros/hotkeys in some GUI programs then you should use GUI functions for this.
View the documentation, here's a snippet from it below.
Global hotkeys
A common use case for keyboard monitors is reacting to global hotkeys.
Since a listener does not maintain any state, hotkeys involving
multiple keys must store this state somewhere.
pynput provides the class pynput.keyboard.HotKey for this purpose. It contains two methods to update the state, designed to be easily
interoperable with a keyboard listener: pynput.keyboard.HotKey.press
and pynput.keyboard.HotKey.release which can be directly passed as
listener callbacks.
[...]
This will create a hotkey, and then use a listener to update its
state. Once all the specified keys are pressed simultaneously,
on_activate will be invoked.
Note that keys are passed through pynput.keyboard.Listener.canonical
before being passed to the HotKey instance. This is to remove any
modifier state from the key events, and to normalise modifiers with
more than one physical button.
The method pynput.keyboard.HotKey.parse is a convenience function to
transform shortcut strings to key collections. Please see its
documentation for more information.
To register a number of global hotkeys, use the convenience class
pynput.keyboard.GlobalHotKeys:
I want to make a program that runs a code when you just click on a button on a keyboard for example, I press A and some code runs, but I do not have to press enter or input it to run it. Just like in video games, your character moves if you press W. Sorry if it is worded badly, I am pretty confused about this.
Keep in mind please it's Python 2.7
I am assuming you mean in the console and not in any gui like tkinter or something.
I'd suggest using pynput (pip install pynput)
with code similar to this
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:
# Stop listener
return False
while True:
with Listener(on_press=on_press,on_release=on_release) as listener:
listener.join()
word of warning:
The above code also catches exit keys so ctrl + c will not stop the console. for that you would need to implement something to break out of the While loop when ctrl+c is pressed.
I'm making a python program that changes my wallpaper every hour, but i want to be able to also change the wallpaper when i press a certain button.
this is the code i've tried
while True:
key = ord(getch())
but the only bad part is that it gets stuck on that until i press something. Is there a better way to do this?
You may be able to achieve what you want by using https://pypi.python.org/pypi/pynput.
See also its docs on pythonhosted http://pythonhosted.org/pynput/, especially the section about monitoring the keyboard http://pythonhosted.org/pynput/keyboard.html#monitoring-the-keyboard.
The following is an example from the docs:
from pynput.keyboard import Key
from pynput.keyboard import Listener
def on_press(key):
print('{0} pressed'.format(
key))
def on_release(key):
print('{0} release'.format(
key))
if key == Key.esc:
# Stop listener
return False
# Collect events until released
with Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
It will print every key you press until you press ESC, after which it will terminate.
Note that there are some operating system specific things to consider, for example on OSX the process must run as root.
I somehow accidentally found this.
import msvcrt
if msvcrt.kbhit():
Key = ord(getch())
if Key ==96:
#Do something here
And that seems to work. I think msvcrt.kbhit() is waiting for an keypress. Key = ord(getch()) takes the keypress and if Key ==96: checks if its the right keypress
I programmed a standard keylistener with pynput, but when using keyboard.type, it seems like the keys are released twice.
from pynput.keyboard import Controller, Listener
keyboard = Controller()
def on_release(key):
print('key {} released'.format(key))
if key.char == 'a':
keyboard.type('b')
with Listener(on_release=on_release) as listener:
listener.join()
# Pressing 'a' yields:
#
# key u'a' released
# key u'b' released
# key u'b' released
It doesn't seem like the key is pressed twice, only released twice. Is this the intended behavior? If not, what should be done to avoid this?
This is a bug in pynput.
As you have noticed, events can reach a Listener both from the system and when Controllers are invoked. The latter is true only for Xorg and win32, as they do no propagate synthetic events to listeners.
Or so I thought. It turns out that on win32, this is true only for mouse events; keyboard events appear to propagate normally. In any case, I have pushed a proposed solution here.
If you have the opportunity to test it, I would be grateful, otherwise I will merge it into master in a couple of days and make a new release. I only have access to win32 through VirtualBox, so I would appreciate some more bare-metal testing.