Does Python evdev library have an event specific grab or passthrough? - python

A python evdev device has a .grab() function that prevents other processes from getting input events on the device. Is there any way to limit this to specific events from a device?
For my example, if I .grab() a pen input device that has pressure sensitivity and tilt and 2 click buttons on the side, how would I 'grab' ONLY the 2 click buttons but let the rest of the input (the tip, pressure sensitivity and tilt) be caught by the rest of the system as normal?
One of my pen buttons is normally a right click mouse event. I want to make it do something else but it still pops up the right click menu so I'm trying to figure out how to stop that.
I tried doing the grab and ungrab when the event occurs. Like event > grab > do my stuff > ungrab. But that is obviously too late and the OS still pops up the menu.
I tried doing the full grab, then in the event loop if it is a button press do my stuff, otherwise create a UInput event injection by just passing the event back to the system. This was a bit of a tangled mess. Permissions are required. When I finally got past that, the movement was offset and the pressure/tilt wasn't working... I think it is something to do with the DigiMend driver that actually makes that stuff work and/or xinput settings I have to pass to calibrate the tablet. But I'm not interested in writing all the pressure/tilt functionality from scratch or anything like that, so I need the DigiMend stuff to work as normal. So I gave up on this idea for now.
The only other thought I had was figure out why the OS defaults to the behavior it does and see if I can just manually disable the actions (i.e. Why does it think that button is a right mouse click and make it think that button is nothing instead.)
So I guess this is a 3 level question.
Can I achieve the the grab functionality on select events instead of the device as a whole?
If the passthrough idea was better, is there a way to achieve this without having to do any permission modifications and be able to pass the exact event (i.e. no offset and such that I experienced?)
If evdev does not have this ability or it'd be easier to do in another way, like disabling the defaults for the pen in the OS somehow, I am open to suggestions. I am using Kubuntu 20.04 if that helps.
Any help would be appreciated, let me know if more info is needed, thanks in advance!

I ended up going with #3 and using xinput. Figured I'd put up this answer for now in case others come across this and want to do something similar.
The workaround was actually kind of simple. I just use xinput to remap the 2 buttons. So evdev doesn't have to grab at all. Just disable those buttons and everything goes normally except those, which I listen for with evdev.
xinput set-button-map {} 1 0 0 4 5 6 7
My device has 7 buttons and are normally mapped 1-7. Which are all mouse equivalents of left click, middle click, right click, etc...
By using that string and passing the device ID in for the {} I just run that with subprocess first. And voila, no more right click menu. And I can use evdev to map the events to whatever I want.

Related

How to control the mouse in Minecraft using Python?

