Open Ao1Pointblank opened 4 months ago
i have discovered that for whatever reason, X11 cannot capture the WM_CLASS of certain windows that capture the cursor, i.e, a lot of games.
relevant error message: xprop: error: Can't grab the mouse.
this revamped script doesn't work with some windows. i have tried with wmctrl, xdotool, xwininfo, xprop, etc etc etc... somehow the old version of this script DID work with those windows, and i think it has something to do with the while-loop and sleep delay?
if i run the loop while true; do xprop -id "$(xdotool getactivewindow)" WM_CLASS; sleep 1; done
, it does work with these cursor-grabbing windows so perhaps instead of polling mouse state every millisecond i can instead use the benefits of xbindkey but also use a while loop to circumvent the weird x11 goofiness.
WOW! i am EXTRA stupid! my stubbornness to not learn any python has cost me many hours on this project!!!
apparently there is a super easy way of doing all this without any xbindkeys shenanigans, in python:
import subprocess
from evdev import InputDevice, ecodes
#path to the input device (your mouse with DPI button)
device_path = '/dev/input/event2'
device = InputDevice(device_path)
#define the event code for the desired button (BTN_FORWARD in my case, aka button 10 according to Xev)
button_event_code = ecodes.BTN_FORWARD
#define the commands for different window classes
commands = {
"discord": "xdotool key 'alt+shift+Up'", # DISCORD navigate to unread
"vesktop": "xdotool key 'alt+shift+Up'", # VESKTOP navigate to unread
"PortalWars-Linux-Shipping": "xdotool key 'f+h'", # SPLITGATE pick up weapon and use spray
"steam_app_782330": "xdotool key 'g+f'; xdotool key 'g'", # DOOMETERNAL icebomb (and switch back to frag)
"steam_app_553850": "xdotool key 'b'", # HELLDIVERS2 free keybind
"steam_app_1240440": "xdotool key 'g'", # HALOINFINITE
"Audacious": "bash -c '/home/pointblank/.local/share/nemo/scripts/💿\ Music/🎼\ Edit\ Current\ Audacious\ Opus'",
"Nemo-desktop": "sleep 0.2; dbus-send --session --dest=org.Cinnamon --type=method_call --print-reply /org/Cinnamon org.Cinnamon.ShowOverview 1> /dev/null",
"cube2_client": "play -q ~/.sounds/save_open.ogg"
}
#listen for events
for event in device.read_loop():
if event.type == ecodes.EV_KEY:
if event.code == button_event_code:
if event.value == 1: #check for button press event
#execute xdotool command to get the active window ID
xdotool_process = subprocess.Popen(["xdotool", "getactivewindow"], stdout=subprocess.PIPE)
#get the output of the xdotool command
active_window_id, _ = xdotool_process.communicate()
#decode the output to a string
active_window_id = active_window_id.decode("utf-8").strip()
#execute xprop with the active window ID to get the window class
xprop_process = subprocess.Popen(["xprop", "-id", active_window_id, "WM_CLASS"], stdout=subprocess.PIPE)
#get the output of xprop
xprop_output, _ = xprop_process.communicate()
#decode the output to a string
xprop_output = xprop_output.decode("utf-8").strip()
#parse the output to extract the window class
window_class = xprop_output.split('"')[3]
#execute the corresponding command based on the window class
if window_class in commands:
command = commands[window_class]
print(f"Window Detected: {window_class}. Executing command:")
print(command)
subprocess.Popen(["/bin/bash", "-c", command])
else:
print(f"No command defined for window class: {window_class}")
The Problem
while i am proud of the old button10.sh script's ability to restart itself via a lock file, making updating binds very easy, and of the method of detecting when a button10 press was made, via a while loop and xinput --query-state, the whole thing was being done the wrong way.
let me explain some a downside: the loop itself is really bad for performance. since these are binds mainly needed for gaming, they must be responsive. being held up by a 0.1sec delay simply is not fast enough and results in button mashing that most mouse dpi buttons maybe are not intended to handle (could be a skill issue lol)
the whole script is simply unnecessarily complex for something being run every 0.1sec.
The solution
there are already very robust tools for handling custom keybinds. (xbindkeys and its gui config tool, xbindkeys-config) using these, i am able to get instantaneous input from the dpi button.
How to implement
xinput --list
. find your mouse's ID. if you think your mouse is listed twice, it is probably the first one, under "Virtual core pointer", not "Virtual core keyboard". next, runwatch -n 0.1 xinput --query-state ID
where ID is the number you picked from the last step. press the DPI button a few times and see which button number shows changes in state up/down. that button number is the actual mouse button keycode, vs the fake one displayed in piper. remember this number.$HOME/.xbindkeysrc
with contents similar to:the
b:10
represents a mouse button press with the specific xinput mouse button ID from the last step.xbindkeys
(you should double check it is running with your task manager). it may need to be started again each time the PC boots.