How do I PROPERLY map a keyboard key to a mouse button?

13,009

Solution 1

An askubuntu post contains an answer that I will summarize below.

The problem is that xbindkeys grabs the entire mouse, making modifers+mouse click mapping uncertain. The answer uses uinput via python-uinput script to monitor /dev/my-mouse for the thumb button click and send the Ctrl key to the virtual keyboard. Here are the detailed steps:

1. Make udev rules

For the mouse, file /etc/udev/rules.d/93-mxmouse.conf.rules :

KERNEL=="event[0-9]*", SUBSYSTEM=="input", SUBSYSTEMS=="input", 
ATTRS{name}=="Logitech Performance MX", SYMLINK+="my_mx_mouse", 
GROUP="mxgrabber", MODE="640"

Udev will look for kernel devices with names like event5. The SYMLINK is for finding the mouse in /dev/my_mx_mouse, readable by the group mxgrabber.

To find hardware information run something like :

udevadm info -a -n /dev/input/eventX

For uinput, file /etc/udev/rules.d/94-mxkey.rules :

KERNEL=="uinput", GROUP="mxgrabber", MODE="660"

Unplug and plug your mouse, or force udev to trigger the rules with udevadm trigger.

2. Activate UINPUT Module

sudo modprobe uinput

And in /etc/modules-load.d/uinput.conf :

uinput

3. Create new group

sudo groupadd mxgrabber
sudo usermod -aG mxgrabber your_login

4. Python script

Install python-uinput library and python-evdev library.

The script below requires identifying the event.code of the button :

#!/usr/bin/python3.5
# -*- coding: utf-8 -*-

"""
Sort of mini driver.
Read a specific InputDevice (my_mx_mouse),
monitoring for special thumb button
Use uinput (virtual driver) to create a mini keyboard
Send ctrl keystroke on that keyboard
"""

from evdev import InputDevice, categorize, ecodes
import uinput

# Initialize keyboard, choosing used keys
ctrl_keyboard = uinput.Device([
    uinput.KEY_KEYBOARD,
    uinput.KEY_LEFTCTRL,
    uinput.KEY_F4,
    ])

# Sort of initialization click (not sure if mandatory)
# ( "I'm-a-keyboard key" )
ctrl_keyboard.emit_click(uinput.KEY_KEYBOARD)

# Useful to list input devices
#for i in range(0,15):
#    dev = InputDevice('/dev/input/event{}'.format(i))
#    print(dev)

# Declare device patch.
# I made a udev rule to assure it's always the same name
dev = InputDevice('/dev/my_mx_mouse')
#print(dev)
ctrlkey_on = False

# Infinite monitoring loop
for event in dev.read_loop():
    # My thumb button code (use "print(event)" to find)
    if event.code == 280 :
        # Button status, 1 is down, 0 is up
        if event.value == 1:
            ctrl_keyboard.emit(uinput.KEY_LEFTCTRL, 1)
            ctrlkey_on = True
        elif event.value == 0:
            ctrl_keyboard.emit(uinput.KEY_LEFTCTRL, 0)
            ctrlkey_on = False

5. Finishing

Make the python file executable and ensure it is loaded at startup.

Solution 2

I figured this out earlier today with other modifier keys. The issue is that you must include the modifier in the button combination for the release. Assuming your Super key is mapped to Mod4 (which should be the default, afaik):

"xte 'keydown Super_L'"
  b:11

"xte 'keyup Super_L'"
  Mod4 + b:11 + release

EDIT: Just realized that this doesn't completely answer your question as you still won't be able to use LMB while holding down b:11

Solution 3

As you can run script on a mouse click, you can use the following trick.
1. Press Button 11 to hold the super key. ( Button 11 trigers a script )
2. Move windows using the other mouse buttons
3. Press mouse button 11 again to release super key

script
Use xdotool to hold super key
On first Button click ,create a temp file and hold key. On the next click delete tmp file and release the key,

update

According to ubuntu help page ( many button mouse how to ) imwheel can remap to a key.

