Using xmodmap to change the keyboard layout

One of the first things I do whenever I get on a new computer is to go the GNOME keyboard preference dialog and switch caps lock and the left control. While this has sufficed in the past, I now have a situation where I’d like to do a more complicated keyboard modification.

Note: The following was done on an Lenovo S10-3t running MeeGo 1.1.

Terminology
A KeyCode is the numerical code for the key. A KeySym is the symbolic code for the key. For example, my Return key has a KeyCode of 36 and a KeySym of Return.

Determining KeyCodes and KeySyms
The first thing to do is to determine the KeyCode and KeySym for the keys your want to change. This can be done by generating a list for all keys or interactively. The former approach is done by issuing the following command.

xmodmap -pke > kbd_mapping.txt

Here I’ve redirected the output to a text file so that I can view the results in a text editor. A small section of the contents look like this.

keycode 36 = Return NoSymbol Return
keycode 37 = Control_L NoSymbol Control_L
keycode 38 = a A a A ae AE
keycode 39 = s S s S ssharp section
keycode 40 = d D d D eth ETH
keycode 41 = f F f F dstroke ordfeminine
keycode 42 = g G g G eng ENG
keycode 43 = h H h H hstroke Hstroke
keycode 44 = j J j J
keycode 45 = k K k K kra ampersand
keycode 46 = l L l L lstroke Lstroke
keycode 47 = semicolon colon semicolon colon dead_acute dead_doubleacute
keycode 48 = apostrophe at apostrophe at dead_circumflex dead_caron

The different columns to the right of the equals sign corrospond to the way modifier keys change the key. Obviously the second column is the effect of the shift key being pressed. As always, the man page is the place to look for more details.

The interactive approach uses the following command.

xev | grep -A 4 KeyPress

Because xev produces a lot of output we use grep to filter only for ‘KeyPress’ events.

Here is some example output

KeyPress event, serial 29, synthetic NO, window 0x2400001,
root 0xaa, subw 0x0, time 3663762, (159,-24), root:(582,207),
state 0x0, keycode 36 (keysym 0xff0d, Return), same_screen YES,
XLookupString gives 1 bytes: (0d)

Here the KeyCode is 36 and the KeySym (also given in hex) is Return.

Once you’ve got the code and symbol combination you want, you you can place them in a file named .Xmodmap. The format for entries is the same as the output from the ‘xmodmap -pke’ command. A section of my file looks like this.
keycode 66 = Control_L NoSymbol Control_L
clear Lock
add Control = Control_L

keycode 135 = ISO_Level3_Shift Multi_key ISO_Level3_Shift Multi_key
keycode 108 = Alt_L Meta_L Alt_L Meta_L

Here I’ve turned my Caps Lock key into a control key. I’ve also moved ‘Alt Gr’ to the menu key and ‘Alt Gr’ is now an additional Alt key. The clear and add commands are necessary to redefine modifier keys. Again, see the man page for more info.

While I’ve put the commands in .Xmodmap so that it’ll persist acrooss restarts, you can also use the ‘xmodmap -e’ to test these changes out. For example, the first 3 commands would look like this.

xmodmap -e 'keycode 66 = Control_L NoSymbol Control_L'
xmodmap -e 'clear Lock'
xmodmap -e 'add Control = Control_L'

On MeeGo and openSUSE the .Xmodmap file is detected at session start. However, I’ve read that’s not always the case. So, consult your distro’s help if you have problems with loading.

Tweets for week ending 2010-11-07

  • Openismus day 100: This is the last daily update. Worked out ConferenceGoer's initial data acquisition class hierarchy. Implementing now. #
  • Openismus day 99: Did some admin stuff. Helped P. Finished off small sample conference schedule. Blogged about Merkmal: http://ur1.ca/29lpv #
  • Openismus day 98: Fleshed out microformats to be used in ConferenceGoer and started making example conference pages to scrape. #
  • Openismus day 97: Did some sketches and wrote down some thoughts for my next small project, ConferenceGoer. Few small changes to Merkmal. #
  • Openismus day 96: Couple small code changes to Merkmal. Released cluttermm 1.1.2 at Murray's behest. Attempted to get GNOME ftp access. #

