Skip to content

Instantly share code, notes, and snippets.

@gatopeich
Created February 5, 2023 10:26
Show Gist options
  • Save gatopeich/21863b353b505ee3b116a2135a3a4315 to your computer and use it in GitHub Desktop.
Save gatopeich/21863b353b505ee3b116a2135a3a4315 to your computer and use it in GitHub Desktop.
Mapping keys and mouse to gamepad with Linux UDEV system
This is something I never had the time to put together.
Today I asked openai.org and it provided a nice walk-through...
QUESTION> How can I map gamepad buttons to keys and mouse with UDEV?
To map gamepad buttons to keyboard and mouse inputs with UDEV, you will need to create a udev rule file to specify the mapping. Here are the steps:
Identify the gamepad device name: Run ls /dev/input/by-id to see a list of all input devices connected to your system. Look for the one that corresponds to your gamepad and note its name, e.g. /dev/input/by-id/usb-<VENDOR_ID>-<PRODUCT_ID>.
Create a udev rule file: Create a new file in /etc/udev/rules.d/ with a descriptive name, e.g. 99-gamepad-mapping.rules.
Add the mapping rules: In the rule file, add a line for each button you want to map. The format of each line is as follows:
makefile
SUBSYSTEM=="input", ATTRS{idVendor}=="<VENDOR_ID>", ATTRS{idProduct}=="<PRODUCT_ID>", ENV{ID_INPUT_KEY}=="<KEY_NAME>", RUN+="<COMMAND>"
Replace <VENDOR_ID> and <PRODUCT_ID> with the values you noted in step 1.
Replace <KEY_NAME> with the name of the button you want to map. The names of buttons can be found by running evtest on the device and pressing buttons to see the corresponding output.
Replace <COMMAND> with a shell command that simulates the desired keyboard or mouse input. For example, to map a button to the "A" key, you would use /bin/sh -c 'echo a > /dev/input/uinput'.
Reload udev rules: Run sudo udevadm control --reload-rules to reload the udev rules and apply the changes.
Test the mapping: Test the mapping by pressing the buttons on your gamepad and checking if the corresponding keys or mouse inputs are triggered.
Note: The exact steps may vary depending on the Linux distribution you are using.
QUESTION #2: Thanks that is helpful. Only missing how to mapping axis to mouse a... (accidentally hit enter)
To map a gamepad axis to mouse movement, you can use the jstest utility to identify the axis number, and then use that in the udev rule to control the mouse. Here are the steps:
Identify the gamepad axis number: Run jstest /dev/input/js0 (replace js0 with the appropriate joystick device for your system) to see the state of all axes and buttons on the gamepad. Move the joystick or trigger you want to map and note the number of the corresponding axis.
Create a udev rule file: Create a new file in /etc/udev/rules.d/ with a descriptive name, e.g. 99-gamepad-mapping.rules.
Add the mapping rule: In the rule file, add the following line to map the axis to mouse movement:
makefile
SUBSYSTEM=="input", ATTRS{idVendor}=="<VENDOR_ID>", ATTRS{idProduct}=="<PRODUCT_ID>", ENV{ID_INPUT_JOYSTICK}=="1", ATTRS{[axis_number]}=="+*", RUN+="/usr/bin/xdotool mousemove_relative -- [axis_number]"
Replace <VENDOR_ID> and <PRODUCT_ID> with the values you noted in step 1.
Replace [axis_number] with the number of the axis you want to map, as identified in step 1.
Reload udev rules: Run sudo udevadm control --reload-rules to reload the udev rules and apply the changes.
Test the mapping: Test the mapping by moving the joystick or trigger and checking if the mouse pointer moves accordingly.
Note: The exact steps may vary depending on the Linux distribution you are using, and you may need to adjust the xdotool command to fit your specific needs.
QUESTION #2 (edited): Thanks that is helpful. Only missing how to map axis to mouse movement and wheels
To map gamepad axes to mouse movement and wheel inputs with UDEV, you can use the evtest tool to monitor the events generated by the axes and then write a udev rule to map them to desired mouse inputs. Here's an example of how to do this:
Install evtest: Run sudo apt-get install evtest or equivalent to install the evtest tool.
Identify the gamepad device name: Run ls /dev/input/by-id to see a list of all input devices connected to your system. Look for the one that corresponds to your gamepad and note its name, e.g. /dev/input/by-id/usb-<VENDOR_ID>-<PRODUCT_ID>.
Test the axes with evtest: Run sudo evtest /dev/input/by-id/<DEVICE_NAME> to start the evtest tool and monitor the events generated by the gamepad. Move the axes you want to map to mouse movement and note the event codes generated.
Create a udev rule file: Create a new file in /etc/udev/rules.d/ with a descriptive name, e.g. 99-gamepad-mapping.rules.
Add the mapping rules: In the rule file, add a line for each axis you want to map. The format of each line is as follows:
makefile
SUBSYSTEM=="input", ATTRS{idVendor}=="<VENDOR_ID>", ATTRS{idProduct}=="<PRODUCT_ID>", ENV{ID_INPUT_ABS}=="<EVENT_CODE>", RUN+="/bin/sh -c 'echo <MOUSE_INPUT> > /dev/input/mice'"
Replace <VENDOR_ID> and <PRODUCT_ID> with the values you noted in step 2.
Replace <EVENT_CODE> with the event code for the axis you want to map, which you noted in step 3.
Replace <MOUSE_INPUT> with the desired mouse input. To map an axis to mouse movement, you would use $((<EVENT_VALUE> * <SCALING_FACTOR>)). To map an axis to mouse wheel, you would use $((<EVENT_VALUE> * <SCALING_FACTOR> / WHEEL_DELTA)). Replace <EVENT_VALUE> with the value of the axis event, <SCALING_FACTOR> with the desired scaling factor for mouse movement, and WHEEL_DELTA with the standard mouse wheel delta (usually 120).
Reload udev rules: Run sudo udevadm control --reload-rules to reload the udev rules and apply the changes.
Test the mapping: Test the mapping by moving the axes on your gamepad and checking if the corresponding mouse movement or wheel inputs are triggered.
Note: The exact steps may vary depending on the Linux distribution you are using.
@gatopeich
Copy link
Author

