Nexus 7 Bluetooth Keyboard and UK Layout

I’ve really been enjoying playing with my Nexus 7 but have discovered a slight problem. I decided to purchase a bluetooth keyboard and so grabbed myself a Perixx PERIBOARD-804. This won out over the Zagg Keys Flex and the Logitech keyboards thanks to compact size, internal USB-rechargeable battery and UK keyboard layout. Unfortunately, while testing this out on the Nexus 7 I discovered that the Nexus doesn’t come with UK keyboard layouts for external keyboards. I haven’t been this annoyed by a keyboard layout since I bought a Mac. Anyway, after a bit of digging around online I found that it’s possible (with root) to upload a custom character mapping for my device to make it work as expected. You can read more about the specs of these files over at the Android Open Source Project.

New Configuration

Two files need to be created to ensure that all the buttons work as expected:

  • A Keyboard Layout which defines which android key code results from a key press.  This lives in /system/usr/keylayout and is named Vendor_<VendorID>_Product_<ProductID>.kl
  • A Key Character Map which defines which android key code produces which character (with modifiers).  This lives in /system/usr/keychars and is named Vendor_<VendorID>_Product_<ProductID>.kcm
Each of these locations contains a Generic.kl/Generic.kcm file that can be used as a template for any changes. These files are used when no other suitable configuration is present so I suggest not editing them directly, or at least backing them up.

Identifying the Device

The VendorID and ProductID in the filenames are used to match the configuration to the specific device.  With the keyboard connected this can be found in a shell (adb or on device) by looking in /proc/bus/input/devices.

shell@android:/ $ cat /proc/bus/input/devices
...
I: Bus=0005 Vendor=04f2 Product=1063 Version=0505
N: Name="Bluetooth Keyboard                   "
P: Phys=10:BF:48:F3:8B:E2
S: Sysfs=/devices/platform/tegra_uart.2/tty/ttyHS2/hci0/hci0:12/input4
U: Uniq=90:7F:61:8E:78:A4
H: Handlers=sysrq event3 keychord
B: PROP=0
B: EV=12001f
B: KEY=4c37fff 72ff32d bf544456 0 0 1 30f90 8b17c007 ffff7bfa d951dfff febeffdf ffefffff ffffffff fffffffe
B: REL=40
B: ABS=101 30000
B: MSC=10
B: LED=1f

Here my Vendor ID is 042f and my Product ID is 1063. Once you’ve created your baseline files by copying (adb pull is your friend) the generic configuration and renaming to match your Vendor & Product IDs you can jump into them and make the changes you require.

Changing Keys

In my case most of the work was in the key character map file (moving quote marks, tilde, etc.) and you may not need to make any changes to the keyboard layout at all. One change I had to make was to support the # key on a UK keyboard (which has the ~ character above it). The generic keyboard layout was sending it as a backslash, along with the actual backslash key. To find which key to change I needed to know the shortcode being sent by the keyboard and for this you can use KeyTest.apk made by Chris Boyle. This app will run and report the short code for all key presses so you can hunt down the one you’re interested in. In my case this meant changing key 43 BACKSLASH to key 43 POUND in my layout file and then putting a corresponding entry in my key character map:

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

Note that this format for the character map is supported from Android 3.0+ (the Nexus 7 is on 4.1 at the time of writing). It’s worth digging into the documentation to read up on the various modifier keys you can react to. Power users may decide that they want alt characters for all of their keys to produce special characters. The AOSP docs explain a bit more about any escape characters you might need to use in special cases as well as how to represent more exotic characters as unicode code points. Wikipedia should serve to provide a reference for the latter.

Installation