Introducing Merkmal, a concentration game for GNOME.

For the last few week I’ve been working on a version of GMemory written using the gtkmm and cluttermm bindings. The project is called Merkmal.

Merkmal 0.1.0 screenshot

Currently the functionality is on par with that of GMemory. It requires at least cluttermm 1.1.2, clutter-gtkmm 0.9.6.

Here is a video of Merkmal in action. As you should see, basic game play is working but there are tons of things to be added to make the game more interesting. I listed some of those in the GMemory post.

Merkmal 0.1.0 screencast from Chris Kuehl on Vimeo.

Cluttermm

Now that I’ve ported the game to C++, adding these features should be much easier. However, there are some issues that I’ve been running into. I seem to be among the first (if not the only) consumer of cluttermm at the moment. This has of course meant that I’ve been running into bugs here and there. I’ve fixed the ones I’ve run into. I’ve also started filing bugs for missing api. For example, the new layout classes and animation framework have yet to be wrapped. I’ve filed some bugs for the ones that I’d most like to use.

GNOME Bindings

Having written the same application in both gtk+ and gtkmm, I don’t see why one would not use one of the bindings to write user apps. One of the beauties of GNOME is that there are so many high-quality bindings available. Bindings are a top priority for the project and it shows. With the introspection work that is going on, the situation will only get better.

Tweets for week ending 2010-10-31

  • Openismus day 95: Offered Merkmal up for review. Basically spent the day reworking code based on feedback. Release should be coming soon. #
  • Openismus day 94: Got game play working in Merkmal now. Also cherry-picked Fridays fixes in cluttermm master to cluttermm-1.2 branch. #
  • Openismus day 93: Reworked some code and got cards responding to clicks and such in Merkmal. Game play should be be working very soon. #
  • Openismus day 92: Got initial layout and card interaction working as well as logic for menu item sensitivity implemented for Merkmal. #
  • Openismus day 91: Had to backport my patch from yesterday to cluttermm tarball due to crashes using master. Moving forward w/ Merkmal now. #

Tweets for week ending 2010-10-24

  • Openismus day 90: Filed bug http://ur1.ca/25b19 for cluttermm issue. murrayc helped fix my bad patch. Merkmal layout code almost finished. #
  • Openismus day 89: Made progess on Merkmal until I ran into an issue initializing a Clutter::Cairo::Texture. Found the problem @ end off day. #
  • Openismus day 88: Back from baby leave! Caught up on email. Helped P w/ her app. Got back to full speed on my Merkmal game. #

Tweets for week ending 2010-10-10

  • Openismus day 87: Made changes to Merkmal that Murray proposed. RefPtr'd objects. Son, Rigby, born. #

Tweets for week ending 2010-10-03

  • Openismus day 86: Got initial class structure of Merkmal compiling and commited. Doesn't do anything and still needs considerable changes. #
  • Openismus day 85: More Merkmal hacking. Detour into what it would take to build clutter-gtk to gtk3. Reviewed signals and refptr's in gtkmm. #
  • Openismus day 84: Remember kids, if you wanna waste time w/ weird errors just forget to call clutter's init function in your clutter app. :( #
  • Openismus day 83: Small change to clutter-gtkmm: http://ur1.ca/1ur4h. Fought with jhbuild a bit. Getting weird error in Merkmal. #
  • Openismus day 82: Learning more Gtkmm. Added menus and toolbar using UIManager and Actions. http://ur1.ca/1sh08 Started basic Clutter stuff. #
  • Openismus day 81: Read 2nd half of Clutter Cookbook. Got Merkmal into Gitorious… just autotools and i18n stuff. Signed up for MeeGo conf.! #