Solution 4

Debugging suggestion: I would try to monitor /dev/input/eventX file to see what events are generated when you press and release that button, especially in combinations with BTN_LEFT. Here is a sample code to get you started. You'll obviously have to modify it to log all events, not only key presses.

You may also want to check out xev output, if you haven't already. Analysing both logs should reveal the exact issue you're having.

Chances are that your mouse is generating extra button release events when multiple buttons are pressed. In that case, your options would be to use key binding workarounds, or modify xf86-input-evdev library to filter unwanted events (or simulate missing ones). I did something similar a while back for a touchscreen which generated "click" events when trying to drag & drop. The idea was to filter "release" events which came almost simultaneously (within a small time window) with "click" events. If my guess is correct, you would essentially need to implement something similar.

Share:
13,009

Related videos on Youtube

Hubro
Author by

Hubro

Code enthusiast!

Updated on September 18, 2022

Comments

  • Hubro
    Hubro over 1 year

    Question summary: I want one of my mouse buttons to be registered as the left Windows button Super_L by X11.


    In my window manager, I can move windows around by holding the "left Windows button" (Left Super) and dragging a window with the left mouse button. I want to be able to do that without touching the keyboard, so I want to map the left Super key to mouse button 11, that way I can hold mouse button 11 and click+drag windows.

    The most obvious solution is using xbindkeys and xte like this (.xbindkeysrc):

    "xte 'keydown Super_L'"
      b:11
    
    "xte 'keyup Super_L'"
      b:11 + release
    

    This works like this:

    • When I press down mouse button 11, Super_L is also pressed down
    • When I release mouse button 11, Super_L is also released

    But there's a problem: I can't move windows using Super_L + Mouse1 if I'm also holding down another mouse button, like Mouse button 11. Using the solution above, mouse button 11 is still being registered as pressed and released, and so none of the window manager operations work.

    I have tried this using both Cinnamon and Awesome WM, and absolutely none of the Super_L keyboard combinations work while mouse button 10 or 11 is being held down.

    A subpar hack

    I'm currently working around this issue by causing the mouse 11 click to hold the Super_L button for a certain amount of time. That way I can click the mouse button, then drag stuff around for a brief period afterwards:

    "xte 'keydown Super_L' 'usleep 250000' 'keyup Super_L'"
      b:11
    

    Another attempt

    As suggested by totti, I tried this xbindkeys configuration:

    "xte 'mouseup 10' 'keydown Super_L'"
      b:10
    
    "xte 'keyup Super_L'"
      b:10 + Release
    

    It doesn't work. It seems the Super_L key is being held down, because as soon as I release button 10 it remains held down for ever (until I press the Super_L key again on the keyboard) but the mouse button is still being registered, because I can't click&drag windows. I don't think I'm going to be able to make this work using xbindkeys and xte.

  • Hubro
    Hubro about 9 years
    A couple of problems with that: #1 This is still just another hack/workaround, and doesn't answer the question. #2 xbindkeys doesn't work while the super key is being held down. It's as if xbindkeys is paused, and doesn't register anything, until the super key is released.
  • Hubro
    Hubro about 9 years
    Ok, after about 5 minutes of research, I retract point #2. I apparently have to add + Mod4 in my xbindkeys config to account for the super key being held down. The workaround you suggest is better than mine, and I'm switching to it :-) But it still doesn't answer the question.
  • zmo
    zmo over 7 years
    I've updated the script to assign an unused keycode to the mouse buttons (I set them up to F13, F14 and F15, and disabling mouse functions using xinput. Then I can simply reassign those keys to whatever I need using a simple xmodmap. The main idea is drafted in a gist (there is some hardcoded values and I do not restore xinput mouse function afterwards), I'll make a blog post about this with the final version of the script (and share the link over here when it'll be done. Thank you for your help! ☺♥
  • Maxim
    Maxim about 7 years
    Also check my new answer on the other thread for a x11-based solution askubuntu.com/a/903389/269589