Prevent keystrokes - python

It is necessary to make sure that during a certain period of time they are not available for pressing a certain key, for example Space. So that during a break, user clicks are not displayed in any way in the input(). Please suggest a module or a complete solution. Example:
import time
time.sleep(5) # So that during this period of time nothing could be written.
enter = input()

welcome to SO!
Your description is very vague, but assuming you want to prevent a specific keystroke from affecting your program for 5 seconds, this might just work:
import keyboard
import time
time_end = time.time() + 5
while time.time() < time_end:
if keyboard.is_pressed('q'):
pass
replace 'q' with the key you don't want to affect your program. Wherever "pass" is is what will happen if q is pressed within those seconds. I think q will still show up in your program when it's pressed, but wont affect any of your other functions unless you have threading. Sorry if this doesn't help, this is the only thing I could think of.

Related

How to execute an if else statement in while loop without making the while loop stop?

Im trying to make a countdown timer with the feature to reset/stop/pause/resume. I tried implementing an if/elif/else statement to check for user input letter within the while loop while it continues looping. However, the loop stops running when the conditional statement executes. How do I implement my intended functionality into the code?
code:
import time
import datetime
def timeinput():
# Inputs for hours, minutes, seconds on timer
h = input("Enter the time in hours: ")
m = input("Enter the time in minutes: ")
s = input("Enter the time in seconds: ")
countdown(int(h), int(m), int(s))
# Create class that acts as a countdown
def countdown(h, m, s):
# Print options for user to do
print("Press w to reset \nPress s to stop \nPress a to pause \nPress d to resume")
# Calculate the total number of seconds
total_seconds = h * 3600 + m * 60 + s
# While loop that checks if total_seconds reaches zero
# If not zero, decrement total time by one second
while total_seconds > 0:
# Timer represents time left on countdown
timer = datetime.timedelta(seconds = total_seconds)
# Prints the time left on the timer
print(timer, end="\r")
# Delays the program one second
time.sleep(1)
# Reduces total time by one second
total_seconds -= 1
user=input()
if user=="w":
total_seconds=0
print("Timer will now reset")
timeinput()
print("Bzzzt! The countdown is at zero seconds!")
timeinput()
result:
outcome of code
As shown in the provided image, the loop stops at 20 secs. My intended action here was for the countdown to continue until the user presses the W key, which shall then reset the countdown back to its original set time at initialization.
Soo, I'm also kinda new to programming and python so I don't exactly how to make a timer with that functionality. What is happening is that when you use the input() function the code stops and waits for the user input.
I know you can use some libraries, like pygame, in order to check for user input inside the loop without stopping it, but without one I'm not sure how to do it.
You can also use the module keyboard, that comes inside python, and I think is great for the problem you shared. Check this post How to detect key presses?
The command input() is blocking. It waits until it get something from the console. Maybe take a look at this post and try to implement a non blocking version of input. Non-blocking console input?
The problem is that input is blocking - that is, it will stop the execution until the user presses < enter> .
Antique running environments, on 8 bit computers, using Basic, could check "what the user is pressing right now", without waiting for a confirmation with "enter" using the inkey command.
In Python programs running on terminal, terminedia, a 3rdy party library, implements inkey() as it was - but it needs the terminal input to be reconfigured for which it provides a "keyboard" context manager.
You can then run almost the same code you have -just install terminedia in your Python environment with "pip install terminedia"
import terminedia as TM
...
def countdown(h, m, s):
...
while total_seconds > 0:
# Timer represents time left on countdown
timer = datetime.timedelta(seconds = total_seconds)
# Prints the time left on the timer
print(timer, end="\r")
with TM.keyboard:
# Delays the program one second
time.sleep(1)
# Reduces total time by one second
total_seconds -= 1
user=TM.inkey()
if user=="w":
total_seconds=0
print("Timer will now reset")
timeinput()
print("Bzzzt! The countdown is at zero seconds!")
timeinput()
(disclaimer: I am terminedia author)
Taking inputs from the answers received here and subsequent follow-up questions on stack overflow and Reddit, this question has been solved using pygame. I'll provide the link below for future reference to this question.
problem solution

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(),
})

Ignore keyboard input in python while sleeping

I'm having a code with a loop asking for some input and then sleeps for some time. The purpose is to prevent for human errors, forcing the user to wait before entering the next input.
The problem is, that python does not ignore the keyboard inputs while time.sleep.
Here is an example code:
from time import sleep
from msvcrt import getch
for i in range(3):
print 'Enter a character'
char = getch()
sleep(2)
print char
When pressing some characters consecutively during time.sleep(), msvcrt.getch() remembers them and the loop runs to the end. I want that every character pressed during sleep will be ignored. How can I do that?
Sorry for wrong answer that i have posted before(as i have deleted though), it is the human level problem that you are asking for.
The program thread is the only event that is put on to sleep, while the keyboard process is still running obviously it will record all the inputs and type after resuming from sleep.
This can't be achieved in this fashion
This is an OS dependant issue, for windows i use this:
import msvcrt
import time
time.sleep(4)
while msvcrt.kbhit():
flush = input()
entry = input("Press enter!")
it just catches all the inputs before asking user for a new input, hope it helps!

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.

Categories