Stop keyboard.record() function at any keypress in Python - python

I found this keyboard module in Python which is used to log keyboard events (from what I got, mainly) using keyboard.record(), which takes in a string as a parameter, indicating at which keypress the function should stop.
So my question is.. is there any way to make the function stop at any keypress? As far as I know the module has no special keyword which would indicate such a thing.
Like I tried doing this
keys_pressed = keyboard.record(until='any')
But that's causing an error.

I don't see the point to using keyboard.record() if all you need it for is to stop at (and record) only the first keypress.
Instead, you could use keyboard.read_key() like this:
import keyboard
k = keyboard.read_key() # in my python interpreter, this captures "enter up"
k = keyboard.read_key() # so repeat the line if in the python interpreter

After digging around in the source code, it looks like this is not possible.
def record(until='escape'):
"""
Records all keyboard events from all keyboards until the user presses the
given key combination. Then returns the list of events recorded, of type
`keyboard.KeyboardEvent`. Pairs well with
`play(events)`.
Note: this is a blocking function.
Note: for more details on the keyboard hook and events see `hook`.
"""
recorded = []
hook(recorded.append)
wait(until)
unhook(recorded.append)
return recorded
The parameter until is passed into wait(). Thus, wait() must have code to handle an arbitrary key press, which it does not.
def wait(combination=None):
"""
Blocks the program execution until the given key combination is pressed or,
if given no parameters, blocks forever.
"""
wait, unlock = _make_wait_and_unlock()
if combination is not None:
hotkey_handler = add_hotkey(combination, unlock)
wait()
remove_hotkey(hotkey_handler)
Ultimately, there is no source code built to handle something like keyboard.record(until='any'), so you'll have to find a workaround. Consider checking How do I make python to wait for a pressed key. However, if you need to record the arbitrary key you would have used to stop the recording, then use J-L's workaround:
import keyboard
k = keyboard.read_key() # in my python interpreter, this captures "enter up"
k = keyboard.read_key() # so repeat the line if in the python interpreter

You can make a function that sets a hook for all keys.
import keyboard
def record_until(any_key=False):
recorded = []
keyboard.hook(recorded.append) # need this to capture terminator
wait, unlock = keyboard._make_wait_and_unlock()
if any_key:
hook = keyboard.hook(unlock)
wait()
try:
keyboard.remove_hotkey(hook)
except ValueError: pass
return recorded
record_until(any_key=True)

Related

How to use Python keyboard module to persistently detect input?

I'm trying to write a script so that when I press "0" I will get an output, but I want to work without restarting the script, and I haven't been successful using the keyboard module which I've seen as being the most commonly used for detecting key inputs in Python.
What I have so far is
import keyboard
def goto(linenum):
global line
line = linenum
line = 1
if line == 1:
while True:
if keyboard.is_pressed('0'):
print('pressed 0')
break
goto(1)
What I tried doing was after the loop breaks to refer back to the beginning of the loop and try again from there, however the script ends after I press 0. If I remove the break then it constantly outputs "pressed 0", which is not what I want to happen.
You can use pynput to detect key input.
I would do something like this:
from pynput.keyboard import Key, Listener
def on_press(key):
if str(key).replace("'","") == '0':
print('pressed 0')
listener = Listener(on_press=on_press)
listener.start()
Once you start the listener, it will be always waiting for the key press and you can still add code after. In fact, with this example I recommend to add something after, maybe an input() so the script won't close immediately.
I think there are a few problems going on here.
goto is a pretty bad pattern to use and I don't think there's anything here to make your implementation work. It kinda sounds like you're going for some kind of recursion like approach here where when 0 is pressed, then it does some 'reset' and starts looping again. If that is the case you could do something like this:
def wait_for_zero():
# wait for press here
# Should add some sort of exit check too
# 'reset' logic, if any here
wait_for_zero()
looping with a weak condition is pretty fast cycling and generally a bad idea without some time delay. This is mentioned in the documentation for keybaord. There also is an example in the documentation for keyboard to wait for a keypress: https://github.com/boppreh/keyboard#waiting-for-a-key-press-one-time

Python pynput.keyboard.write() sending text repeatedly the same text and unrequested part of text

