Added a pop-up menu when pressing a key (with configurable font)

This commit is contained in:
Pierre Pronchery 2010-07-26 17:24:41 +00:00
parent d40372d163
commit 7c0c2ad1ff
5 changed files with 185 additions and 85 deletions

View File

@ -42,21 +42,21 @@ gboolean on_keyboard_delete_event(gpointer data)
void on_keyboard_key_clicked(gpointer data, GtkWidget * key) void on_keyboard_key_clicked(gpointer data, GtkWidget * key)
{ {
Keyboard * keyboard = data; Keyboard * keyboard = data;
unsigned int * keysym; KeyboardKey * kk;
unsigned int keycode; unsigned int keycode;
Display * display; Display * display;
gboolean upper; gboolean upper;
if((kk = g_object_get_data(G_OBJECT(key), "key")) == NULL)
return;
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%p, \"%s\")\n", __func__, keyboard, fprintf(stderr, "DEBUG: %s(%p, \"%s\")\n", __func__, keyboard,
gtk_button_get_label(GTK_BUTTON(key))); kk->label);
#endif #endif
if((keysym = g_object_get_data(G_OBJECT(key), "keysym")) == NULL)
return;
display = gdk_x11_get_default_xdisplay(); display = gdk_x11_get_default_xdisplay();
keycode = XKeysymToKeycode(display, *keysym); keycode = XKeysymToKeycode(display, kk->keysym);
XTestGrabControl(display, True); XTestGrabControl(display, True);
if(*keysym == XK_Shift_L || *keysym == XK_Shift_R) if(kk->keysym == XK_Shift_L || kk->keysym == XK_Shift_R)
{ {
upper = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(key)); upper = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(key));
XTestFakeKeyEvent(display, keycode, upper ? True : False, 0); XTestFakeKeyEvent(display, keycode, upper ? True : False, 0);
@ -69,3 +69,29 @@ void on_keyboard_key_clicked(gpointer data, GtkWidget * key)
} }
XTestGrabControl(display, False); XTestGrabControl(display, False);
} }
/* on_keyboard_key_pressed */
gboolean on_keyboard_key_pressed(GtkWidget * key, GdkEventButton * event,
gpointer data)
{
Keyboard * keyboard = data;
KeyboardKey * kk;
if((kk = g_object_get_data(G_OBJECT(key), "key")) != NULL)
keyboard_key_show(keyboard, kk, TRUE);
return FALSE;
}
/* on_keyboard_key_released */
gboolean on_keyboard_key_released(GtkWidget * key, GdkEventButton * event,
gpointer data)
{
Keyboard * keyboard = data;
KeyboardKey * kk;
if((kk = g_object_get_data(G_OBJECT(key), "key")) != NULL)
keyboard_key_show(keyboard, kk, FALSE);
return FALSE;
}

View File

@ -25,5 +25,9 @@
/* functions */ /* functions */
gboolean on_keyboard_delete_event(gpointer data); gboolean on_keyboard_delete_event(gpointer data);
void on_keyboard_key_clicked(gpointer data, GtkWidget * key); void on_keyboard_key_clicked(gpointer data, GtkWidget * key);
gboolean on_keyboard_key_pressed(GtkWidget * key, GdkEventButton * event,
gpointer data);
gboolean on_keyboard_key_released(GtkWidget * key, GdkEventButton * event,
gpointer data);
#endif /* !KEYBOARD_CALLBACKS_H */ #endif /* !KEYBOARD_CALLBACKS_H */

View File

