The bounty expires in 6 days. Answers to this question are eligible for a +50 reputation bounty.
Thingamabobs wants to draw more attention to this question:
It seems like the issue is related to the manufacture hp. I would like to have an answer that explains the issue a little bit more, even though I think it is not really solvable.
I tried to track the control-key when pressed and released.
While everything seemed fine in the beginning a curious thing happened.
When scrolling with my touch-pad on my HP laptop on Windows 11 the KeyPress event is fired automatically.
While I used to search the C-code I didn't found a hint, but I might not fell into the right file. Is this a Windows thing and is normal behavior or is it a bug in tkinter?
My test-code:
import tkinter as tk
ctrl_pressed = None
def check_ctrl(event):
print(ctrl_pressed, 'checked')
def track_ctrl(event):
global ctrl_pressed
if (et:=event.type.name) == 'KeyPress':
ctrl_pressed = True
elif et == 'KeyRelease':
ctrl_pressed = False
print(ctrl_pressed, 'tracked')
root = tk.Tk()
root.bind('<MouseWheel>', check_ctrl)
root.bind('<KeyPress-Control_L>', track_ctrl)
root.bind('<KeyRelease-Control_L>', track_ctrl)
root.mainloop()
Using the MouseWheel first will output None - as expected
Using the Touchpad first will output True - unexpected
Pressing the Key will output first True then False - as expected
Seems to be an generated event:
def track_ctrl(event):
print(event.send_event)
produces True with touchpad.
patchlevel of tkinter 8.6.12
python version 3.11.0
Related
In my CS class, my students just finished their first "clone your classic" contest. The PONG team went rapidly through the "Hey my paddle is frozen" issue with their two players on one keyboard version. I came across this problem 5 years ago and found Python bind - allow multiple keys to be pressed simultaniously that enlightened me (watch out ! The article uses python2.7). But I didn't realize then that the script only worked on windows machines.
On a linux system, the <KeyRelease-a> event triggers the callback, but the event.char then points to ' ' and not 'a' as one could expect. I tried googling the issue, but even on stackoverflow I couldn't find anything of interest.
Any hints? Next find the reproducible code sample:
import os
from tkinter import *
os.system("xset r off")
def keyup(e):
#print(f"up {e.char}")
print(f"up {e.keysym}")
def keydown(e):
#print(f"down {e.char}")
print(f"down {e.keysym}")
root = Tk()
frame = Frame(root, width=100, height=100)
frame.bind("<KeyPress>", keydown)
frame.bind("<KeyRelease>", keyup)
frame.pack()
frame.focus_set()
root.mainloop()
os.system("xset r on")
for reproducibility as asked by Bryan, which I thank for his concern about my question.
Just to close the subject, all the job has been done by Atlas435 : if you want to code a Pong with Tkinter, with two paddles listening independently to the keystrokes, follow this post Python bind - allow multiple keys to be pressed simultaniously but change e.char into e.keysym in the callbacks to get which key triggered the event Pressed or Released.
When playing with sdl2 via pysdl2 I noticed this strange side-effect where once the sdl script runs unrelated windows which would normally become translucent when moved do now stay opaque.
I wouldn't mind all that much if it weren't for the nagging feeling
that this indicates that I'm doing something fundamentally wrong.
Anyone able to enlighten me as to what the heck is going on here?
Here is my script:
import sdl2
import sdl2.ext as se
import time
def main():
k = 2
event_buffer = (k * sdl2.SDL_Event)()
se.init()
window = se.Window("what the ?", size=(400, 300))
window.show()
while True:
window.refresh()
time.sleep(0.01)
sdl2.SDL_PumpEvents()
sdl2.SDL_PeepEvents(event_buffer, k, sdl2.SDL_GETEVENT,
sdl2.SDL_FIRSTEVENT, sdl2.SDL_LASTEVENT)
for event in event_buffer:
if not event.type:
continue
elif event.type == sdl2.SDL_QUIT:
se.quit()
break
else:
pass
event.type = 0
else:
continue
break
if __name__ == '__main__':
main()
And here are a before and an after screen grab:
The System Settings window of my KDE 5.45.0 desktop without the sdl script running, showing the relevant setting Desktop Effects>Translucency. Notice how the window is translucent because I'm dragging it while taking the picture.
The same but with the sdl script running. Notice how the window despite my vigorously dragging it stays stubbornly opaque.
I can also reproduce this in my Ubuntu desktop with Unity, so it's definitely not a problem of your KDE desktop. I think this is a bug in pysdl2 and this solution should be a temporary workaround until it gets fixed but in the meanwhile, you can just add this inside your while loop:
window.get_surface()
The issue is already reported here: https://github.com/marcusva/py-sdl2/issues/139
I have a Python Tkinter Text widget with scrollbars. I would like to define my own method for using horizontal edge scrolling on my laptop's touchpad. However, I don't know the event name(s) to allow me to do this. The vertical events work fine (so does pressing shift and using the vertical edge scroll to do horizontal scrolling). What are the event names I'm looking for? They don't appear to be "<Button-6>" and "<Button-7>", as these give errors; e.g.
_tkinter.TclError: specified keysym "6" for non-key event
I'm not sure what "<Button-6>" has to do with keys, but okay.
I'm using Linux (I say this because the events for vertical scrolling are different on Linux than Windows). I know how to discover unknown event names from key presses, but I'm not sure how to do that with the touchpad, too.
Looking at the list of events for a Text widget doesn't seem particularly insightful (other than that I don't see an event that looks like it's for the horizontal mousewheel).
I'm using Python 3.5.3 on Linux (Xubuntu 17.04, 64-bit).
I investigated code relating to printing general events, made code to do that for button presses (not just key presses) and I saw what event.num is for the horizontal mousewheel. So, I did the following solution:
I don't think there are event names for horizontal mouse scrolling (tell me if I'm wrong), but there do appear to be event numbers (which are 6 for scrolling left and 7 for scrolling right). While "<Button-6>" and "<Button-7>" don't seem to work, horizontal edge scrolling is still possible in Tkinter in Python 3.5.3 on Linux (I haven't tested anything else).
You'll need to bind "<Button>" instead of "<Button-6>" and "<Button-7>", and make a handler something like this:
...
self.bind("<Button>", self.touchpad_events)
...
def touchpad_events(self, event):
if event.num==6:
self.xview_scroll(-10, "units")
return "break"
elif event.num==7:
self.xview_scroll(10, "units")
return "break"
I do a return "break" in each section of the if/elif statement because we don't want to return "break" all the time and interrupt other button events (only when the horizontal mousewheel is scrolled); I mean, if you break all the time regular left-clicking won't work anymore (unless you program it in), and stuff like that. I just do 10 and -10 instead of event.delta/120 because it gives me the following error otherwise for some odd reason, and just putting in numbers manually seems to work great:
tkinter.TclError: expected integer but got "0.0"
Anyway, I tested this solution and it works. Problem solved. :)
I just wanted to add on that on MacOS as no where tells this and I spent quite a bit of time experimenting and searching. The event.state changes from 0 for vertical mouse scroll and 1 for horizontal mouse scroll.
def mouseScroll(event):
if event.state == 0:
canvas.y_viewscroll(-event.delta, "units")
elif event.state == 1: # you can use just an else as it can only be 0 or 1
canvas.x_viewscroll(-event.delta, "units")
I have been making a game using pygame in python and it refuses to identify the 1 key.
if event.type == KEYDOWN and event.key == K_1:
print("pass")
started = True
I added the "pass" to check if something else is wrong but nothing happens. I have used a few other keys like up, down, w, s and enter which work but it won't recognize any numbers.
If it helps, I am using a Trust Xpress wireless keyboard.
In regard to Dominic's question , I have tried both number pad and standard keys.
Your problem probably has nothing to do with your keyboard.
You probably just left numb lock off and are using the keypad.
If not, get the window to print all events and see if anything comes up when you press the 1 key.
It should be 49, but if it's not, just use whatever it is.
If nothing comes up at all, and you can't use the keyboard elsewhere, then it is something wrong with your keyboard.
How can I detect mouse clicks regardless of the window the mouse is in?
Perferabliy in python, but if someone can explain it in any langauge I might be able to figure it out.
I found this on microsoft's site:
http://msdn.microsoft.com/en-us/library/ms645533(VS.85).aspx
But I don't see how I can detect or pick up the notifications listed.
Tried using pygame's pygame.mouse.get_pos() function as follows:
import pygame
pygame.init()
while True:
print pygame.mouse.get_pos()
This just returns 0,0.
I'm not familiar with pygame, is something missing?
In anycase I'd prefer a method without the need to install a 3rd party module.
(other than pywin32 http://sourceforge.net/projects/pywin32/ )
The only way to detect mouse events outside your program is to install a Windows hook using SetWindowsHookEx. The pyHook module encapsulates the nitty-gritty details. Here's a sample that will print the location of every mouse click:
import pyHook
import pythoncom
def onclick(event):
print event.Position
return True
hm = pyHook.HookManager()
hm.SubscribeMouseAllButtonsDown(onclick)
hm.HookMouse()
pythoncom.PumpMessages()
hm.UnhookMouse()
You can check the example.py script that is installed with the module for more info about the event parameter.
pyHook might be tricky to use in a pure Python script, because it requires an active message pump. From the tutorial:
Any application that wishes to receive
notifications of global input events
must have a Windows message pump. The
easiest way to get one of these is to
use the PumpMessages method in the
Win32 Extensions package for Python.
[...] When run, this program just sits
idle and waits for Windows events. If
you are using a GUI toolkit (e.g.
wxPython), this loop is unnecessary
since the toolkit provides its own.
I use win32api. It works when clicking on any windows.
# Code to check if left or right mouse buttons were pressed
import win32api
import time
state_left = win32api.GetKeyState(0x01) # Left button down = 0 or 1. Button up = -127 or -128
state_right = win32api.GetKeyState(0x02) # Right button down = 0 or 1. Button up = -127 or -128
while True:
a = win32api.GetKeyState(0x01)
b = win32api.GetKeyState(0x02)
if a != state_left: # Button state changed
state_left = a
print(a)
if a < 0:
print('Left Button Pressed')
else:
print('Left Button Released')
if b != state_right: # Button state changed
state_right = b
print(b)
if b < 0:
print('Right Button Pressed')
else:
print('Right Button Released')
time.sleep(0.001)
It's been a hot minute since this question was asked, but I thought I'd share my solution: I just used the built-in module ctypes. (I'm using Python 3.3 btw)
import ctypes
import time
def DetectClick(button, watchtime = 5):
'''Waits watchtime seconds. Returns True on click, False otherwise'''
if button in (1, '1', 'l', 'L', 'left', 'Left', 'LEFT'):
bnum = 0x01
elif button in (2, '2', 'r', 'R', 'right', 'Right', 'RIGHT'):
bnum = 0x02
start = time.time()
while 1:
if ctypes.windll.user32.GetKeyState(bnum) not in [0, 1]:
# ^ this returns either 0 or 1 when button is not being held down
return True
elif time.time() - start >= watchtime:
break
time.sleep(0.001)
return False
Windows MFC, including GUI programming, is accessible with python using the Python for Windows extensions by Mark Hammond. An O'Reilly Book Excerpt from Hammond's and Robinson's book shows how to hook mouse messages, .e.g:
self.HookMessage(self.OnMouseMove,win32con.WM_MOUSEMOVE)
Raw MFC is not easy or obvious, but searching the web for python examples may yield some usable examples.
The windows way of doing it is to handle the WM_LBUTTONDBLCLK message.
For this to be sent, your window class needs to be created with the CS_DBLCLKS class style.
I'm afraid I don't know how to apply this in Python, but hopefully it might give you some hints.