diff --git a/src/callbacks.c b/src/callbacks.c index d13482b..d023d73 100644 --- a/src/callbacks.c +++ b/src/callbacks.c @@ -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; +} diff --git a/src/callbacks.h b/src/callbacks.h index b9c7562..7d0c86b 100644 --- a/src/callbacks.h +++ b/src/callbacks.h @@ -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 */ diff --git a/src/keyboard.c b/src/keyboard.c index 49ec114..2877e84 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -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); +} diff --git a/src/keyboard.h b/src/keyboard.h index f7b1dd7..170bb5b 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -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 */ diff --git a/src/main.c b/src/main.c index 14c9d88..38d351c 100644 --- a/src/main.c +++ b/src/main.c @@ -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')