Tweets for week ending 2010-09-26

  • Openismus day 80: Accompanied Vada to 2nd day of pre-school. Small jhbuild dep fix. Started on gmemory C++ port. Dinner with #ds2011 team. #
  • Openismus day 79: Read half of http://ur1.ca/1rhny. Spent rest of day in #ds2011 kick-off meeting. Tried to fix some gtkmm build issues. #
  • Openismus day 78: Fixed another small bug in cluttermm_tutorial. Set up Merkmal project. Spent rest of time with jhbuild issues. #
  • Openismus day 77: Fixed another example in cluttermm tutorial. http://ur1.ca/1pgel Wrote a blog post. http://ur1.ca/1pge5 Ate PB&J sandwich. #

Debugging reference counting in GNOME C++ bindings with GDB

Overview

For the last couple days I’ve been tracking down some reference counting problems in cluttermm. In the course of this I’ve been working on figuring out how GDB can help me do this. Here is what I’ve come up with. If you have improvements please let me know.

Watching the reference count variable

The first small obstacle is that pretty much all objects are wrapped in a RefPtr, glibmm‘s reference-counting shared smartpointers. This is a good thing and gdb makes accessing the underlying C++ object pretty painless. The following command demonstrates this.

p alpha.pCppObject_

For this example I’m using the alpha variable of type Glib::RefPtr<Clutter::Alpha>. In this command we used the fact that gdb gives you access to any member of a class, whether public or private. You should have gotten output similar to the following.

$1 = (Clutter::Alpha *) 0x9cfe40

Now the interesting part. We want to detect any changes in the ref_count variable. To do this we need to watch the ref_count field. The following command does this.

watch alpha.pCppObject_->gobject_->ref_count

To make this a bit more convenient, I’ve used the gdb define command to create a shortcut. Here is an example session.

(gdb) define watchRefCnt
Type commands for definition of "watchRefCnt".
End with a line saying just "end".
>watch ($arg0).pCppObject_->gobject_->ref_count
>end

Now you just need to use the shortcut like this.

watchRefCnt alpha

Which should give you a confirmation similar to the following.

Hardware watchpoint 2: (alpha).pCppObject_->gobject_->ref_count

The obvious thing to do next is to place this command in a .gdbinit file so that it can be pulled in automatically.

Breaking on last unreference

One of things I was most interested in catching was when the g_object_unref function was called with the condition that the _object pointer was equal to a certian pointer and the ref_count variable == 1. This would indicate that the object is ready to be disposed. To do this we first need to get the address of the underlying GObject like this.

(gdb) p alpha.pCppObject_->gobject_
$3 = (GObject *) 0x9c91e0

You now have a convenience variable, $3, which you can use in the conditions. You then need to set a breakpoint on g_object_unref and set the conditions like this.

b g_object_unref
cond 4 _object==$3&&((GObject*)$3)->ref_count==1

This, of course, would also be nice as a custom command. I’ll leave that as an exercise for the reader. ;)

Future explorations

I forsee future blog entries along these lines so stay tuned. There are quite a few things that interest me in gdb right now.

The Archer project is quickly improving C++ support in gdb. I’ve been using gdb 7.2 for my debugging as I wanted to have a stable debugging platform with all the new C++ enhancements. They have a git repository for those who want the bleeding edge.

Python scripting has been available in gdb since 7.0. I plan on looking into this as a way of streamlining debugging tasks and honing my Python skills which are pretty rusty.

Please let me know if you see any areas for improvement.

Tweets for week ending 2010-09-19

  • Openismus day 76: murrayc showed me the proper way to fix cluttermm bug. Committed fix for that and a few other issues. http://ur1.ca/1o8sp #
  • Openismus day 75: Found the problem with cluttermm. Clutter::Alpha::get_timeline() was the culprit. Came up with a fix that worked. #
  • Openismus day 74: Went thru clutter code to see what tutorial program is doing. emacs+gdb+gtags (GNU Global) is nice for this. More gdb too. #
  • Openismus day 73: Took a bit of a detour to go deeper into gdb. Think I've pretty much gone though the entire manual. Back to cluttermm bug. #
  • Openismus day 72: Struggling with the bug in cluttermm. Maybe I should first understand what the clutter c code is doing. ;) #
  • Openismus day 71: Learned to use gdb to debug reference counting issues in GObject-based code. http://ur1.ca/1lrpi & comments were helpful. #