Warning: my English sucks and also I'm really new to python
So I'm making a program that requires a specific Key Press (e.g. space bar) to continue the loop, like:
for i in *some sort of list*:
print(something)
*waits for a key*
and my method for the last line is the keyboard module (not from pynput), which has the functionis_pressed. When I pressed a key, I got the output:
*something*
*something*
*something*
*repeats for several times*
I know that the function detects key press instead of press and release, so this output stops as soon as I release it. But that not how my program works. It should respond every time I release that key. Unfortunately I couldn't find a function called is_released or something, and module pynput can't get the key I pressed using Listener. At least I can't.
Also, is there a way to have both keyboard and pynput importable in a computer? My VS Code ignores keyboard when pynput is installed.
Edit: this is my solution for the problem, but it's super dumb:
while True:
if keyboard.is_pressed('space'):
while True:
if not keyboard.is_pressed('space'):
break
break
Is there a function that does the same thing?
Since it detects keypress only, use flags. I think something like this can do it:
1. Make a bool variable to detect a single key press
2. If key is pressed, the bool will be set to true
3. If bool is true and not key.is_pressed: do your thing
4. Set bool to false after operation
For example, in code, that will be like this:
keypress = False
key = 'space'
while True:
if keypress and not keyboard.is_pressed(key):
'''DO YOUR THING'''
#beak out of while loop?
keypress = False
break
elif keyboard.is_pressed(key) and not keypress:
keypress = True
Dont know if this is how you'll do it, but I guess you can get my drift from this. Good luck!
Related
I want to make it so that the game will print and ask to type a certain letter, and if I don't then I lose
What I want it to be like:
Press E:
(if you don't type it after 5 seconds, you lose. If you DO type it, the game will continue)
Update: I have been told that this is a bad answer, so I decided to improve it, but I left in my old reply for you to still see
Old reply:
Check out the keyboard library, and probably the time library too. I think the easiest way to do this is to create some sort of clock, save a "start time" (what time the prompt came up) and then enter a loop, exiting only when you have either pressed the key, or 5 seconds from the start time has elapsed. Make sure you keep track of which one actually happened.
My updated response, including a code example:
Okay so we're going to be using the time and keyboard libraries.
Note: In order to use most functions in keyboard, you need to run your script on root. You'll have to look up instructions if you're running a different OS, but what I did on my linux machine was just first installing keyboard on root (idk why it needed to be installed seprately but it did) with sudo pip install keyboard, and then running my code as sudo python3 filename.py
.
Our code is going to be running all within a while loop. Here's the basic idea:
play = True
while play:
play = runGame('e')
where runGame() is a func that plays 1 "round" of the game, and returns True if you win, False if you lose.
First, let's look at a way to actually tell if we pressed some desired key (like 'e') We'll be using keyboard.on_press_key() We'll be passing 2 arguments into it, key (what key will trigger it) and callback (a function to call when that key gets pressed) see the docs for more info.
So something like this:
import keyboard
def keyIsPressed(x):
global buttonPress
buttonPress = True
# calls keyIsPressed() when we press targetKey
keyboard.on_press_key(targetKey, keyIsPressed)
i added the unused x argument in the function because on_press_key wants to return some data into the function when you use it. Feel free to print(x) to get a look at what that data is. I just did that as an easy way to deal with an error.
Okay, so let's put everything together finally:
import keyboard
import time
#func called by on_press_key when our targetKey is pressed
def keyIsPressed(x):
global buttonPress
buttonPress = True
def runGame(targetKey):
# variable to tell if we have pressed the targetKey yet
global buttonPress
# always start the round false
buttonPress = False
# calls keyIsPressed() when we press targetKey
keyboard.on_press_key(targetKey, keyIsPressed)
#start time
st = time.time()
while True:
#current time
ct = time.time()
# if 5 seconds or more has passed between start time and current time
if ct >= (st + 5):
print("you took too long!")
return buttonPress #False
#if you have pressed the button
elif buttonPress:
#unhook the key now that you're done with it
keyboard.unhook_key(targetKey)
print("\n\nwow u did it good job!\n\n")
return buttonPress #True
# Run
buttonPress = False
play = True
# you don't have to use a list, but I'm doing so for my prototype
letters = ['e', 'f', 'g']
#the amount of times you've played
loops = 0
while play:
# play the game, use 'e', then 'f', then 'g'
# outside of a prototype, you'll need to update the list or use a different
# method to avoid errors after 3 rounds
play = runGame(letters[loops])
#up loop counter
loops += 1
#remove all key hooks when you are done playing
keyboard.unhook_all()
Hopefully that's comprehensive enough without being too wordy. I really wasn't expecting this to be as difficult as it was, but all of the intuitive solutions that I thought of actually ran into issues either with dropping inputs, or freezing the loop. So this is the simplest implementation I could come up with.
I'm trying to write a small script with Autokey (not regular Python) on Linux Mint which presses a single key and stops after I press another specific key but I can't get it to stop the loop after I press this specific key.
I got the loop working but I can't make it stop.
import time
a = True
b = keyboard.press_key('s')
keyboard.release_key('s')
while a:
keyboard.send_key("a", repeat=5)
time.sleep(2)
if b:
break
So this outputs the letter "a" indefinitely and after I press "s" it doesn't stop and I don't know what I'm doing wrong
I read about the while function and break but all the examples I found were with a loop stopping after it reached a certain number and these examples with numbers are different than what I try to achieve with this kind of script so I hope someone can help me to figure this out.
You will have to use the keyboard module for this, because press_key is used to "press" the keys not to detect.
If you haven't already installed keyboard you can do it by going to cmd,
pip install keyboard
after that you can add the code in python as follows, pressing "q" will print "a" 5 times and pressing "s" will stop the program.
import keyboard
while True:
if keyboard.is_pressed('q'): # pressing q will print a 5 times
for i in range(5):
print("a")
break
elif keyboard.is_pressed('s'): # pressing s will stop the program
break
You can check if a key is pressed with evdev
Check your InputDevice by looking at python -m evdev.evtest
Then to check if the s key is pressed :
import evdev
from evdev import ecodes as e
device = evdev.InputDevice('/dev/input/event7')
if e.KEY_S in device.active_keys():
do_something()
At first glance your problem is that you never update the value of b and it is only assigned before the loop. You should probably try something like this:
import time
a = True
keyboard.release_key('s')
while a:
keyboard.send_key("a", repeat=5)
b = keyboard.press_key('s')
time.sleep(2)
if b:
break
I don't know how "b = keyboard.press_key('s')" affects the code, if it stops it.
I'm using python 3.7 on windows 7.
Is there any way to detect number (for example: "1") key presses in pynput module?
I have tried many other modules and i got nothing except for tkinter
which needs a window but i don't want that.
from pynput import keyboard
def on_press(key):
print(key)
if str(format(key)) == 'Key.1':
print('Exiting...')
return False
with keyboard.Listener(on_press = on_press) as listener:
listener.join()
It actually only prints the pressed key and never brakes(doesn't accept the numeric input).
Your code is testing for the value "1". This is, your pardon for stating the obvious, what pynput returns if you press the 1 key. You want to respond to the NumLock key.
Instead of
if str(format(key)) == '1':
you can code either of these tests, both of which check for the value you are looking for:
if key == keyboard.Key.num_lock:
if str(format(key)) == "Key.num_lock":
But... There are two kinds of NumLock key.
One is Keyboard NumLock and Clear which has both a USB code (0x53) and a Windows virtual key code (0x90). pynput will respond to pressing this key.
The other kind is Keyboard Locking NumLock which works at the keyboard level: it changes the way your keyboard behaves, and Windows doesn't get to hear about it. It has a USB code (0x83), but it doesn't have a Windows virtual key code. If there is no virtual key code for the key, there won't be a Windows message for pressing it, and pynput reports Windows messages.
So the behaviour is hardware-dependent and it may be that your machine has the second kind of NumLock key. If it does, then nothing you can say to pynput will help. This is unlikely, though, unless you are working with a very restricted laptop keyboard.
The code you've provided seems to be trying to detect Numeral key '1' rather than 'Num lock'.
#BoarGules has provided a complete answer. Just to add a bit of clarification:
When you monitor keyboard using pynput, if trying to detect a control key, you should compare it with appropriate pynput.keyboard.Key object. In case of checking for num lock, your code should look like this:
if key == keyboard.Key.num_lock:
print('exiting')
On the other hand, if you're looking for an alpha-numeric key, compare it with pynput.keyboard.KeyCode:
if key == keyboard.KeyCode(char = '1'):
print('exiting')
A quick glance at the doc shows that the num lock key may be undefined on some platforms. I don't have a windows machine to test this on unfortunately.
num_lock = <Key.f1: 0>
The NumLock key. This may be undefined for some platforms.
I've been trying to get keypresses to be detected in a Python program. I want to find a way to do this without using Tkinter, curses, or raw_input. Here's what I'm going at:
while True:
if keypressed==1:
print thekey
Does anyone know how this is possible?
Python has a keyboard module with many features. Install it, perhaps with this command:
pip3 install keyboard
Then use it in code like:
import keyboard #Using module keyboard
while True:#making a loop
try: #used try so that if user pressed other than the given key error will not be shown
if keyboard.is_pressed('a'): #if key 'a' is pressed
print('You Pressed A Key!')
break #finishing the loop
else:
pass
except:
break #if user pressed other than the given key the loop will break
You can set multiple Key Detection:
if keyboard.is_pressed('a') or keyboard.is_pressed('b') or keyboard.is_pressed('c'):
#then do this
I took the liberty of editing your question slightly so it makes sense and has an answer, at least on Windows. (IDLE only interacts with your keyboard by means of the tkinter interface to tk.) On Windows, the answer is to use the msvcrt module's console io functions
import msvcrt as ms
while True:
if ms.kbhit():
print(ms.getch())
For other systems, you will have to find the equivalent system-specific calls. For posix systems, these may be part of curses, which you said you did not to use, but I do not know.
These functions do not work correctly when the program is run is run from IDLE in its default mode. The same may be true for other graphics-mode IDEs.
I'm trying to break a loop in Python with a specific key press using win32api. How would one go about this?
What is the actual version of win32api.KeyPress('H'), in the following code?
Revised:
import win32api
while True :
cp = win32api.GetCursorPos()
print cp
if win32api.KeyPress('H') == True :
break
I want to be able to break a loop by pressing the h key.
Edit:
I'm attempting to make a program that repeatedly reports mouse positions and I need a mechanism to exit said program.
See revised code.
win32api is just an interface to the underlying windows low-level library.
See the GetAsyncKeyState Function:
Determines whether a key is up or down at the time the function is called, and whether the key was pressed after a previous call to GetAsyncKeyState.
Syntax
SHORT WINAPI GetAsyncKeyState(
__in int vKey
);
Return Value
Type: SHORT
If the function succeeds, the return value specifies whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down. If the most significant bit is set, the key is down, and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState.
Note that the return value is bit-encoded (not a boolean).
To get at vKey values, an application can use the virtual-key code constants in the win32con module.
For example, testing the "CAPS LOCK" key:
>>> import win32api
>>> import win32con
>>> win32con.VK_CAPITAL
20
>>> win32api.GetAsyncKeyState(win32con.VK_CAPITAL)
0
>>> win32api.GetAsyncKeyState(win32con.VK_CAPITAL)
1
The virtual-key constant for simple letters are ASCII codes,
so that testing the state of the "H" key (key was pressed) will look like:
>>> win32api.GetAsyncKeyState(ord('H'))
1
This isn't how it works in GUI programming. You don't call a method to check for a key press. Instead you get sent messages when keys are pressed. Assuming that you have a window that is receiving input then you need to respond to the WM_KEYDOWN message arriving in your window procedure, or message map in Python win32api terms.
Your edit shows that you are not using the message queue which is rather unusual. You may be able to achieve what you wish by calling GetAsyncKeyState().
Check the python tiler on github, very useful even if you are trying to just find key codes to send. Also this will be useful if you are running your code in the background and want to break the loop from outside the window.
git project:
https://github.com/Tzbob/python-windows-tiler
code with windows keys:
https://code.google.com/p/python-windows-tiler/source/browse/pwt/hotkey.py?r=df41af2a42b6304047a5f6f1f2903b601b22eb39