Once you’re done with your new configuration you’ll want to deploy this to your device. I did all of this using adb as follows.

  1. Put my new configuration in two local directories: keylayout and keychars
  2. Create a keyboard folder in the root of your /sdcard partition.
  3. adb push your configuration to the device:
    adb push keylayout /sdcard/keyboard/keylayout
    adb push keychars /sdcard/keyboard/keychars
  4. Launch adb shell and run the following commands:
    su
    mount -o remount rw /system
    cat /sdcard/keyboard/keylayout/Vendor_04f2_Product_1063.kl > /system/usr/keylayout/Vendor_04f2_Product_1063.kl
    cat /sdcard/keyboard/keychars/Vendor_04f2_Product_1063.kcm > /system/usr/keychars/Vendor_04f2_Product_1063.kcm
    chmod 644 /system/usr/keychars/Vendor_04f2_Product_1063.kcm
    chmod 644 /system/usr/keylayout/Vendor_04f2_Product_1063.kl
    reboot
  5. Wait for your device to reboot
  6. Profit

Profit

Voila! You should now have a working keyboard layout for your device! If you’ve also got the Perixx 804 then you can take my configuration files from a repo on GitHub. Please feed back any mistakes you find and shout if you’d like any more layouts uploaded. If I have time I might try to get an app together for installing any configs from git and/or editing these config files on the device.

Troubleshooting

If you’re trying to do this yourself and having difficulty troubleshooting what’s happening, keep an eye on adb logcat when you’re connecting your bluetooth device. A message should appear telling you which layout and character map files are being used. This helped me identify what was failing on my first attempt and I eventually tracked a problem to a duplicate definition for POUND in the character map.

A shout out to this post on the Thrive forums for getting me on the right track.

 

Spending Time to Save Time: Automating My Builds

As a one man developer it’s very easy to fall into patterns of bad habits with the development process.  I don’t have a team to worry about, I’m not beholden to any code reviews or quality metrics and it’s just me and my PC, so why go the extra mile to do things right?  Some things have clear benefits and such a small up-front effort requirement that they’re a no brainer.  I have a svn repo running on my NAS and this has saved me many a time – do not underestimate the sinking feeling you will get when you realise the drive that just failed in your PC was the one with your dev environment on it.  Even if you don’t have a seperate server for source control, it may be worth considering a local install and then regular dumps of your repository to external storage.

OK, so that was quite an easy example.  Job done, point justified right?  Well, not quite.  I’d like to share an example of another area where a little bit of upfront effort has made my life easier: automation in the build process.  Now, to be clear, I’m not talking about a full end to end build process / CI here.  At the moment I don’t see the value in that beyond providing me with an excuse to spend money on a server.  Any changes I’m making in code I’ll be immediately deploying to either a simulator or device depending on my current requirement.  There is, however, one key part of my build process that needed some automation and that’s creating art resources.

I’ve written before about the tools I use to create sprites: Inkscape, Blender and TexturePacker Pro (with a splash of Paint.NET) all come together nicely as a toolbox for those who aren’t up to creating graphics by hand.  The thing is, when I want to tweak a sprite, change something completely, add something new or provide assets for multiple resolutions I have to go through a hell of a process to manually deploy this to a build.  Let’s take creating a new menu button as an example:

  1. Create the menu button in Inkscape
  2. Save this somewhere sensible that I’ll find again later
  3. Export the region I want at a scale for the app sizes I want (1080p, 720p, SD, etc.)
  4. Store these exported files somewhere
  5. Open up the texture atlas definitions for each app size and add the new assets
  6. Export the new texture atlases and their indexes and save these somewhere
  7. Copy the new atlases into each project that uses them and rebuild

The process doesn’t differ much for making small changes to existing sprites.  As you can imagine, this results in me looking at to-do items demanding I perform a bit of an art clean-up, sighing and then ignoring them in favour of playing with some new code.  Not a great position to be in. Looking at the above process, there’s clearly a lot of scope for automation and process improvement.  I’ve probably made a lot of things more difficult than they need to be as this was my first project.  Luckily, all of the apps I use come with command line functionality that provides what I need to make my life easier.  By making a few design decisions I now have a three step process:

  1. Create / edit Inkscape / Blender files
  2. Run batch script
  3. Rebuild apps