I'm trying to make some mapped.HotKeys to transfer some text.
Using pynput, I made a function to transfer raw text and another to transfer just numbers.
Whith pynput.keyboard.GlobalHotKeys, I've mapped 'ctrl+alt+1' for te first and 'shift+ctrl+alt+1' for the second.
Using the first shortcut, a "¹" caractere is printed before the sequence wanted (like normal use of these keys).
Using the second, the first text, folowed by the second (only digits), is printed repeatedly (as more the keys are manteined pressed, more times the text is printed).
Ex.: the string '45.785.422/0001-25'
ctrl+alt+1 results - ¹45.785.422/0001-25
shift+ctrl+alt+1 results - 45.785.422/0001-25457854220001254578542200012545785422000125457854220001254578542200012545.785.422/000...
The code:
from pynput import keyboard as kbd
import keyboard
from pynput.keyboard import Key, Controller
import re
txt_base = '45.785.422/0001-25'
# keyboard = Controller()
def send_text():
keyboard.write(txt_base)
def clean_text():
txt_array = re.findall(r'\d+', txt_base)
txt_cln = ''.join(txt_array)
keyboard.write(txt_cln)
hotkeys = kbd.GlobalHotKeys({
'<ctrl>+<alt>+1': send_text(),
'<ctrl>+<shift>+<alt>+1': clean_text(),
})
with hotkeys:
hotkeys.join()
Somebody can help me with these issue? Tks
Apparently, maybe the program get's confused that you press combination 1 all the time. I had similar problem and in my case, it happened because my key combination was containing keys, that I write at the same time with keyboard.write().
In your case, maybe the program bugs, because you press ctrl+alt+1 but you also write 45.785.422/0001-25, which contains 1. So since you hold ctrl+alt for a little and print something with 1 in it, you make the bot think that you hold ctrl+alt and spam 1 and so the keyboard.write() repeats.
As far as I know, unfortunately pnput can't distinguish user from PC when typing keys.
There are workarounds though.
One way is, you can change the shortcut to something that can't appear in the thing you are writing with keyboard
The other way around can be to replace send_text() with a delay that waits for you to release the hotkeys
Something like this:
def send_text():
keyboard.write(txt_base)
def run_send_text():
time.sleep(0.5) # time it takes for a regular person to release the keys
send_text()
hotkeys = kbd.GlobalHotKeys({
'<ctrl>+<alt>+1': run_send_text(), # this time runs after 0.5 seconds
'<ctrl>+<shift>+<alt>+1': clean_text(),
})

How do I use this callback in Python?

Please mind that I am completely green in Python and I do not know how callbacks work in this language.
I have been trying for some time to solve my problem, but I cannot figure out what to do.
I have the problem with using callbacks in Python. I use the Python keyboard module to listen to keys pressed on a machine.
When I try to use the keyboard.hook() method, it asks me for a callback. I know how callbacks work, but as long as Python is not my main language I can't really figure out what to do with it.
In JavaScript it's as easy as naming a parameter in a function then printing that parameter. Easy as that.
import keyboard
keyboard.hook()
## How to print keys?
In the official documentation, it is written that the hook() method invokes a callback. How do I access this callback and most importantly print keys which are recorded from it? I just need a simple example then I will be able to remember it forever.
Any help really appreciated.
You can pass a function just like you would a variable—by passing its name to the hook() method.
Then, per the docs on keyboard.hook(), it calls your callback with a keyboard.KeyboardEvent with three fields:
name: an Unicode representation of the character (e.g. "&") or description (e.g. "space"). The name is always lower-case.
scan_code: number representing the physical key, e.g. 55.
time: timestamp of the time the event occurred, with as much precision as given by the OS.
So, putting it together, you can use it like this:
import keyboard
def my_keyboard_hook(keyboard_event):
print("Name:", keyboard_event.name)
print("Scan code:", keyboard_event.scan_code)
print("Time:", keyboard_event.time)
keyboard.hook(my_keyboard_hook)
# Block forever, so that the program won't automatically finish,
# preventing you from typing and seeing the printed output
keyboard.wait()
And each time a key is pressed, you'll print the details of the keyboard event.
Note that the keyboard.wait() call is not necessary if your program would otherwise continue running—I just wanted to make sure that you didn't run the example code, see it terminate immediately, and then think something went wrong.
Something like this appears to be what you want from the documentation.
def keyHook(info):
print(info)
keyboard.hook(keyHook)