@ -28,87 +28,81 @@
/* Keyboard */ /* Keyboard */
/* private */ /* private */
/* types */ /* types */
typedef struct _KeyboardKey
{
GtkWidget * widget;
unsigned int keysym;
char const * label;
char const * upper_label;
} KeyboardKey;
struct _Keyboard struct _Keyboard
{ {
KeyboardKey * layout[4]; KeyboardKey * layout[4];
PangoFontDescription * bold;
GtkWidget * window; GtkWidget * window;
GdkRectangle geometry;
}; };
/* variables */ /* variables */
static KeyboardKey _1234567890[] = static KeyboardKey _1234567890[] =
{ {
{ NULL, XK_Escape, "Esc", NULL }, { NULL, NULL, XK_Escape, "Esc", NULL },
{ NULL, XK_1, "1", NULL }, { NULL, NULL, XK_1, "1", NULL },
{ NULL, XK_2, "2", NULL }, { NULL, NULL, XK_2, "2", NULL },
{ NULL, XK_3, "3", NULL }, { NULL, NULL, XK_3, "3", NULL },
{ NULL, XK_4, "4", NULL }, { NULL, NULL, XK_4, "4", NULL },
{ NULL, XK_5, "5", NULL }, { NULL, NULL, XK_5, "5", NULL },
{ NULL, XK_6, "6", NULL }, { NULL, NULL, XK_6, "6", NULL },
{ NULL, XK_7, "7", NULL }, { NULL, NULL, XK_7, "7", NULL },
{ NULL, XK_8, "8", NULL }, { NULL, NULL, XK_8, "8", NULL },
{ NULL, XK_9, "9", NULL }, { NULL, NULL, XK_9, "9", NULL },
{ NULL, XK_0, "0", NULL }, { NULL, NULL, XK_0, "0", NULL },
{ NULL, XK_BackSpace, "\xe2\x8c\xab", NULL }, { NULL, NULL, XK_BackSpace, "\xe2\x8c\xab", NULL },
{ NULL, 0, NULL, NULL } { NULL, NULL, 0, NULL, NULL }
}; };
static KeyboardKey _qwertyuiop[] = static KeyboardKey _qwertyuiop[] =
{ {
{ NULL, XK_Tab, "Tab", NULL }, { NULL, NULL, XK_Tab, "\xe2\x86\x92|", NULL },
{ NULL, XK_Q, "q", "Q" }, { NULL, NULL, XK_Q, "q", "Q" },
{ NULL, XK_W, "w", "W" }, { NULL, NULL, XK_W, "w", "W" },
{ NULL, XK_E, "e", "E" }, { NULL, NULL, XK_E, "e", "E" },
{ NULL, XK_R, "r", "R" }, { NULL, NULL, XK_R, "r", "R" },
{ NULL, XK_T, "t", "T" }, { NULL, NULL, XK_T, "t", "T" },
{ NULL, XK_Y, "y", "Y" }, { NULL, NULL, XK_Y, "y", "Y" },
{ NULL, XK_U, "u", "U" }, { NULL, NULL, XK_U, "u", "U" },
{ NULL, XK_I, "i", "I" }, { NULL, NULL, XK_I, "i", "I" },
{ NULL, XK_O, "o", "O" }, { NULL, NULL, XK_O, "o", "O" },
{ NULL, XK_P, "p", "P" }, { NULL, NULL, XK_P, "p", "P" },
{ NULL, XK_Return, "Ret", NULL }, { NULL, NULL, XK_Return, "Ret", NULL },
{ NULL, 0, NULL, NULL } { NULL, NULL, 0, NULL, NULL }
}; };
static KeyboardKey _asdfghjkl[] = static KeyboardKey _asdfghjkl[] =
{ {
{ NULL, XK_Caps_Lock, "Caps", NULL }, { NULL, NULL, XK_Caps_Lock, "Caps", NULL },
{ NULL, XK_A, "a", "A" }, { NULL, NULL, XK_A, "a", "A" },
{ NULL, XK_S, "s", "S" }, { NULL, NULL, XK_S, "s", "S" },
{ NULL, XK_D, "d", "D" }, { NULL, NULL, XK_D, "d", "D" },
{ NULL, XK_F, "f", "F" }, { NULL, NULL, XK_F, "f", "F" },
{ NULL, XK_G, "g", "G" }, { NULL, NULL, XK_G, "g", "G" },
{ NULL, XK_H, "h", "H" }, { NULL, NULL, XK_H, "h", "H" },
{ NULL, XK_J, "j", "J" }, { NULL, NULL, XK_J, "j", "J" },
{ NULL, XK_K, "k", "K" }, { NULL, NULL, XK_K, "k", "K" },
{ NULL, XK_L, "l", "L" }, { NULL, NULL, XK_L, "l", "L" },
{ NULL, XK_colon, ":", NULL }, { NULL, NULL, XK_colon, ":", NULL },
{ NULL, XK_at, "@", NULL }, { NULL, NULL, XK_at, "@", NULL },
{ NULL, 0, NULL, NULL } { NULL, NULL, 0, NULL, NULL }
}; };
static KeyboardKey _zxcvbnm[] = static KeyboardKey _zxcvbnm[] =
{ {
{ NULL, XK_Shift_L, "\xe2\x87\xa7", NULL }, { NULL, NULL, XK_Shift_L, "\xe2\x87\xa7", NULL },
{ NULL, XK_Z, "z", "Z" }, { NULL, NULL, XK_Z, "z", "Z" },
{ NULL, XK_X, "x", "X" }, { NULL, NULL, XK_X, "x", "X" },
{ NULL, XK_C, "c", "C" }, { NULL, NULL, XK_C, "c", "C" },
{ NULL, XK_V, "v", "V" }, { NULL, NULL, XK_V, "v", "V" },
{ NULL, XK_B, "b", "B" }, { NULL, NULL, XK_B, "b", "B" },
{ NULL, XK_N, "n", "N" }, { NULL, NULL, XK_N, "n", "N" },
{ NULL, XK_M, "m", "M" }, { NULL, NULL, XK_M, "m", "M" },
{ NULL, XK_space, " ", NULL }, { NULL, NULL, XK_space, " ", NULL },
{ NULL, XK_period, ".", NULL }, { NULL, NULL, XK_period, ".", NULL },
{ NULL, XK_minus, "-", NULL }, { NULL, NULL, XK_minus, "-", NULL },
{ NULL, XK_slash, "/", NULL }, { NULL, NULL, XK_slash, "/", NULL },
{ NULL, 0, NULL, NULL } { NULL, NULL, 0, NULL, NULL }
}; };
@ -118,10 +112,9 @@ static KeyboardKey _zxcvbnm[] =
Keyboard * keyboard_new(KeyboardPrefs * prefs) Keyboard * keyboard_new(KeyboardPrefs * prefs)
{ {
Keyboard * keyboard; Keyboard * keyboard;
KeyboardKey * kk;
GdkScreen * screen; GdkScreen * screen;
GdkRectangle rect;
gint height; gint height;
PangoFontDescription * bold;
GtkWidget * vbox; GtkWidget * vbox;
GtkWidget * hbox; GtkWidget * hbox;
GtkWidget * widget; GtkWidget * widget;
@ -142,34 +135,48 @@ Keyboard * keyboard_new(KeyboardPrefs * prefs)
screen = gdk_screen_get_default(); screen = gdk_screen_get_default();
if(prefs != NULL && prefs->monitor > 0 if(prefs != NULL && prefs->monitor > 0
&& prefs->monitor < gdk_screen_get_n_monitors(screen)) && prefs->monitor < gdk_screen_get_n_monitors(screen))
gdk_screen_get_monitor_geometry(screen, prefs->monitor, &rect); gdk_screen_get_monitor_geometry(screen, prefs->monitor,
&keyboard->geometry);
else else
gdk_screen_get_monitor_geometry(screen, 0, &rect); gdk_screen_get_monitor_geometry(screen, 0, &keyboard->geometry);
height = rect.width / 8; height = (keyboard->geometry.width / 12) * 3;
gtk_widget_set_size_request(keyboard->window, rect.width, height); gtk_widget_set_size_request(keyboard->window, keyboard->geometry.width,
gtk_window_move(GTK_WINDOW(keyboard->window), rect.x, height);
rect.y + rect.height - height); gtk_window_move(GTK_WINDOW(keyboard->window), keyboard->geometry.x,
keyboard->geometry.y + keyboard->geometry.height
- height);
g_signal_connect_swapped(G_OBJECT(keyboard->window), "delete-event", g_signal_connect_swapped(G_OBJECT(keyboard->window), "delete-event",
G_CALLBACK(on_keyboard_delete_event), keyboard); G_CALLBACK(on_keyboard_delete_event), keyboard);
/* layouts */ /* layouts */
bold = pango_font_description_new(); if(prefs->font != NULL)
pango_font_description_set_weight(bold, PANGO_WEIGHT_BOLD); keyboard->bold = pango_font_description_from_string(
prefs->font);
else
keyboard->bold = pango_font_description_new();
pango_font_description_set_weight(keyboard->bold, PANGO_WEIGHT_BOLD);
vbox = gtk_vbox_new(TRUE, 4); vbox = gtk_vbox_new(TRUE, 4);
for(i = 0; i < 4; i++) for(i = 0; i < 4; i++)
{ {
hbox = gtk_hbox_new(TRUE, 4); hbox = gtk_hbox_new(TRUE, 4);
for(j = 0; keyboard->layout[i][j].label != NULL; j++) for(j = 0; keyboard->layout[i][j].label != NULL; j++)
{ {
if(keyboard->layout[i][j].keysym == XK_Shift_L) kk = &keyboard->layout[i][j];
if(kk->keysym == XK_Shift_L || kk->keysym == XK_Shift_R)
widget = gtk_toggle_button_new(); widget = gtk_toggle_button_new();
else else
widget = gtk_button_new(); widget = gtk_button_new();
label = gtk_label_new(keyboard->layout[i][j].label); label = gtk_label_new(kk->label);
keyboard->layout[i][j].widget = label; kk->widget = label;
gtk_widget_modify_font(label, bold); gtk_widget_modify_font(label, keyboard->bold);
gtk_container_add(GTK_CONTAINER(widget), label); gtk_container_add(GTK_CONTAINER(widget), label);
g_object_set_data(G_OBJECT(widget), "keysym", g_object_set_data(G_OBJECT(widget), "key", kk);
&keyboard->layout[i][j].keysym); g_signal_connect(G_OBJECT(widget), "button-press-event",
G_CALLBACK(on_keyboard_key_pressed),
keyboard);
g_signal_connect(G_OBJECT(widget),
"button-release-event", G_CALLBACK(
on_keyboard_key_released),
keyboard);
g_signal_connect_swapped(G_OBJECT(widget), "clicked", g_signal_connect_swapped(G_OBJECT(widget), "clicked",
G_CALLBACK(on_keyboard_key_clicked), G_CALLBACK(on_keyboard_key_clicked),
keyboard); keyboard);
@ -180,7 +187,6 @@ Keyboard * keyboard_new(KeyboardPrefs * prefs)
} }
gtk_container_add(GTK_CONTAINER(keyboard->window), vbox); gtk_container_add(GTK_CONTAINER(keyboard->window), vbox);
gtk_widget_show_all(keyboard->window); gtk_widget_show_all(keyboard->window);
pango_font_description_free(bold);
return keyboard; return keyboard;
} }
@ -189,6 +195,7 @@ Keyboard * keyboard_new(KeyboardPrefs * prefs)
void keyboard_delete(Keyboard * keyboard) void keyboard_delete(Keyboard * keyboard)
{ {
gtk_widget_destroy(keyboard->window); gtk_widget_destroy(keyboard->window);
pango_font_description_free(keyboard->bold);
free(keyboard); free(keyboard);
} }
@ -223,3 +230,51 @@ void keyboard_show(Keyboard * keyboard, gboolean show)
else else
gtk_widget_hide(keyboard->window); gtk_widget_hide(keyboard->window);
} }
/* keyboard_key_show */
void keyboard_key_show(Keyboard * keyboard, KeyboardKey * key, gboolean show)
{
GtkWidget * widget;
unsigned int bwidth;
unsigned int bheight;
size_t i;
size_t j;
if(show == FALSE)
{
if(key->popup != NULL)
gtk_widget_destroy(key->popup);
key->popup = NULL;
return;
}
if(key->popup == NULL)
{
key->popup = gtk_window_new(GTK_WINDOW_POPUP);
widget = gtk_button_new_with_label(key->upper_label != NULL?
key->upper_label : key->label);
gtk_widget_modify_font(gtk_bin_get_child(GTK_BIN(widget)),
keyboard->bold);
bwidth = keyboard->geometry.width / 12;
bheight = (bwidth / 4) * 3;
gtk_widget_set_size_request(key->popup, bwidth, bheight * 2);
gtk_container_add(GTK_CONTAINER(key->popup), widget);
}
for(i = 0; i < 4; i++)
{
for(j = 0; keyboard->layout[i][j].label != NULL; j++)
if(&keyboard->layout[i][j] == key)
break;
if(keyboard->layout[i][j].label != NULL)
break;
}
if(i == 4 && j == 12) /* XXX hard-coded */
{
i = 0;
j = 5;
}
gtk_window_move(GTK_WINDOW(key->popup), bwidth * j,
keyboard->geometry.height - (bheight * 6)
+ (bheight * i));
gtk_widget_show_all(key->popup);
}