All in all, I'm trying to programmatically -and externally- control the Minecraft player's orientation.
No APIs, no Java mods to the game environment
Typically this requires the movement of the mouse, but every single mouse movement simulating python3 library that I've tried doesn't move the player's head in-game. Each library does something different, too.
For example, pyautogui doesn't do anything until you move the mouse manually after the script has finished. Doing this will jerk the player's view to where the program supposedly moved it to, before continuing to follow your current mouse movements. This happens for both mouse commands.
import pyautogui
pyautogui.moveTo(500, 500)
pyautogui.moveRel(100, 100)
The pynput library had the same weird result as pyautogui:
from pynput.mouse import Controller
mouse = Controller()
mouse.position = (100, 200)
mouse.move(200, -100)
Quartz doesn't do anything at all:
import Quartz
class Mouse():
down = [Quartz.kCGEventLeftMouseDown, Quartz.kCGEventRightMouseDown, Quartz.kCGEventOtherMouseDown]
up = [Quartz.kCGEventLeftMouseUp, Quartz.kCGEventRightMouseUp, Quartz.kCGEventOtherMouseUp]
[LEFT, RIGHT, OTHER] = [0, 1, 2]
def click_pos(self, x, y, button=LEFT):
self.move(x, y)
self.click(button)
def to_relative(self, x, y):
curr_pos = Quartz.CGEventGetLocation( Quartz.CGEventCreate(None) )
x += curr_pos.x;
y += curr_pos.y;
mouse = Mouse()
mouse.to_relative(200, 200)
And the python mouse library is outdated: the error showed that it will only run on Darwin (I'm on macOS High Sierra). I was sad on learning this because of the description on the Github page. It says "Global event hook on all mice devices (captures events regardless of focus)". I then thought that, somehow, Minecraft was sucking up all the simulated mouse movements on it's own. Either way, I'm not using the right interface for this game, and I need something that can bypass Minecraft's interesting mouse controls to get the movement that I want.
I even tried using mouse keys (mac's mouse-moving accessibility feature that lets you control the mouse with only keys) along with pyautogui.
import pyautogui # with mouse keys on
import time
# mouse keys is an accessibility feature on mac that controls the mouse with the keyboard
print("[ALERT]: Make sure mouse keys is on! (press option 5 times if shortcut is enabled)")
pyautogui.keyDown('8') # up in mouse keys
time.sleep(5)
pyautogui.keyUp('8')
I wasn't particularly surprised that the last one didn't work, but I think I'm running out of ways to try and bypass whatever is making Minecraft not take my python-mouse input. At this point, I'm pretty sure that there must be some distinction in the kind of input that I'm giving the computer. Minecraft as a program doesn't use the mouse like other programs do, and python mice don't control the mouse like other sources do, so there is a disconnect.
I'm on my macOS High Sierra running Minecraft in both fullscreen and windowed mode, trying everything I can to get this to function properly. I'll start the test script (python 3.6) in PyCharm, change windows (or window focus) to Minecraft (with adequate delay time in-program), and then witness what happens. Mouse clicking, keyboard presses, and even hotkeys that involve the command and escape keys all work fine in Minecraft with pyautogui, so I'm not worried about those at all. It's literally just the mouse movement that's not doing anything.
First of all, is this the right place to ask this question? Is there anything else to try, or is there something crucial that I'm missing, that would allow my mouse input to be responded to correctly?
I am trying to do the same thing, and I got mine to move the view in Minecraft (Java edition).
What worked for me was to use pynput with relative mouse commands. It also needed 'Raw Input' to be off in the Minecraft settings. [Esc -> Options... -> Controls... -> Mouse Settings... -> Raw input: OFF]
import pynput
mouse = pynput.mouse.Controller()
mouse.move(10, 10)
Also, here's the beginnings to a smooth movement of the mouse if anyone wants it:
def move_smooth(xm, ym, t):
for i in range(t):
if i < t/2:
h = i
else:
h = t - i
mouse.move(h*xm, h*ym)
time.sleep(1/60)
move_smooth(2, 2, 40)
Now, onto trying to make the keyboard work :P
I managed to make it work with the mouse library. Instead of using mouse.move(x,y,absolute,duration) I used mouse._os_mouse.move_to(x,y) and mouse._os_mouse.move_relative(x,y). Take into account that if you want a smooth effect you'll have to implement it yourself using something like time.sleep(s).
This question has also bothered me for a while and I finally found a solution to this question.(macOS Monterey 12.2, M1 chip 2020)
I have tried multiple python library and macro apps which none worked and rawinput also didn't help. However, pointer control in system preferences works with Minecraft mouse movement. The mouse keys option allows you to control mouse movement with keystrokes,
Where to find Mouse Keys in system preferences
System Preferences -> Accessibility -> Pointer control(under Motor) -> Enable Mouse Keys
so I tried to simulate the keyboard to move the mouse. For some reason, none of the python library or macro apps will work with mouse keys except for apple script. So I wrote an apple script and embedded it in python, which worked moving the mouse in Minecraft when the mouse key option is on.
The mouse keys option will allow you to use the numpad keys to control you mouse.
https://eastmanreference.com/complete-list-of-applescript-key-codes
This link will tell you the key code for the keystroke you want to press.
import os
cmd=""" osascript -e '
repeat 500 times
tell application "System Events" to key code 88 --right
end repeat'
"""
os.system(cmd)
In the script key code 88 matches numpad key 6, which will move your cursor right, change the key code to customize where the cursor will move.
I am in a similar situation to you. I was also unable to find a way to register my mouse movements in games such as minecraft.
However, I learned that you can use Java and the built-in robot library to achieve the mouse movement as desired. I don't know if you are set on python but if not it's worth checking out.
In the Minecraft Options... go to Controls... go to Mouse Settings... and there turn off Raw Input.
That should do it (you're on mac tho and I don't know if this setting is on
the mac version of minecraft)
I was struggling with this too and I found the following findings (tested on Ubuntu 20.04):
If you activate RawInput, you can use mouse.position=(dx, dy) which (although it is intended to be absolute) causes relative motion of the head! And it also works with negative values for dx and dy.
This is much faster and more accurate. You can for instance chain
mouse.position = (0, -100000) # turn head all the way up
mouse.position = (0, 600) # turn head exactly to horizon level
The horizon is 600 "pitch-pixels" down from upright, when mouse sensitivity is set to 100%. You don't need any delay between the calls and they happen so fast that in the vast majority of cases, the player does not seem to look up in between, but looks to the horizon right away. When I used the relative motion with raw input off, I needed sleeps in between and the speed was also capped at some value.
The only issue is, that you need to switch between this hacky way of controlling the mouse and the normal way using mouse.move(dx, dy) or with actually absolute screen coordinates mouse.position=(x, y) when you are on the crafting screen / in a menu. But I found that if you also create a pynput mouse listener, you will see that Minecraft sets the mouse position to the center of its window everytime you enter a menu and it does it another two times when you go back to the game. So I use these as triggers.
Try running python as admin and run the game in windowed mode. Pyautogui should work then.

How to detect mouse scroll and mouse position in Python and then make some actions with it?

I would like to make a program for displaying some information and help (like it is sometimes done at libraries or in other public places). So basically some information screen. The problem is I would like to prevent the user from exiting the program and scrolling up, to see what others typed.
I would like to do that without importing big libraries like Pygame. There are plenty of modules for automatic mouse movement and and mouse clicks, but almost no modules for detecting it. If you know some please write them here. I am using Windows 10 and 7.
Try pynput. It's a bit fiddly to use when capturing, but can capture keyboard and mouse and also emit both.
This answer doesn't really answer the question asked in the title:
However it might answer the use case that you describe:
I don't have a windows computer at hand for testing:
but perhaps this could work:
import os
os.system('cls')
# now rewrite the lines, that a user is allowed to see.
Theoretically cls is supposed to clean the windows screen buffer and you wouldn't see any history and it should be impossible to scroll back.
I think most other solutions would quickly become complicated or could be circumvented by a user with some combinations of key presses and mouse movements.
However you had to explicitely rewrite whatever you want to keep on the display.

Recording all mouse click and keyboard events in linux [Python]

I need a function that when will return true or false depending on whether a mouse event was recorded. Right now I'm using python-Xlib to record cursor positions, but the amount of documentation for the module is really sparse. It seems the only way to get familiar with it is to dig through the source code.
I'm not talking about keeping track of a gui being pressed or anything like that, I need raw input from the mouse.
Check out pyHook.
It handles tons of events at relatively low-level (Windows Only).
If you need examples, you'll find a lot of projects around the web, such as this one
If you are on Linux, there is also pyxhook

Recording the time of the start of a screen touch in PsychoPy on Windows

I'm helping to implement an experiment using PsychoPy on a Windows 8 tablet. It doesn't seem to be possible to get direct access to touch events through either PsychoPy, or the pyglet or PyGame interfaces.
Most other sources I've found have referred to using mouse move events in place of touch events. This works fine for recording position, but for recording time it doesn't work for us. We would like to collect the timing of the start of the touch, whereas the mouse event comes at the end of the touch.
Does anyone know of a way to do this, either in PsychoPy or by importing another library into the experiment?
Update: Logging ioHub mouse events, it looks like press and release mouse events are both sent at the end of the touch. This makes sense as this is the point at which the OS is sure that the touch is not a swipe. (Also, it will decide whether the touch is a left- or right-click depending on the duration of the touch).
I've managed this using a hook into the WndProc, it's not pretty but it works. The solution, for posterity:
https://github.com/alisdt/pywmtouchhook
A brief summary:
I used a combination of ctypes and pywin32 (unfortunately neither alone could do the job) to register the target HWND to receive touch messages, and replace its WndProc, passing through all non-touch messages to the original WndProc.

easygui CLOSE button (on top right of window) not functioning

i have created a chat system in python, using easygui for graphical user interface.
there are minimize,maximize and close button on top right of window,but the close button is not functioning at all.i just can use the exit button which i created to close the application. i had some search and found there is a problem with easygui, so is it totally impossible to fix this problem? or how can i remove that close button from top right as there is no use for it. its final year project and i'm afraid my advisor and supervisor want try that button and i lose mark because of no function
is there anyway to fix it or at least remove that close button?
This is likely past the due date for your assignment...sorry. But, that was a known limitation of easygui. An up-to-date version with a fix for that will be released soon. If you can't wait, you can take a look at it in development form: https://github.com/robertlugg/easygui

Categories

Resources