UPDATE:
As of recent versions of Chrome OS, the procedure detailed below (using jscal) no longer works to remap keys for Android apps. The original post should now be considered deprecated and no longer applicable.
In some cases, Android apps will suffice to remap keys, and in other cases it may be possible to remap events in CrOS via evdev.
I wanted to play the game "War Robots" but when I opened it up I discovered that, while I could move and aim, the buttons to fire were incorrectly mapped.
First of all, I tried creating /system/usr/keylayout/Vendor_045e_Product_0719.kl on the Android filesystem, as this was what had worked for me to configure this gamepad on my Nexus 9. However, editing the Android keylayout didn't seem to do anything on the Chromebook. I had a look around the device and found that in the list of CrOS installable packages at /etc/portage/make.profile/package.installable, the following was included: games-util/joystick-1.4.2.
Accordingly, I emerged joystick-1.4.2 and played around with jstest and jscal.
The set of commands to emerge these binaries:
shell
Turned out I that with this I was able to easily swap gamepad button mappings around.
First of all I dumped the current mapping with
jscal -q /dev/input/js0
which gave the following output
jscal -u 6,0,1,2,3,4,5,15,304,305,307,308,310,311,314,315,316,317,318,704,705,706,707 /dev/input/js0
In order to determine which number corresponded to which button, I tried
jstest /dev/input/js0
However, when I pressed some buttons on the gamepad, numbers for the buttons were displayed which did not correspond with the set above. So I tried evtest
emerge evtest
Output:
No device specified, trying to scan all of /dev/input/event*
6
Hooray! Pressing the buttons on the gamepad gives useful output, such as
code 311 (BTN_TR), value 1
and so on
Armed with this information I was easily able to fix the mapping in War Robots, which had one "Fire" button mapped to "Start" and another "Fire" button mapped to "Back". I found a number of reports online suggesting that this is a current issue with (lack of) controller support in the game itself, rather than any quirk of running Android on Chrome OS.
jscal -u 6,0,1,2,3,4,5,15,304,305,307,308,310,311,314,315,316,317,318,704,705,706,707 /dev/input/js0
jscal -u 6,0,1,2,3,4,5,15,304,305,307,308,314,315,310,311,316,317,318,704,705,706,707 /dev/input/js0
Saved the config. to a file with:
jscal -q /dev/input/js0 > /usr/local/WR_gamepad.sh
Unfortunately I also had another issue to fix. There is a fair amount of play in both the analog axis of my controller, the right one particularly, meaning that with the controller at rest, it's sometimes still pointing to the right slightly. In order to stop the annoying 'camera moving to the right without me moving it' issue, I needed to calibrate the dead zones.
Back to jscal:
jscal -c
(went through the calibration, which involves pressing each button/moving each axis once)
Output:
Calibrated axis:
Setting correction to:
Dumped the above corrections with
jscal -p /dev/input/js0 which gave the following output:
jscal -s 6,1,0,-338,-338,16555,16217,1,0,-8,-8,16388,16380,1,0,126,126,4260750,4161663,1,0,-64,-64,16416,16352,1,0,55,55,16357,-16357,1,0,111,128,4836527,4227201 /dev/input/js0
jscal -p /dev/input/js0 > /usr/local/jscal.sh
First attempt at editing dead zones.
vi/usr/local/jscal.sh
Original file contents (as above):
jscal -s 6,1,0,-338,-338,16555,16217,1,0,-8,-8,16388,16380,1,0,126,126,4260750,4161663,1,0,-64,-64,16416,16352,1,0,55,55,16357,-16357,1,0,111,128,4836527,4227201 /dev/input/js0
Changed the 4th and 5th values (axis 0) and the 22nd and 23rd values (axis 3) from -338,-338 and -64, -64 respectively to +/- ~3000 (Axis 0 and 3 are L-< >+R on the two analogs).
New file contents:
jscal -s 6,1,0,-3038,3038,16555,16217,1,0,-8,-8,16388,16380,1,0,126,126,4260750,4161663,1,0,-3064,3064,16416,16352,1,0,55,55,16357,-16357,1,0,111,128,4836527,4227201 /dev/input/js0
Opened up the game. Still some drift in the right-hand analog. Let's have a look at what's going on with jstest:
jstest /dev/input/js0
Moving the analogs different ways, dropping them to center, and watching the values change in jstest confirms that while there is play in both sticks, the right hand side of the right hand stick is particularly loose.
Second attempt at modifying the calibration
vi /usr/local/jscal.sh
Tried -3064,10064 on axis 3.
:wq!
Opened up the game. This one works quite well! I probably set it a little too high, but at least there's no right hand drift at all, now.
Final file contents:
#!/bin/bash
jscal -s 6,1,0,-3038,3038,16555,16217,1,0,-8,-8,16388,16380,1,0,126,126,4260750,4161663,1,0,-3064,10064,16416,16352,1,0,55,55,16357,-16357,1,0,111,128,4836527,4227201 /dev/input/js0
The following config seems to work well in MC5 to eliminate camera drift while still passing maximum values reasonably close to the original. It still doesn't quite give the proper maximum range, but seems close enough to work well for this game.
#!/bin/bash
jscal -s 6,1,0,237,237,16266,16503,1,0,797,797,16153,16792,1,0,126,126,4260750,4161663,1,0,-3908,3908,18086,18694,1,0,-6989,6989,19894,19904,1,0,122,125,4400447,4129650 /dev/input/js0
TL;DR version: