keyboard.read_key() records 2 events - python

I'm trying something:
When I press a key, I want a counter to increase and add the current timestamp
problem is: I get 2 events for whenever I press a key, any idea?
import keyboard
from datetime import datetime
running = True
counter = 0
while running:
input = keyboard.read_key()
if input== "esc":
print (counter)
running = False
else:
counter += 1
dateTimeObj = datetime.now()
print(counter,dateTimeObj)

It is probably registering both key down and key up. You can use an auxiliary variable to only register it once:
import keyboard
from datetime import datetime
running = True
counter = 0
not_pressed = True
while running:
input = keyboard.read_key(suppress = True)
if input== "esc":
print (counter)
running = False
else:
if not_pressed:
counter += 1
dateTimeObj = datetime.now()
print(counter,dateTimeObj)
not_pressed = False
else:
not_pressed = True

maybe your program is registering events when you are pressing the key and when you
releasing the key?
maybe the keyboard.record() will help you
# Record events until 'esc' is pressed.
recorded = keyboard.record(until='esc')
here is the description to keyboard module

Related

Detect a key pressed within a while Python

I want to detect a key pressed in python without using "with", because I want it to show a text in a while
all this with the pynput library:
import time
from pynput import keyboard
i = 0
while True:
if event.key == keyboard.Key.esc:
break
else:
if a == "hello":
print("y")
else:
print("n")
if i % 2 = 0:
a = "hello"
else
a = "good bye"
i += 1
print(a)
time.sleep(2)
pynput's Events blocks by default. You can .get to limit how long it blocks for:
from pynput import keyboard
import time
i = 0
a = "start"
while True:
if a == "hello":
print("y")
else:
print("n")
if i % 2 == 0:
a = "hello"
else:
a = "good bye"
i += 1
print(a)
# Not needed anymore, we're going to block waiting for key events for 2 seconds
# time.sleep(2)
with keyboard.Events() as events:
# Block at most for two seconds
event = events.get(2.0)
if event is not None:
if event.key == keyboard.Key.esc:
break
This won't necessarily always block for two seconds if the user presses some other key. You can either add code to check for that condition and keep calling events.get till enough time has passed, or use keyboard.Listener to react to events in real time.

How to use Esc to stop a while loop?

How do I break this loop with a keystroke such as Esc ? This example captures the keystroke but never passes the variable into the while loop.
from pynput import keyboard
count = 0
stop = 0
while True:
def press_callback(key):
if key == keyboard.Key.esc:
def stop_loop():
stop = 1
return stop
print('You pressed "escape"! You must want to quit really badly...')
stop = stop_loop()
return stop
count +=1
print (count)
if stop == 1:
break
if count == 1:
l = keyboard.Listener(on_press=press_callback)
l.start()
I'm using Ubuntu 18.04.
Update your stop_loop method like this:
def stop_loop():
global stop
stop = 1
return stop
If you don't declare global stop then instead of updating stop variable you defined at the beginning of the file you'll create a new local stop variable inside stop_loop method.
Probably read this for better understanding: https://realpython.com/python-scope-legb-rule/
Here is the final working solution:
from pynput import keyboard
count = 0
stop = 0
def press_callback(key):
if key == keyboard.Key.esc:
def stop_loop():
global stop
stop = 1
return stop
print('Get Out')
stop = stop_loop()
return stop
l = keyboard.Listener(on_press=press_callback)
l.start()
while True:
count += 1
print (count)
if stop == 1:
break

How to get count of keys pressed on the keyboard in an minute? ( using python )

Actually I am trying to build a monitoring system that returns the total count of keystrokes made by the keyboard in a minute. The output should be an integer that holds the value of the number of keystrokes by a person in a minute? ( in python )
This should kinda do the trick... It's not the most efficient / precise but I believe it works.
import sys
import tty
import time
# Disable newline buffering on stdin
tty.setcbreak(sys.stdin.fileno())
seconds = 60
keys = []
while x := sys.stdin.read(1):
now = time.time()
keys.append((now, x))
# Filter out old keys
keys = [(timestamp, key) for timestamp, key in keys if timestamp > now - seconds]
if keys:
# Calculate how many seconds our current list spans
timestamps = [timestamp for timestamp, _key in keys]
total = max(timestamps) - min(timestamps)
# Wait until at-least 1 second passed before showing results
if total > 1:
keys_per_second = len(keys) / total
print(keys_per_second * seconds)
Or a Python<3.8 friendly version:
import sys
import tty
import time
# Disable newline buffering on stdin
tty.setcbreak(sys.stdin.fileno())
seconds = 60
keys = []
x = sys.stdin.read(1)
while x:
now = time.time()
keys.append((now, x))
# Filter out old keys
keys = [(timestamp, key) for timestamp, key in keys if timestamp > now - seconds]
if keys:
# Calculate how many seconds our current list spans
timestamps = [timestamp for timestamp, _key in keys]
total = max(timestamps) - min(timestamps)
# Wait until at-least 1 second passed before showing results
if total > 1:
keys_per_second = len(keys) / total
print(keys_per_second * seconds)
x = sys.stdin.read(1)
you can use pygame library to track the count of any specific key
import pygame
count = 0
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
count = count + 1
you can also use simple way
import msvcrt
count = 0
while True:
s = msvcrt.getch()
if(s == 'q'):
break
else:
count = count + 1
print(count)
This will keep on counting you keystrokes until you press 'q'
from pynput import keyboard
c=0
with keyboard.Events() as events:
for event in events:
if event.key == keyboard.Key.esc:
break
elif (str(event)) == "Press(key='1')":
c+=1
print(c)
Use any keys inside "Press(key='1')" like "Press(key='2')", "Press(key='t')", to get counts

Unused variable in Python

This is my first time to create a python program to take screenshot every two seconds. The problem is that I don't know how to break the while loop. I wrote while sscount is not zero, keep screenshotting. Then when a user press ESC button, set sscount to 0. This should stop the while loop but I get the warning, "Unused variable 'sscount'" and it doesn't stop the while loop either.
Could anyone help me? Thanks.
import pynput
import pyautogui
import time
from pynput.keyboard import Key, Listener
count = 0
def on_release(key):
if key == Key.esc:
sscount = 0 #this is where the warning comes.
return False
with Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
while sscount != 0:
pyautogui.screenshot('/users/aliha/desktop/screenshot/image'+str(sscount)+'.png')
sscount += 1
time.sleep(2.0)
Below a snippet code to enhance.
The main program run while is_running is True
ctrl+c event set is_running to False
screenshot is took if the elasped time is upper than 2 sec between 2 <escape> key pressed
output path is not hardcoded
global variable is used to share state
import time
from os.path import expanduser
from pathlib import Path
import datetime
from pynput.keyboard import Key, Listener, Controller
keyboard = Controller()
is_running = True
sscount = 0
previous_date = None
screenshot_dir = None
def on_press(key: Key):
global previous_date, sscount
have_to_take_screenshot = False
current_date = datetime.datetime.now()
if previous_date is None:
previous_date = current_date
have_to_take_screenshot = True
else:
elapsed_time = current_date - previous_date
if elapsed_time > datetime.timedelta(seconds=2):
previous_date = current_date
have_to_take_screenshot = True
else:
have_to_take_screenshot = False
print(have_to_take_screenshot)
if have_to_take_screenshot and key == Key.esc:
pyautogui.screenshot(f'{screenshot_dir}/image{sscount}.png')
sscount+= 1
def on_release(key: Key):
global screenshot_dir
should_continue = True
print(key)
if key == Key.esc:
is_running = False
should_continue = False
return should_continue
if __name__ == '__main__':
home_dir = expanduser('~/')
screenshot_dir = Path(f'{home_dir}/desktop/screenshot')
if not screenshot_dir.exists():
screenshot_dir.mkdir(parents=True, exist_ok=True)
while is_running:
try:
with Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
except KeyboardInterrupt:
is_running = False
In order to be able to use variable sscount globally and to manipulate the global variable within function on_release , you have to declare sscount as global variable in the function using global sscount. Complete result:
def on_release(key):
global sscount
if key == Key.esc:
sscount = 0 #this is where the warning comes.
return False
One way to fix this is to raise a StopIteration and make the loop infinite.
import pynput
import pyautogui
import time
from pynput.keyboard import Key, Listener
def on_release(key):
if key == Key.esc:
raise StopIteration
with Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
while True:
pyautogui.screenshot('/users/aliha/desktop/screenshot/image'+str(sscount)+'.png')
time.sleep(2.0)

Increase just by one when a key is pressed

I want to increase the variable "shot_pressed" just by one when the key "s" is pressed no matter how long I pressed. But the result is that the variable keeps on increasing. The longer I pressed, the bigger the value of the variable. Below is a part of my code.
import keyboard
shot_pressed = 0
if keyboard.is_pressed('s'):
shot_pressed += 1
First of all looks like you use https://pypi.python.org/pypi/keyboard
Second, I assume your code is not like you wrote above but like
import keyboard
shot_pressed = 0
while True:
if keyboard.is_pressed('s'):
shot_pressed += 1
print("shot_pressed %d times"%shot_pressed)
If yes, here is the core of the problem: is_pressed will be always True, while key is pressed. So if condition will be True and while will repeat it many times.
There are two ways of dealing with that.
1) Use the same method, but check if this is the first is_pressed moment, so inroduce was_pressed variable:
import keyboard
shot_pressed = 0
was_pressed = False
while True:
if keyboard.is_pressed('s'):
if not was_pressed:
shot_pressed += 1
print("shot_pressed %d times"%shot_pressed)
was_pressed = True
else:
was_pressed = False
2) Better use the library. You can set a hook, so on key pressed your function will be called (only once for one press). So the code will look like this:
import keyboard
shot_pressed = 0
def on_press_reaction(event):
global shot_pressed
if event.name == 's':
shot_pressed += 1
print("shot_pressed %d times"%shot_pressed)
keyboard.on_press(on_press_reaction)
while True:
pass
I do not know that keyboard module but the problem with your code is that the program takes input once. Your program should wait next input from keyboard. Try to use while loop to take inputs from user.
import keyboard
import time
shot_pressed = 0
try:
while True:
if keyboard.is_pressed("S"):
shot_pressed += 1
time.sleep(0.1)
print(sh)
except Exception as er:
pass
Or can use read key
try:
shot_pressed = 0
while True:
key.read_key()
if key.is_pressed("s"):
sh += 1
print(shot_pressed)
except Exception as er:
pass
I haven't used that module, but you probably want the same thing that you would want in javascript. keyboard.KEY_DOWN instead of is_pressed.
https://github.com/boppreh/keyboard#keyboard.KEY_DOWN
You probably need to handle things asynchronously as well.

Categories