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)
{
Keyboard * keyboard = data;
unsigned int * keysym;
KeyboardKey * kk;
unsigned int keycode;
Display * display;
gboolean upper;
if((kk = g_object_get_data(G_OBJECT(key), "key")) == NULL)
return;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%p, \"%s\")\n", __func__, keyboard,
gtk_button_get_label(GTK_BUTTON(key)));
kk->label);
#endif
if((keysym = g_object_get_data(G_OBJECT(key), "keysym")) == NULL)
return;
display = gdk_x11_get_default_xdisplay();
keycode = XKeysymToKeycode(display, *keysym);
keycode = XKeysymToKeycode(display, kk->keysym);
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));
XTestFakeKeyEvent(display, keycode, upper ? True : False, 0);
@ -69,3 +69,29 @@ void on_keyboard_key_clicked(gpointer data, GtkWidget * key)
}
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 */
gboolean on_keyboard_delete_event(gpointer data);
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 */

View File

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

View File

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