QUESTION #4> I prefer not to use RUN, it could be slow for gaming... is there no way to map the gamepad as if it was a hardware keyboard?

Yes, there is a way to map the gamepad buttons as if they were hardware keyboard buttons. This approach is likely to be faster than using the RUN command in UDEV, as it avoids running an external shell script.

You can use the xinput tool to map the gamepad buttons to keyboard keys, and then use the X Window System's standard key mapping mechanism to map the keyboard keys to the desired mouse inputs. Here's an example of how to do this:

Install xinput: Run sudo apt-get install xinput or equivalent to install the xinput tool.

Identify the gamepad device name: Run xinput list to see a list of all input devices connected to your X Window System. Look for the one that corresponds to your gamepad and note its name, e.g. Gamepad (<VENDOR_ID> <PRODUCT_ID>).

Map the buttons to keyboard keys: Run the following command to map a button on your gamepad to a keyboard key:

php

xinput set-button-map <DEVICE_NAME> <BUTTON_INDEX> <KEY_CODE>

Replace <DEVICE_NAME> with the name of your gamepad device, <BUTTON_INDEX> with the index of the button you want to map (starting from 1), and <KEY_CODE> with the X Window System key code for the desired keyboard key. Repeat this step for each button you want to map.

Map the keyboard keys to mouse inputs: You can use the X Window System's standard key mapping mechanism to map the keyboard keys to the desired mouse inputs. For example, you can use the Xmodmap tool to create a keymap file that maps keyboard keys to mouse buttons and wheel inputs.

Note that the exact steps for mapping the keyboard keys to mouse inputs may vary depending on the Linux distribution and window manager you are using. You may need to consult the documentation for your specific setup for more information on how to do this.

@gatopeich
Copy link
Author

LET'S MAKE IT FASTER!> I prefer not to use RUN, it could be slow for gaming... is there no way to map the gamepad as if it was a hardware keyboard?

Yes, there is a way to map the gamepad buttons as if they were hardware keyboard buttons. This approach is likely to be faster than using the RUN command in UDEV, as it avoids running an external shell script.

You can use the xinput tool to map the gamepad buttons to keyboard keys, and then use the X Window System's standard key mapping mechanism to map the keyboard keys to the desired mouse inputs. Here's an example of how to do this:

Install xinput: Run sudo apt-get install xinput or equivalent to install the xinput tool.

Identify the gamepad device name: Run xinput list to see a list of all input devices connected to your X Window System. Look for the one that corresponds to your gamepad and note its name, e.g. Gamepad (<VENDOR_ID> <PRODUCT_ID>).

Map the buttons to keyboard keys: Run the following command to map a button on your gamepad to a keyboard key:

php

xinput set-button-map <DEVICE_NAME> <BUTTON_INDEX> <KEY_CODE>

Replace <DEVICE_NAME> with the name of your gamepad device, <BUTTON_INDEX> with the index of the button you want to map (starting from 1), and <KEY_CODE> with the X Window System key code for the desired keyboard key. Repeat this step for each button you want to map.

Map the keyboard keys to mouse inputs: You can use the X Window System's standard key mapping mechanism to map the keyboard keys to the desired mouse inputs. For example, you can use the Xmodmap tool to create a keymap file that maps keyboard keys to mouse buttons and wheel inputs.

Note that the exact steps for mapping the keyboard keys to mouse inputs may vary depending on the Linux distribution and window manager you are using. You may need to consult the documentation for your specific setup for more information on how to do this.

@gatopeich
Copy link
Author

To be honest the instructions provided by OpenAI have glitches but saved me a lot of time gathering information about obscure topics

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment