Modifying hardware key layouts for Android apps on Chrome OS

I recently used an Android terminal emulator on Chrome OS for the first time in a while, and encountered the following issue: although my locale/keyboard settings in CrOS were set to UK, it seemed to be the case that certain Android apps, e.g. terminal emulators were stuck with the US keyboard mappings. Due to this, I found myself mistyping certain characters (mainly @ and "), when switching back and forth between the Chrome OS shell and Termux/Terminal Emulator. 

To fix the keylayout for the locale of my Chromebook's physical keyboard, I modified a couple of files on the rootfs. Although I edited the files directly, which requires a writeable Android system, it's also possible to make a copy, edit the copy, then bind mount it over the original.


Switching the " and @


First way - editing the file directly. Modified (R/W) Android rootfs needed.

With a read/write Android filesystem, as created with the rooting scripts, the easiest way to fix the key layout seemed to be by editing the relevant key mapping file directly. It would be best to make a backup of the file to be edited beforehand.

I opened a root shell in CrOS and entered
vi /opt/google/containers/android/rootfs/root/system/usr/keychars/Generic.kcm
(To swap the " and @ characters, in vi I entered /@ to search Generic.kcm for the @ character, pressed x to delete the @, then pressed i to enter "insert text mode" and typed " to add the quote mark character at the place where the @ had been. I did similar with the " character, replacing it with @)

After modifying the file I saved and quit vi by typing :wq!

I then rebooted the Android container
printf reboot | android-sh
Now, in Termux etc., Shift+2 types the " character, and Shift+' types the @ character, as is expected with a UK keyboard layout. 

Second way - Editing a copy of the file and bind mounting it over the original.

It's also possible to do it without editing the file directly, by copying it out to /usr/local (or to a place accessible within the File Browser such as ~/Downloads) editing the copy, bind mounting it back in place, then rebooting the Android container. In this case, the bind mount and Android reboot have to be redone after every time Chrome OS is rebooted.

i.e.

Either:

To copy the file to /usr/local and edit it with vi, then bind it back: 

Copy the file with permissions preserved
cp -a /opt/google/containers/android/rootfs/root/system/usr/keychars/Generic.kcm /usr/local
Edit the copy e.g. in vi (as above).

Bind mount the file back over the original
mount --bind /usr/local/keychars/generic.kcm /opt/google/containers/android/rootfs/root/system/usr/keychars/Generic.kcm
Then reboot the Android container so it sees the new file
printf reboot | android-sh
Or: 

Alternatively, it might be easier to copy the file to ~/Downloads and edit it with another text editor (e.g. Caret), then move it to /usr/local and bind mount it & reboot Android

Copy the file to ~/Downloads
cp -a /opt/google/containers/android/rootfs/root/system/usr/keychars/Generic.kcm /home/chronos/user/Downloads
After editing the file in text editor, move it to /usr/local/
mv /home/chronos/user/Downloads/Generic.kcm /usr/local/Generic.kcm
Mount bind and then reboot Android as above

Adding the #~ key found on UK keyboards


After swapping the " and @, I still had an issue with the key for # and ~ (located to the left of the Enter key on my UK keyboard). It appeared to have the same mapping in Android as the \ key (to the right of my left Shift key). It turned out that to fix this I had to do two things:

Step 1. Changing key 43 in cros_ec.kl

I found that key 43 and key 86 were both mapped to BACKSLASH at /system/usr/keylayout/cros_ec.kl in the Android container. I had a look at the list of key codes for Android, and decided to change key 43 from BACKSLASH to POUND, since the key code POUND in Android apparently refers to the # key found on phones.

Step 2. Changing the relevant key declaration in Generic.kcm  

then opened the key character map file I'd previously modified (/system/usr/keychars/Generic.kcm), found the key declaration for POUND therein, which looked like this:


key POUND {
    label:                              '#'
    base:                              '#'
}

And added a line for the shift modifier.


key POUND {
    label:                              '#'
    base:                              '#'
    shift:                               '~'
}

 I rebooted Android again, and now my keyboard was finally behaving how I wanted it to in Android terminal apps. 

If anyone is considering making the changes detailed above, or similar, I should mention that Android is quite particular about how it expects these files to be; if the formatting is at all out of place or if an unexpected character is present then Android might fail to load, or revert to a fallback character mapping. If the latter is happening then logcat usually notes the offending line in the problematic file, which can be seen in the output to the following (entered in a CrOS root shell):

printf "logcat | grep key" | android-sh
In  the event of Android failing to load completely and the above command returning an error, if the files had been bind mounted, a reboot would fix it, and if they were edited directly it might be necessary to restore the original file/s from backups.