I am trying to create a tkinter app that checks if two keys are pressed consecutively. For example, if the user presses ":" and then the enter key right after. Is there a way to do this using key events in tkinter?
I have tried doing the following, but it does not work.
if key_pressed == ':':
if key_pressed == '<Enter>':
print("ok")
One way is to save a state for each keypress which stores the last key pressed:
from tkinter import *
root = Tk()
last_key = None
def keypress_handler(event):
global last_key
key_pressed = event.keysym
print(key_pressed)
if key_pressed == 'b':
if last_key == 'a':
print('Pressed first "a" and then "b"')
last_key = key_pressed
root.bind('<KeyPress>', keypress_handler)
root.mainloop()
If you are going to use modifiers like shift, ctrl or alt you'll have to filter them out because they also generate keypress events.
Related
I've used the keyboard module in python to identify a keypress event as shown below.
import keyboard
while True:
if keyboard.read_key() == "k":
print("You pressed k")
break
Now I have 2 keyboards and I want to identify the keyboard used to press the key (Something like below).
import keyboard
while True:
if 'k' of keyboard 1 pressed:
print("You pressed k of keyboard 1")
break
if 'k' of keyboard 2 is pressed:
print("You pressed k of keyboard 2")
break
Can I do this with the keyboard module? If not is there any other way to do this in python?
I am new to python and I found a code that detects mouse buttons when held down and released, but i want "x" to turn True when both of the buttons held down, how can I do this
# This function will be called when any key of mouse is pressed
def on_click(*args):
# see what argument is passed.
print(args)
if args[-1]:
# Do something when the mouse key is pressed.
print('The "{}" mouse key has held down'.format(args[-2].name))
elif not args[-1]:
# Do something when the mouse key is released.
print('The "{}" mouse key is released'.format(args[-2].name))
# Open Listener for mouse key presses
with Listener(on_click=on_click) as listener:
# Listen to the mouse key presses
listener.join()
To detect if both buttons are held down simultaneously, three variables will be required (initialise these at the start of your program, outside of the on_click function):
global leftPressed, rightPressed, bothPressed
leftPressed = False
rightPressed = False
bothPressed = False
*note the variables are global here, as multiple versions of on_click will be accessing and modifying the variables
Then, in the first if statement (when a mouse button has been pressed):
if args[-2].name == "left":
leftPressed = True
elif args[-2].name == "right":
rightPressed = True
if leftPressed and rightPressed:
# if both left and right are pressed
bothPressed = True
And in the second if statement (when a mouse button has been released)
if args[-2].name == "left":
leftPressed = False
elif args[-2].name == "right":
rightPressed = False
# as one key has been released, both are no longer pressed
bothPressed = False
print(bothPressed)
Finally, to access the global variables from within the function on_click, place this line at the start of the function:
global leftPressed, rightPressed, bothPressed
See a full version of the code here:
https://pastebin.com/nv9ddqMM
I am trying to convert from pygame to tkinter as it seems to be much better for what I want to do, although I have hit a bit of a wall. I need to be able to call a function when both a certain key and mouse button are pressed. In pygame it was as simple as the following.
while not done:
for event in pygame.event.get():
keys = pygame.key.get_pressed()
mouse = pygame.mouse.get_pressed()
if event.type == pygame.QUIT:
done = True
if mouse[0]:
if keys[pygame.K_s]:
pos = pygame.mouse.get_pos()
// function
I know in tkinter you can do c.bind("<Button-1>", function) to register mouse clicks and c.bind("e", function) to register key presses but I'm not sure how to get both at the same time as the button event does not pass through key presses
Not sure if there is an official method to bind both Button-1 and Key, but maybe you can work around it.
import tkinter as tk
root = tk.Tk()
tk.Label(root,text="Hi I'm a label").pack()
class Bindings:
def __init__(self):
self.but_1 = False
root.bind("<Button-1>", self.mouse_clicked)
root.bind("<e>", self.e_clicked)
root.bind("<ButtonRelease-1>",self.mouse_release)
def mouse_release(self,event):
self.but_1 = False
def mouse_clicked(self,event):
self.but_1 = True
print ("Mouse button 1 clicked")
def e_clicked(self,event):
if self.but_1:
print ("Both keys clicked")
self.but_1 = False
else:
print ("Key E pressed")
Bindings()
root.mainloop()
I am controlling a remote toy car using python code. As of now, the code is as below:
def getkey():
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
new = termios.tcgetattr(fd)
new[3] = new[3] & ~TERMIOS.ICANON & ~TERMIOS.ECHO
new[6][TERMIOS.VMIN] = 1
new[6][TERMIOS.VTIME] = 0
termios.tcsetattr(fd, TERMIOS.TCSANOW, new)
c = None
try:
c = os.read(fd, 1)
finally:
termios.tcsetattr(fd, TERMIOS.TCSAFLUSH, old)
return c
def car():
while True:
key = getkey()
if key == 's': #Down arrow
print "Down"
Backward()
elif key == 'w': #Up arrow
print "Up"
forward()
elif key == 'a':
print "left"
Left()
elif key == 'd':
print "Right"
Right()
elif key == 'q': #Quit
print "That's It"
break
def forward():
GPIO.output(11,True) #Move forward
When I press 'w' forward() method is called and the car moves forward but wont stop until I quit the program or call GPIO.output(11, False) from some other method.
Is there any key Listener which detects the key release of any particular key?
For example, if 'w' pressed called this method and if released call some other method
Sudo code:
if w_isPressed()
forward()
else if w_isReleased()
stop()
I've seen Pygame game development library being successfully used in similar scenarios before, handling realtime systems and machinery in production, not just toy examples. I think it's a suitable candidate here too. Check out pygame.key module for what is possible to do with the keyboard input.
In short, if you are not familiar with game development, you basically continuously poll for events such as input state changes inside an 'infinite' game loop and react accordingly. Usually update the parameters of the system using deltas per time elapsed. There's plenty of tutorials on that and Pygame available around and Pygame docs are pretty solid.
A simple example of how to go about it:
import pygame
pygame.init()
# to spam the pygame.KEYDOWN event every 100ms while key being pressed
pygame.key.set_repeat(100, 100)
while 1:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
print 'go forward'
if event.key == pygame.K_s:
print 'go backward'
if event.type == pygame.KEYUP:
print 'stop'
You'll need to play with pygame.KEYDOWN, pygame.KEYUP and pygame.key.set_repeat depending on how your car movement is implemented.
Faced a similar problem (I am no Python expert) but this worked for me
import pynput
from pynput import keyboard
def on_press(key):
try:
print('Key {0} pressed'.format(key.char))
#Add your code to drive motor
except AttributeError:
print('Key {0} pressed'.format(key))
#Add Code
def on_release(key):
print('{0} released'.format(key))
#Add your code to stop motor
if key == keyboard.Key.esc:
# Stop listener
# Stop the Robot Code
return False
# Collect events until released
with keyboard.Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
I'm currently working on project where I ssh to a raspberry pi from my laptop to control some motors. I have written some code in Python that allows you to enter a letter and depending on the letter it moves forwards or backwards. However you have to press enter after every letter for the code to execute.
Is there a way that the interface detects letters without the need to press enter.
I know you can bind key presses in tkinter but I can not do that through ssh.
Thanks in advance
You could use the curses library for that.
You can grab the key that was pressed using the screen.getch() function. It will return the decimal code of the key (see ASCII Table).
An example:
import curses
screen = curses.initscr()
curses.cbreak()
screen.keypad(1)
key = ''
while key != ord('q'): # press <Q> to exit the program
key = screen.getch() # get the key
screen.addch(0, 0, key) # display it on the screen
screen.refresh()
# the same, but for <Up> and <Down> keys:
if key == curses.KEY_UP:
screen.addstr(0, 0, "Up")
elif key == curses.KEY_DOWN:
screen.addstr(0, 0, "Down")
curses.endwin()
Another option is sshkeyboard library. Simply pip install sshkeyboard, and then use the following code to detect key presses over SSH:
from sshkeyboard import listen_keyboard
def press(key):
print(f"'{key}' pressed")
def release(key):
print(f"'{key}' released")
listen_keyboard(
on_press=press,
on_release=release,
)
Inside def press you could have some logic to react to specific keys:
def press(key):
if key == "up":
print("up pressed")
elif key == "down":
print("down pressed")
elif key == "left":
print("left pressed")
elif key == "right":
print("right pressed")