Python: detect specific key press and prompt the user

I need to print out sentence "Hello World" every 10 seconds. However, if the user either 'c' or 'Enter', the program should stop printing the sentence and prompt the user to provide with the another sentence. The user-provided sentence is checked and if the sentence contains any digits, a message shows up: "cannot contain digits". Otherwise a message shows up: "correct sentence". After displaying either of the messages, the program continues printing "Hello World".
Here is the code I have strated with. Any hints on how to continue further would be greatly appreciated.
Thanks!
import threading
def looping():
threading.Timer(10.0, looping).start()
print("Hello World!")
looping()
From my understanding of your assignment's instructions, it looks like you're on the right track with using a timer to print "Hello World"! I'd like to upvote Irmen de Jong's comment on your question with regard to the statement "threads and console input/output don't work nicely together", since I've experienced this myself in C programming.
Once you have the timer going, the text it prints to the screen shouldn't have an effect on responding to keyboard input. If it's really required to respond directly to a keypress of 'c' (not followed by 'Enter', as one would normally have to do when reading input from the keyboard with input()), I recommend following one of the solutions in Python method for reading keypress? to figure out how you would like to implement that.
EDIT: Implementing a solution using a thread-based timer is a bit more tricky than I thought.
As you may have found in your research on this problem, the threading.Timer object has both start() and stop() methods that you can use to control the execution of individual thread timers if you've saved a reference to the timer in a variable (e.g. doing my_timer = threading.Timer(10.0, looping) then calling my_timer.start() to start the timer). If you do this, you may be able to call my_timer.stop() to pause the looping, provided you've kept a proper reference to the current timer instance that you need to stop at that point in time.
To make things a bit easier, I chose to create a global variable PAUSE_LOOPING that, when set to False, will stop a new timer instance from being started when looping is called, thereby halting all further repetitions of the function until PAUSE_LOOPING is set back to True and looping() is called again:
import threading
from msvcrt import getch
PAUSE_LOOPING = False
def looping():
global PAUSE_LOOPING
if not PAUSE_LOOPING:
threading.Timer(10.0, looping).start()
print("Hello World!")
looping()
while True:
# key = ord(getch())
# if key == 13: # Enter
# PAUSE_LOOPING = True
input_string = input()
if input_string == "":
PAUSE_LOOPING = True
else:
PAUSE_LOOPING = False
looping()
Commented out in the last code block is one way to grab a key press directly (without needing to press the 'Enter' key as is required by input()) taken from the stackoverflow question I linked to earlier in my answer. This should work as long as you're using Python for Windows (so you have the MS VC++ runtime library msvcrt installed), but to make the script stop when pressing 'Enter' you can use the standard input() function. In my example, typing any other string of characters before pressing 'Enter' will resume looping after it's been paused.
NOTE: Beware of using Python's IDLE to run this code. It won't work. Instead, you must run it from the command line.

Python - detect keypress in shell

Trying to detect and respond to key presses in Python. Am using IDLE and Python 3.3. I have the following code so far
import msvcrt
while True:
inp = ord(msvcrt.getch())
if (inp != 255):
print(inp)
I have the IF statement because if I just allow the script to throw out the value of 'inp' it just spoons out 255 repeatedly. So I threw in the if statement to respond to anything but 255 and now when run the code does nothing but output the actual keypress character in the shell.
This is because getch reads the input immediately, it doesn't wait until you type something. When it doesn't receive any input, it will simply return "\xff" (ordinal 255).
The getch function is designed to work in a console, not in a graphical program.
When you use it in a graphical program it is going to return immediately with \xff.
If you run your program in the reguler python interpreter it will not cause you that problem.
In addition, when you run the loop with the if statement it is running continuously and using a lot more processor time then it needs. In windows the only proper way of doing so is using window messages which sounds like it is overkill for your needs.
Python has a keyboard module with many features. You Can Use It In Both Shell and Console. It Also Detect Key For The Whole Windows.
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 it to multiple Key Detection:
if keyboard.is_pressed('a') or keyboard.is_pressed('b') or keyboard.is_pressed('c'): # and so on
#then do this
When You Install The Module, got to folder:
python36-32/Lib/site-packages/keyboard
Open File_keyboard_event.py in notepad++.
There will be keyboard events.
Not Sure About All Of Them.
Thanks.

Categories