I am trying to catch user key press Ctrl+d on a GUI window to quit. My code looks like this:
static gboolean
callback(GtkWidget *widget,
GdkEventKey *event,
gpointer data)
{
if(event->state == GDK_CONTROL_MASK && event->keyval == 'd')
gtk_main_quit();
return FASLE;
}
This works on my laptop(Ubuntu 11.04, gcc 4.5.2, libgtk 2.24.4). But when I do the same thing on a newer system(Ubuntu 12.10, gcc 4.7.2, libgtk 2.24.13), it doesn't work.
I added g_print("%u\n", event->state);
before the if
statement, it shows that when I press Ctrl
, the event->state
is 20 instead of 4 or 1 << 2 in the documentation. If I change the GDK_CONTROL_MASK
to 20, it works on the newer system but not the old one. Someone please tell me why this happen and how to fix it.
event->state
is a bitmap, which means that a value of 20 doesn't mean "20 instead of 4", but "4 and 16 at the same time". According to the headers, the value 16 (1 << 4
) corresponds to the MOD2
modifier, which might correspond to the fn key present on laptops.
A simple fix is to use the &
operator to check for control while ignoring other modifiers:
if (event->state & GDK_CONTROL_MASK && event->keyval == 'd')
which will work on both systems.
This happens because state
also includes modifiers like Caps Lock and Num Lock.
The solution is documented at https://developer.gnome.org/gtk3/stable/checklist-modifiers.html:
Use gtk_accelerator_get_default_mod_mask()
to get a bitmap of the modifiers that are also accelerator keys (Control, Alt, Shift, Super, Hyper, and Meta), then bitwise and the event state, e.g.:
GdkModifierType accel_mask = gtk_accelerator_get_default_mod_mask ();
if (event->state & accel_mask == GDK_CONTROL_MASK && event->keyval == 'd')
...