View File

@ -25,9 +25,19 @@
/* types */ /* types */
typedef struct _Keyboard Keyboard; typedef struct _Keyboard Keyboard;
typedef struct _KeyboardKey
{
GtkWidget * widget;
GtkWidget * popup;
unsigned int keysym;
char const * label;
char const * upper_label;
} KeyboardKey;
typedef struct _KeyboardPrefs typedef struct _KeyboardPrefs
{ {
int monitor; int monitor;
char const * font;
} KeyboardPrefs; } KeyboardPrefs;
typedef enum _KeyboardCase { KC_LOWER, KC_UPPER } KeyboardCase; typedef enum _KeyboardCase { KC_LOWER, KC_UPPER } KeyboardCase;
@ -43,4 +53,6 @@ void keyboard_set_case(Keyboard * keyboard, KeyboardCase kcase);
/* useful */ /* useful */
void keyboard_show(Keyboard * keyboard, gboolean show); void keyboard_show(Keyboard * keyboard, gboolean show);
void keyboard_key_show(Keyboard * keyboard, KeyboardKey * key, gboolean show);
#endif /* !KEYBOARD_KEYBOARD_H */ #endif /* !KEYBOARD_KEYBOARD_H */

View File

@ -28,7 +28,7 @@
/* usage */ /* usage */
static int _usage(void) static int _usage(void)
{ {
fputs("Usage: keyboard [-m monitor]\n", stderr); fputs("Usage: keyboard [-f font][-m monitor]\n", stderr);
return 1; return 1;
} }
@ -45,9 +45,12 @@ int main(int argc, char * argv[])
memset(&prefs, 0, sizeof(prefs)); memset(&prefs, 0, sizeof(prefs));
gtk_init(&argc, &argv); gtk_init(&argc, &argv);
while((o = getopt(argc, argv, "m:")) != -1) while((o = getopt(argc, argv, "f:m:")) != -1)
switch(o) switch(o)
{ {
case 'f':
prefs.font = optarg;
break;
case 'm': case 'm':
prefs.monitor = strtol(optarg, &p, 10); prefs.monitor = strtol(optarg, &p, 10);
if(optarg[0] == '\0' || *p != '\0') if(optarg[0] == '\0' || *p != '\0')