Linux Joystick Mapper Wiki
Status: Beta
Brought to you by:
alexandrehardy
A linux userspace device driver that allows joystick events to be remapped. Several joysticks can be combined into a single controller, and button/axes events can be remapped to new joystick, keyboard or mouse events. Advanced scripting also supported.
For a graphical UI to program the joystick (using this software) please see https://rb3d.nl/rb3d/joymixerUI.html
Thank you so much for this driver Mr. Hardy! This script is incredible for mapping to my PS3 Controller into the PiFBA Emulator on RetroPie in my old Raspberry Pi Model B rev.1.2. It works finely with one player, but I want ask you how can I configure the map file for map my keyboard to the two same PS3 Controllers. The provider ID and product ID are the same, only change his Handlers (js0,js1,event0, etc).
I tried adding id=0, id=1 and device=0,device=1 to the map file but not working.
Thank you very much!
Regards from Chile!
I am trying to get this to work with a Hotas Warthog. I am having problems just mapping the axis through... I want to use this tool to combine some saitek rudder pedals with the warthog so I can have one virtual stick I could use in space sims like freespace 2 open. But when I just try to map the axis straitfowardly like:
axis vendor=0x044f product=0x0402 src=0 target=joyaxis axis=0
axis vendor=0x044f product=0x0402 src=1 target=joyaxis axis=1
axis vendor=0x06a3 product=0x0763 src=2 target=joyaxis axis=2
It doesn't work and the curser is in the lower right quadrant, maxed at 32767. Any help or examples would be greatly appreciated.
I am trying to get this to work with a Hotas Warthog. I am having problems just mapping the axis through... I want to use this tool to combine some saitek rudder pedals with the warthog so I can have one virtual stick I could use in space sims like freespace 2 open. But when I just try to map the axis straitfowardly like:
axis vendor=0x044f product=0x0402 src=0 target=joyaxis axis=0
axis vendor=0x044f product=0x0402 src=1 target=joyaxis axis=1
axis vendor=0x06a3 product=0x0763 src=2 target=joyaxis axis=2
It doesn't work and the curser is in the lower right quadrant, maxed at 32767. Any help or examples would be greatly appreciated.
Just wanted to share my post on reddit on how to setup Linux Joystick Mapper with DOSBox on RetroPie 4.7.2 https://www.reddit.com/user/ajscilingo/comments/kmn5nw/configuring_dosbox_to_work_with_linux_joystick/
Hope this helps someone looking to use this project with DOSBox on RetroPie... Edit Still haven't managed to get the HAT working on my controller but maybe someone can add on to this?
Last edit: Anthony S 2020-12-30
Anthony S, regarding the HAT not working. Did you notice anyone having trouble with getting HAT buttons working ? Hope it may assist.
Hi Stephen thanks for that, my gamepad's HAT is also being mapped to axis 16 and 17, and it too has three values -1, 0 and 1. I assumed that the 3 and 4 axis values reported by jstest were correct, but then I added your code and saw in stderr that they were in fact 16 and 17. In any case I didn't need to remap the values I used the following in my map for things to work correctly for me. How come you're re-mapping the values to 0, 128 and 255?
Last edit: Anthony S 2021-01-02
Good to hear.
I mapped the values to 0, 128, 255 to replicate function of other axis. From memory the direct mapping was not working for me.
Hi. Awesome tool.
I am struggling a bit with how to differentiate two identical controllers.
In
/proc/bus/input/devices:A simple map file looks like this:
The output of loadmap looks like this:
It seems like it always maps only the second controller. Is there a way to specify which one I want to use as source in the map file? Thanks a lot.
Hi!
The original joymap code was actually designed for my own use, and thus has some shortcomings when it comes to duplicate devices. The original design goals:
1. Consistently identify devices in a HOTAS setup (joystick, throttle and rudder pedals) even after reboots and hotplug events.
2. Allow programmability of targets.
That is a very broad statement, and was never written down. But the point was to identify devices by their vendor and product id so that the software tolerates reboots and hotplug events and consistently identifies devices correctly, even if they received different "js?" numbers due to the order in which they are detected.
I never added support for identifying a joystick by the linux device identifier (or
/dev/input/js?) so today we still have an issue that you cannot tell the software which device to use if there are multiple devices with the same vendor and product identifiers.There are others with the same request, but I am not sure when I will get time to implement that. I have a number of other commitments at the moment which will probably delay support for multiple devices with the same identifiers for some time. If you have programming experience, you are welcome to attempt to add that feature.
I have no objections to anyone creating forks of the project to add whatever they need, and can even advertise what they have done here. Patches are also welcome, although I may be a bit more fussy about what I would like to maintain :-).
Kind regards
Alexandre
Last edit: Alexandre Hardy 2021-02-14
Hi!
joymap-0.5.0 now supports use f the "id" keyword for mapping the joysticks. The Id corresponds to the event device associated with the device. For example, if event6 is listed as a handler for the device in /proc/bus/input/devices, then you can specify id=6 in the mapping file. If you specify the id, then you should not specify the vendor and product id.
joymap-0.5.0 supports plugging in and out of devices, but if you use the id, then you may find a new event kernel device has been allocated to the physical device. But if you leave the devices plugged in (connected) then the mapping should work fine. Also the event devices allocated by the kernel across reboots may differ. That was why the vendor and product system was selected originally (it works great for HOTAS setups).
Hope that helps!
Kind regards
Alexandre
keep getting this error:
make
cc -Wall -Werror -g -c -o loadmap.o loadmap.c
cc -Wall -Werror -g -c -o dictionary.o dictionary.c
cc -Wall -Werror -g -c -o mapparser.o mapparser.c
cc -Wall -Werror -g -c -o programparser.o programparser.c
cc -Wall -Werror -g -c -o validkeys.o validkeys.c
cc -Wall -Werror -g -c -o events.o events.c
cc -Wall -Werror -g -c -o vm.o vm.c
cc -Wall -Werror -g -c -o devices.o devices.c
cc -Wall -Werror -g -c -o config.o config.c
cc -Wall -Werror -g -c -o daemon.o daemon.c
cc -Wall -Werror -g -c -o file.o file.c
cc -g -o loadmap loadmap.o dictionary.o mapparser.o programparser.o validkeys.o events.o vm.o devices.o config.o daemon.o file.o
cc -Wall -Werror -g -c -o reserve_js.o reserve_js.c
cc -g -o reserve_js reserve_js.o config.o daemon.o
cc -g -rdynamic -shared -fPIC -ldl -o joymap_blocker.so joymap_blocker.c
cc -m32 -g -rdynamic -shared -fPIC -ldl -o joymap_blocker.i386.so joymap_blocker.c
In file included from /usr/include/features.h:392,
from /usr/include/dlfcn.h:22,
from joymap_blocker.c:2:
/usr/include/features-time64.h:20:10: fatal error: bits/wordsize.h: No such file or directory
20 | #include <bits wordsize.h="">
| ^~~~~~~~~~~~~~~~~
compilation terminated.
make: *** [Makefile:15: joymap_blocker.i386.so] Error 1</bits>
I think I'm missing a requirement but I'm clueless. Using Mint Linux 21.3. I tried asking on the Mint discord but no help there.
Hi Nichael,
Sorry to hear that it is not working for you. It has been a while since I encountered an error like that, I believe it is due to missing headers, usually kernel headers. (See for example https://github.com/Zygo/bees/issues/140).
You can try search for packages: glibc-headers, linux-headers, kernel-headers. I'm not using Linux Mint so I don't know exactly which package it is.
However, I do note that it is failing to compile a 32 bit library (which I use for wine) which may not be necessary for you. This library is used to block all attempts to access joysticks except for the joymap joystick, and is only required for programs that don't allow you to choose which joystick to use. Joymap will work fine without it, but if you use dosbox you may want to use the blocker library to force dosbox to only use joymap joysticks (using LD_PRELOAD). This however is the 32-bit version, and dosbox should be 64-bit.
Since this is a 32 bit library (not the whole of joymap, just the blocker library), it would need 32 bit support packages to be able to compile. You might want to see if those are installed, many systems don't have that nowadays. For myself I use it to run the 32-bit wine emulator.
If you don't need the 32-bit version of the blocker, you can remove compilation of that library with this patch:
Hope that helps!
Kind regards
Alexandre
Hi, thanks for the tool. I packaged it in the AUR.
I am having an issue: axes are being reset to -1 instead of 0. After some debugging, I can see the value 0 being written to the device in the set_joy_axis function, but somehow programs will report -1. In fact, anything 0 or below gets dropped by 1. Some program will think that my dpad is always pressed. My controllers dpad are axes that report -1, 0 or 1 and programs like the game controller setting panel in KDE will report -32768, 0 or 32767. My setting for the dpad:
Here's a patch that fixes a few issues:
* Set min and max axis values to the virtual device from map config. This enable SDL to detect axis as "hats" when the range is -1 to 1.
* Set the default minimum to -32768 instead, which fix the issue I was having above.
* Fix formula to rescale axis value between -32767 and 32767.
* Round and clamp value when rescaling value when we have a deadzone.
* Change
dev.absfuzz[i]todev.absfuzz[j]in register_devices.Last edit: patlefort 2025-05-05
Hi!
Thank you for the feedback! Sorry for the late reply, I've been somewhat busy.
Thank you for the patch! It is great to see a contribution in this form, I'll look at it shortly.
Kind regards
Alexandre
I've had a look at the patch, thanks again for that.
I'm going to make a few changes though. The original code allowed device values to be passed through unaltered. In other words, if
minandmaxweren't specified, then we would get the value from the device directly. Ifminandmaxare specified, then the output would be rescaled based on that range. I've changed the config a bit (backward compatible though) and the documentation to make that clearer.The patched you supplied changes that behaviour, so that scaling is always applied. However, the original
minandmaxvalue was designed to tell you about the input behaviour. And the main adjustment in the patch as I see it is to change the output behaviour.So I'm going to adjust the patch a little bit so that the input behaviour remains the same as it was (but the rescaling code is fine, no objections to that) and that the output settings are carried across as specified.
It is a great patch though, I've never tried to use the hat switch for some reason (for some reason I've always resorted to using the keyboard commands for views in flightsims instead of the switching hat because I like the snap to 3 o'clock, 6 o'clock and 9 o'clock positions).
Please check the pushed code, or joymap version 0.6.0 to see if it still solves your problem.
And thanks again for the patch! It made my life a lot easier...
Kind regards
Alexandre
Your code works fine except you forgot to add the new config keys in known_keys in mapparser.c. Thank you very much.
Thanks for catching that!
New version pushed and uploaded.
Feel free to push more patches my way, especially when I mess up. :-)
Kind regards
Alexandre
How do I map a button to the mouse scroll wheel? I have some games that only allow you select different hotbar slots via the mouse scroll wheel. Minecraft only allows you change from hotbar slot 1 to slot 2 by either the scroll wheel or by pressing 2. Half-life 2 only allows weapon selection via the scroll wheel.
Oh do you have a donation link somewhere? Having this continue to exist is really important to me for my current and future gaming needs.
Hi Michael,
Sorry for the late reply. The wheel is programmed as follows:
Note that there are four entries:
* Button press to scroll up
* Button release for scroll up
* Button press for scroll down
* Button release for scroll down
This example allows me to use one of the multiway switches on the Thrustmaster Warthog joystick to scroll up and down.
The magic number "8" for the axis comes from /usr/include/linux/input-event-codes.h (on my system it is here) under the constant ABS_WHEEL. You can use ABS_X (0) or ABS_Y (1) or ABS_WHEEL (8).
Please also check doc/config.pdf for details about the "speed" setting to control the speed of scrolling. You may need to adjust things if your scrolling has to be precise.
Hope that helps!
Kind regards
Alexandre
Using a ch products pro throttle:
button vendor=0x068e product=0x00f1 src=0 target=mouse axis=8 flags=invert speed=1
button vendor=0x068e product=0x00f1 src=0 target=mouse axis=8 flags=invert,release speed=1
button vendor=0x068e product=0x00f1 src=2 target=mouse axis=8 speed=1
button vendor=0x068e product=0x00f1 src=2 target=mouse axis=8 flags=release speed=1
these lines work for direction but the speed is still too fast when I click the hat. when i spin my mouse wheel slowly it clicks and generates a mouse scroll event. can I get that behavior here?
Alternatively can you explain how to script a action to a button press? If I make a variable current_button that outputs a keyboard press of the current_button the increments the value thatcould work. So if current_button is three, it sends a keyboard press of the 3 key/
Hi Michael,
I checked the code again, speed=1 is the slowest reporting rate possible. However, we can make it slower by adding delays between reporting events.
I tested with the following:
Note the vendor is 0x00ff which is actually a virtual joystick that joymap creates. The output for the virtual joystick is set in "mouse.code":
It looks a bit complicated, but it gets easier when you get used to it. The idea is that a button press starts a "thread". The thread executes until the thread itself sets a variable to say the thread is done. (This is necessary because of how threads are implemented in joymap, a thread is actually just a separate instruction pointer that is incremented at each iteration of the script, assuming the thread is executed).
In the thread we turn the button on for a short while, and then off for a short while. The delay ensures that we don't report the button as on all the time even if you hold it in on the joystick. You can play with the value (20) and make it longer for longer delays. You can also play with the value (10) to reduce the period of time over which the scroll event is reported.
I haven't managed to get it to scroll more smoothly. I see there is hi-res scrolling support in the kernel, and this should enable it:
... but it does not work for me, so I cannot confirm that it s a good change to make.
I see that you can also try change this with X-windows:
In this case I changed the device so that ten input events cause 1 unit of scroll, instead of 1. It seems to help to make things smoother.
You would have to investigate what the device number is, on my system it is 16 for the Joymap virtual mouse.
Kind regards
Alexandre
(I looked the details up here: https://unix.stackexchange.com/questions/441579/parameters-of-evdev-scrolling-distance-meaning)
Last edit: Alexandre Hardy 2025-07-24