Nice eh?  To do this I’ve set up my environment in the following way:

  • All projects now look for texture atlases in a root project folder called Resource[X]\textures where the [X] is a number indicating whether the resources are HD or not
  • All Inkscape / Blender files are designed with the assumption of a HD screen to display on and placed in a Textures path within the project directory
  • Sub directories within the Textures path group the texture source files together by theme (uicontrols, menus, decorations)

The batch script (Windows version attached) iterates over each sub-directory and uses Inkscape and Blender to output full resolution PNG exports of each file to a temporary directory, divided up with the same sub-folder structure.  TexturePacker Pro is then used to create an atlas from each of these sub-directories.  This is run three times as TexturePacker Pro will handle reducing the size of the atlases for the different resource sets (I use three multipliers – 1, 0.7 and 0.5).  All that is then left in code is to import the atlases and refer to the textures within by name.  While the process could certainly be made more efficient (by not re-working items with no changes), this isn’t necessary for my personal needs.

If you want to look at the details of the arguments I use on the command line, grab the batch script and take a read.  It’s not amazingly complicated but the effort required to create it more than pays for itself.

The script: generate_svg_to_png

 

Yet Again OS X Pokes Me In The Eye (or OS X Environment Variables)

I bought myself a Macbook Air last year to replace my ageing laptop. The theory was that I’d be using cross platform apps so the underlying system didn’t matter. Or rather it didn’t matter enough to outweigh the pretty 🙂

Anyway, not all of the niggles I have are down to OS X (Apple’s “we must have our own way” GB keyboard is bloody awful and seems designed to piss off developers), but many are and I’ve just come across another. Trying to set consistent environment variables across all apps, regardless of whether terminal based or launched from an icon is an absolute mess. Worse still, Apple doesn’t seem to offer any standard friendly configuration methods for environment variables. Pricks. Anyway, the best resource for troubleshooting these that I’ve found recently is this post on stackoverflow. I’ve reproduced it below in order to ensure it is captured and kept!

There are several places where you can set environment variables.

  • ~/.profile: use this for variables you want to set in all programs launched from the terminal (note that, unlike on Linux, all shells opened in Terminal.app are login shells).
  • ~/.bashrc: this is invoked for shells which are not login shells. Use this for aliases and other things which need to be redefined in subshells, not for environment variables that are inherited.
  • /etc/profile: this is loaded before ~/.profile, but is otherwise equivalent. Use it when you want the variable to apply to terminal programs launched by all users on the machine (assuming they use bash).
  • ~/.MacOSX/environment.plist: this is read by loginwindow on login. It applies to all applications, including GUI ones, except those launched by Spotlight in 10.5 (not 10.6). It requires you to logout and login again for changes to take effect. There is no reason to use this one any more.
  • ~/.launchd.conf: this is read by launchd when the user logs in. It applies to all programs launched by the user, GUI and CLI, on 10.5 and 10.6. Additionally, you can apply changes at any time by piping this file into launchctl (maybe grep ^setenv first if you have other commands you don’t want to run). Then the new variables apply to any application launched by launchd from that point on. This means you should restart Terminal.app for the new variables to cascade down into the shells it launches.
  • /etc/launchd.conf: this is read by launchd when the system starts up and when a user logs in. They affect every single process on the system, because launchd is the root process. Again, to apply changes to the running root launchd you can pipe the commands into sudo launchctl.

The fundamental things to understand are:

  • environment variables are inherited by a process’s children at the time they are forked.
  • the root process is a launchd instance, and there is also a separate launchd instance per user session.
  • launchd allows you to change its current environment variables using launchctl; the updated variables are then inherited by all new processes it forks from then on.

Sample setting an environment variable with launchd and storing it into your personal config so it works for your login even after your reboot:

echo setenv REPLACE_WITH_VAR REPLACE_WITH_VALUE >> ~/.launchd.conf
echo setenv REPLACE_WITH_VAR REPLACE_WITH_VALUE | launchctl

Now, launch your GUI app that uses the variable, and voila!