I just found out about the pynput library which is exactly what I have been looking for. My goal is to capure the keys the user is typing and whenever a specific sequence of keys was captured I want the computer to write a sequence to the current carret's position. After that I want to capture the usersĀ“s keys again until another noteworthy sequence occurs. And so on.
The problem is that the simulated key strokes of keyboard.write() are also considered by the Listener which leads to an infinite loop which was funny the first time it occurred but I am trying to get rid of it now obv.
My approach is to stop the Listener and create a new one after the computer is done typing but this process slows down a lot after the first start_listener() invocation and isn't optimal in the first place I think. And I am out of further ideas so I was hoping someone could help here.
Here is my code so far:
import keyboard
from pynput.keyboard import Key, Listener
def on_press(key):
stop_listener()
keyboard.write("Hello", 0.05)
start_listener()
def on_release(key):
if key == Key.esc:
return False
def start_listener():
global listener
listener = Listener(on_press=on_press, on_release=on_release)
listener.start()
listener.join()
def stop_listener():
global listener
listener.stop()
with Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
There is a simple solution to the problem. I actually missed that I used two packages that have nothing to do with each other. Thanks to the ease to install them on my IDE.
Anyway my solution is now to only use the already present keyboard package https://pypi.org/project/keyboard/ and not pynput.keyboard
It turn out to be really easy when not using two separate packages :).
Here is the code:
# coding=utf8
import keyboard as k
def on_press(key = k.KeyboardEvent):
k.write(key.name, 0.0)
k.on_press(on_press)
k.wait()
On my Linux Mint I need admin privileges to run keyboard but I can do the same with pynput.keyboard.Controller and methods press(), release(), time.sleep()
Instead of stoping and starting listenere I would use global variable paused = False to control when on_press should runs code.
from pynput.keyboard import Key, Listener, Controller
import time
keyboard = Controller()
def on_press(key):
global paused # inform function to assign new value to global variable (instead of creating local variable)
if not paused:
paused = True
#keyboard.type("Hello") # module pynput.keyboard.Controller
for char in "Hello":
keyboard.press(char) # pynput.keyboard.Controller
keyboard.release(char) # pynput.keyboard.Controller
time.sleep(0.05)
paused = False
def on_release(key):
if not paused:
if key == Key.esc:
return False
# global variable with default value at start
paused = False
with Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
Tested on Linux Mint 20, Python 3.8.5, pynput 1.7.3
Related
I am making a program in python to detect what key is pressed and based on my keyboard it will make a decision.
I want to implement it using keyboard module in python.
I would do something like this,
import keyboard
while True:
if keyboard.read_key() == 'enter':
print('Enter is pressed)
if keyboard.read_key() == 'q':
print('Quitting the program)
break
if keyboard.read_key() == 's':
print('Skiping the things')
But it doesn't work. When I execute this program, I have to press s twice to execute the "s" block.
Also, I have a problem that is after the execution is finished, it writes all the keys in my command prompt is it possible to fix that?
As per Keyboard documentation:
Other applications, such as some games, may register hooks that swallow all key events. In this case keyboard will be unable to report events.
One way to solve your problem with keyboard module is keyboard.wait('key')
# Blocks until you press esc
keyboard.wait('esc')
Something work around is as below:
import keyboard
keyboard.wait('enter')
print('Enter is pressed')
keyboard.wait('q')
print('Quitting the program')
keyboard.wait('s')
print('Skiping the things')
As Far I Know There is only one efficient way to Detect user input weather it keybored or mouse input Which is library called pynput ......
from pynput.keyboard import Key , Listener , Controller
keyboard = Controller()
DoubleShot=False
shot=False
def on_press(key):
global DoubleShot
global shot
if Key.num_lock == key:
print("activate")
DoubleShot=True
if DoubleShot:
if Key.shift == key:
shot = not shot
if shot:
keyboard.press(Key.shift)
keyboard.release(Key.shift)
def on_release(key):
if key == Key.esc:
return False
with Listener(on_press=on_press , on_release=on_release) as listener:
listener.join()
i create this for a game to shoot multiple time on 'shift' clicked
code activate only when ' numlock ' clicked.....
Controller is for clicking any key you want
Note:
In My case infinity looping was a problem that's why shot variable is there to stop looping
I'm trying to do something that seems very basic, but I keep getting myself stuck inside of loops that don't allow me to perform other actions. For example:
def functionOne():
if x key is pressed:
do something
def functionTwo():
if y key is pressed:
do something else
def functionThree():
if z key is pressed:
do something else
def main():
functionOne()
functionTwo()
functionThree()
main()
I was trying to to do while loops in each function, but that locks each function in its own loop cycle. I essentially want my program to run until I press a very specific key combination from the Python keyboard package. I assume loops are the way to keep a program running?
Or say, if I wanted to implement this on a GUI, and only exit the program when hitting the quit button on the GUI, while waiting for the other buttons to be clicked to do something else.
I'm aware that I could do a giant main loop with conditions nested inside one another, but I'm hoping there is a cleaner way to do this involving functions.
Try this way:-
def functionOne(key):
if key != 'x':
return
if x key is pressed:
do something
def functionTwo(key):
if key != 'y':
return
if y key is pressed:
do something else
def functionThree(key):
if key != 'z':
return
if z key is pressed:
do something else
def main():
while key != 'q':
key = input("Enter the key :")
functionOne(key)
functionTwo(key)
functionThree(key)
main()
Other than that you can use threading if functions are computationally heavy and key input interval is smaller than the computational time of the functions.
you could take advantage of pynput
first install it
pip install pynput
then you can achieve what you are looking for like the following example (obtained from pynput documentation):
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()
# ...or, in a non-blocking fashion:
listener = keyboard.Listener(
on_press=on_press,
on_release=on_release)
listener.start()
My friend and I were building a typing test. We are using the input() function in python to get input from the user. The problem is that we have to press enter to make the input save and we want that button to be spacebar instead. Is there any way to do this or another module we could use to solve this problem?
for i in range(num_words):
print(final_sentence)
print("")
typed_word = input("Type>")
words_to_list(typed_word)
os.system('clear')
You should probably use other modules like keyboard or pynput because input() detects whole strings while those modules detect key presses. Detect key presses, print them, and stop when Key.space (in pynput case) is pressed.
Something like this:
from pynput.keyboard import Listener
from pynput.keyboard import Key
words=''
def on_press(key):
if key==Key.space:
listener.stop()
print (words)
def on_release(key):
global words
typed = str(key).replace("'", "")
words = words + typed
with Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
This code detects key press using pynput.keyboard's handy listener, and adds it to words until space is pressed. When space is pressed the script stops the listener and prints the typed sentence.
I have a Python module that listens for a key combination using pynput then, once it's pressed, it types a string into a text program.
It works great! Except...
In the example below, the user's key combo is set to shift + space. This makes a lot of sense and will likely be the most common chosen key command for Windows users running my program. The trouble is, while the shift key is held down it changes what pynput types. Instead of 01/20/2019, it will type )!/20/2019.
I need a way to disable the keyboard until pyautogui is finished typing the string. Thanks a lot for your help!!!
Bonus question: I can't seem to get a result when the key combination includes a ctrl key. Key.ctrl simply fails to ever trigger, whilst other keys work fine.
from pynput.keyboard import Key, Controller, Listener
import time
keyboard = Controller()
def insert(): # check line 1 of config file
keyboard.type('01/20/2019')
# The currently active modifiers
current = set()
def on_press(key):
if key in COMBINATION:
current.add(key)
if all(k in current for k in COMBINATION): # I don't know what this k in current for k shit is.
current.remove(key)
insert() # run insert
if key == Key.esc:
listener.stop()
def on_release(key):
try:
current.remove(key)
except KeyError:
pass
with Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
``
You can use pyautogui.keyUp("shift") before you type.
def insert():
f=open('tc.txt')
line=f.readlines()
insert.timestamp=(line[0])
time.sleep(.1)
pyautogui.keyUp("shift")
pyautogui.typewrite(insert.timestamp)
I have this relatively simple program that listens for mouse clicks and when the mouse button is held down prints "1"s. Unfortunately when I let go of the mouse it just keeps printing "1"s, even though there is an if statement which checks if the mouse is clicked and should stop the loop if it is not. I am using the pynput.mouse module for the mouse interaction.
Here is my code:
import time
from pynput.mouse import Listener
def clicked(x, y, button, pressed):
if pressed == True:
while button == button.left:
print("1")
time.sleep(1)
if pressed == False:
break
with Listener(on_click=clicked) as listener:
listener.join()
My theory is that once the loops starts it stops listening for mouse clicks, so it can never stop the loop. Would it be necessary to create a new thread for the loop? If yes, how would I do that?
Thanks!
Your current logic makes it impossible to get out of the loop, since pressed doesn't change within the loop. There is not a statement that checks if the mouse is clicked: your only if statements check whether the mouse was clicked when you entered the function. pressed doesn't change within the function.
Look at the critical logiic:
if pressed == True:
while ...
...
if pressed == False:
break
There is nothing in here to change the value of pressed; the first if guarantees that it's True anywhere within the loop.
Yes, you need to set up another listener that operates within the loop. You already know the building blocks: create a new one within the function and bind it to another operation that breaks the loop. For instance, you might "cheat" and have it reset pressed as a global variable.
You could also research how to do this in other answers, if you want an overall handler solution. keypress and keyrelease have been done often enough.
import pyautogui, random, time
import pynput
keys = ['w', 's', 'a', 'd']
def on_press(key):
p = True
if key == pynput.keyboard.Key.esc:
return False
else:
while p == True:
press = keys[random.randint(0,3)]
pyautogui.keyDown(press)
pyautogui.keyUp(press)
p = False
with pynput.keyboard.Listener(on_press=on_press) as L:
L.join()
a code like this will work instead of what you did.
BTW, that is just an example; feel free to visit my GitHub page: github.com/ironnicko