/* $Id$ */ /* Copyright (c) 2010-2020 Pierre Pronchery */ /* This file is part of DeforaOS Desktop Keyboard */ /* All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #ifdef DEBUG # include #endif #define XK_LATIN1 #define XK_MISCELLANY #include #include #include #include "common.h" #include "layout.h" /* KeyboardLayout */ /* private */ /* types */ typedef struct _KeyboardKeyRow KeyboardKeyRow; struct _KeyboardLayout { KeyboardKeyRow * rows; size_t rows_cnt; /* widgets */ GtkWidget * widget; }; struct _KeyboardKeyRow { KeyboardKey ** keys; size_t keys_cnt; unsigned int width; }; /* prototypes */ /* callbacks */ static void _on_key_clicked(GtkWidget * widget, gpointer data); /* public */ /* functions */ KeyboardLayout * keyboard_layout_new(void) { KeyboardLayout * layout; if((layout = malloc(sizeof(*layout))) == NULL) return NULL; layout->rows = NULL; layout->rows_cnt = 0; #ifdef DEBUG fprintf(stderr, "DEBUG: %s() gtk_table_new(%u, %u)\n", __func__, 1, 1); #endif layout->widget = gtk_table_new(1, 1, TRUE); return layout; } /* keyboard_layout_get_widget */ GtkWidget * keyboard_layout_get_widget(KeyboardLayout * layout) { return layout->widget; } /* useful */ /* keyboard_layout_add */ KeyboardKey * keyboard_layout_add(KeyboardLayout * layout, unsigned int row, unsigned int width, unsigned int keysym, char const * label) { KeyboardKey * ret = NULL; KeyboardKeyRow * p = &layout->rows[row]; KeyboardKey ** q; GtkAttachOptions options = GTK_EXPAND | GTK_SHRINK | GTK_FILL; GtkWidget * widget; if(row >= layout->rows_cnt) { if((p = realloc(layout->rows, sizeof(*p) * (row + 1))) == NULL) return NULL; layout->rows = p; for(; layout->rows_cnt <= row; layout->rows_cnt++) { layout->rows[layout->rows_cnt].keys = NULL; layout->rows[layout->rows_cnt].keys_cnt = 0; layout->rows[layout->rows_cnt].width = 0; } p = &layout->rows[row]; } if((q = realloc(p->keys, sizeof(*q) * (p->keys_cnt + 1))) == NULL) return NULL; p->keys = q; q = &p->keys[p->keys_cnt]; if(keysym != 0 && label != NULL) { if((ret = keyboard_key_new(keysym, label)) == NULL) return NULL; widget = keyboard_key_get_widget(ret); g_object_set_data(G_OBJECT(widget), "key", ret); g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK( _on_key_clicked), layout); if(width == 0) width = 1; #ifdef DEBUG fprintf(stderr, "DEBUG: %s() gtk_table_resize(%u, %u)\n", __func__, (unsigned)layout->rows_cnt, (unsigned)p->width + width); fprintf(stderr, "DEBUG: %s() %s(%u, %u, %u, %u)\n", __func__, "gtk_table_attach", p->width, p->width + width, row, row + 1); #endif gtk_table_resize(GTK_TABLE(layout->widget), layout->rows_cnt, p->width + width); gtk_table_attach(GTK_TABLE(layout->widget), widget, p->width, p->width + width, row, row + 1, options, options, 2, 2); p->keys[p->keys_cnt++] = ret; } p->width += width; return ret; } /* keyboard_layout_add_widget */ void keyboard_layout_add_widget(KeyboardLayout * layout, unsigned int row, unsigned int column, unsigned int width, GtkWidget * widget) { GtkAttachOptions options = GTK_EXPAND | GTK_SHRINK | GTK_FILL; gtk_table_attach(GTK_TABLE(layout->widget), widget, column, width, row, row + 1, options, options, 2, 2); } /* keyboard_layout_apply_modifier */ void keyboard_layout_apply_modifier(KeyboardLayout * layout, unsigned int modifier) { size_t i; size_t j; for(i = 0; i < layout->rows_cnt; i++) for(j = 0; j < layout->rows[i].keys_cnt; j++) keyboard_key_apply_modifier(layout->rows[i].keys[j], modifier); } /* private */ /* functions */ /* on_key_clicked */ static void _on_key_clicked(GtkWidget * widget, gpointer data) { KeyboardLayout * layout = data; KeyboardKey * key; Display * display; KeySym keysym; KeyCode keycode; gboolean active; key = g_object_get_data(G_OBJECT(widget), "key"); keysym = keyboard_key_get_keysym(key); display = gdk_x11_get_default_xdisplay(); if((keycode = XKeysymToKeycode(display, keysym)) == NoSymbol) return; XTestGrabControl(display, True); if(keysym_is_modifier(keysym) != 0) { active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( widget)); if(keysym != XK_Num_Lock) /* XXX ugly workaround */ XTestFakeKeyEvent(display, keycode, active ? True : False, 0); else { XTestFakeKeyEvent(display, keycode, True, 0); XTestFakeKeyEvent(display, keycode, False, 0); } keyboard_layout_apply_modifier(layout, active ? keysym : 0); } else { XTestFakeKeyEvent(display, keycode, True, 0); XTestFakeKeyEvent(display, keycode, False, 0); } XTestGrabControl(display, False); }