diff --git a/data/keyboards/geometry/compact-landscape.xml b/data/keyboards/geometry/compact-landscape.xml new file mode 100644 index 00000000..5781a444 --- /dev/null +++ b/data/keyboards/geometry/compact-landscape.xml @@ -0,0 +1,189 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/data/keyboards/geometry/compact.xml b/data/keyboards/geometry/compact.xml index f9f76bd4..01240edb 100644 --- a/data/keyboards/geometry/compact.xml +++ b/data/keyboards/geometry/compact.xml @@ -3,52 +3,52 @@
- - - - - - - - - - + + + + + + + + + +
- - - - - - - - - - + + + + + + + + + +
- - - - - - - - - + + + + + + + + +
- - - - + + + +
diff --git a/data/keyboards/geometry/extended.xml b/data/keyboards/geometry/extended.xml index f855cebc..68794641 100644 --- a/data/keyboards/geometry/extended.xml +++ b/data/keyboards/geometry/extended.xml @@ -7,54 +7,54 @@ values in the range from 8 to 255. -->
- - - - - - - - - - - + + + + + + + + + + +
- - - - - - - - - - - + + + + + + + + + + +
- - - - - - - - - + + + + + + + + +
- - - - + + + +
diff --git a/data/keyboards/geometry/numbers-keypad.xml b/data/keyboards/geometry/numbers-keypad.xml index 4b5f11b8..2ce06a58 100644 --- a/data/keyboards/geometry/numbers-keypad.xml +++ b/data/keyboards/geometry/numbers-keypad.xml @@ -3,37 +3,37 @@
- - - - - + + + + +
- - - - - + + + + +
- - - - - + + + + +
- - - - + + + +
diff --git a/data/keyboards/symbols/nb.xml b/data/keyboards/symbols/nb.xml index 00a2ca3e..0dc2807a 100644 --- a/data/keyboards/symbols/nb.xml +++ b/data/keyboards/symbols/nb.xml @@ -63,8 +63,8 @@ aring Aring - U00B1 - U00A7 + + a @@ -100,37 +100,37 @@ h H minus - underscore + asciicircum j J - plus - equal + underscore + degree k K - U00FC - asciicircum + plus + equal l L - U00F6 - degree + parenleft + braceleft oslash Oslash - parenleft - braceleft + parenright + braceright ae AE - parenright - braceright + + Return diff --git a/data/squeekboard.gresources.xml b/data/squeekboard.gresources.xml index 2710633a..25830247 100644 --- a/data/squeekboard.gresources.xml +++ b/data/squeekboard.gresources.xml @@ -6,9 +6,6 @@ keyboards/geometry/extended.xml keyboards/geometry/numbers-keypad.xml keyboards/keyboards.xml - keyboards/keymaps/nb.xkb - keyboards/keymaps/us.xkb - keyboards/keymaps/numbers.xkb keyboards/symbols/ar.xml keyboards/symbols/as-inscript.xml keyboards/symbols/be.xml diff --git a/eek/eek-keyboard.c b/eek/eek-keyboard.c index 8782dc5c..1b0f9204 100644 --- a/eek/eek-keyboard.c +++ b/eek/eek-keyboard.c @@ -28,6 +28,7 @@ */ #include "config.h" +#include #include "eek-keyboard.h" #include "eek-marshalers.h" @@ -36,6 +37,7 @@ #include "eek-symbol.h" #include "eek-enumtypes.h" #include "eekboard/key-emitter.h" +#include "keymap.h" enum { PROP_0, @@ -72,6 +74,8 @@ struct _EekKeyboardPrivate GList *pressed_keys; GList *locked_keys; GArray *outline_array; + + /* Map key names to key objects: */ GHashTable *names; /* modifiers dynamically assigned at run time */ @@ -796,3 +800,93 @@ eek_keyboard_get_locked_keys (EekKeyboard *keyboard) g_return_val_if_fail (EEK_IS_KEYBOARD(keyboard), NULL); return g_list_copy (keyboard->priv->locked_keys); } + +/** + * eek_keyboard_get_keymap: + * @keyboard: an #EekKeyboard + * + * Get the keymap for the keyboard. + * Returns: a string containing the XKB keymap. + */ +gchar * +eek_keyboard_get_keymap(EekKeyboard *keyboard) +{ + /* Start the keycodes and symbols sections with their respective headers. */ + gchar *keycodes = g_strdup(keymap_keycodes_header); + gchar *symbols = g_strdup(keymap_symbols_header); + + /* Iterate over the keys in the name-to-key hash table. */ + GHashTableIter iter; + gpointer key_name, key_ptr; + g_hash_table_iter_init(&iter, keyboard->priv->names); + + while (g_hash_table_iter_next(&iter, &key_name, &key_ptr)) { + + gchar *current, *line; + EekKey *key = EEK_KEY(key_ptr); + int keycode = eek_key_get_keycode(key); + + /* Don't include invalid keycodes in the keymap. */ + if (keycode == EEK_INVALID_KEYCODE) + continue; + + /* Append a key name-to-keycode definition to the keycodes section. */ + current = keycodes; + line = g_strdup_printf(" <%s> = %i;\n", (char *)key_name, keycode); + + keycodes = g_strconcat(current, line, NULL); + g_free(line); + g_free(current); + + /* Find the symbols associated with the key. */ + EekSymbolMatrix *matrix = eek_key_get_symbol_matrix(key); + EekSymbol *syms[4]; + int i, j; + + /* Get the symbols for all the levels defined for the key, then + pad it out with the first symbol for all levels up to the fourth. */ + for (i = 0; i < matrix->num_levels; ++i) + syms[i] = eek_symbol_matrix_get_symbol(matrix, 0, i); + + while (i < 4) { + syms[i] = eek_symbol_matrix_get_symbol(matrix, 0, 0); + i++; + } + + /* The four levels are split into two groups in the keymap. + Generate strings for each of these groups, where an empty group is + treated specially. */ + + gchar *groups[2]; + for (i = 0, j = 0; i < 2; ++i, j += 2) { + if (syms[j] && syms[j + 1]) + groups[i] = g_strjoin(", ", eek_symbol_get_name(syms[j]), + eek_symbol_get_name(syms[j + 1]), + NULL); + else + groups[i] = ""; + } + + /* Append a key definition to the symbols section. */ + current = symbols; + line = g_strdup_printf(" key <%s> { [ %s ], [ %s ] };\n", + (char *)key_name, groups[0], groups[1]); + + g_free(groups[0]); + g_free(groups[1]); + + symbols = g_strconcat(current, line, NULL); + g_free(line); + g_free(current); + } + + /* Assemble the keymap file from the header, sections and footer. */ + gchar *keymap = g_strconcat(keymap_header, + keycodes, " };\n\n", + symbols, " };\n\n", + keymap_footer, NULL); + + g_free(keycodes); + g_free(symbols); + return keymap; +} diff --git a/eek/eek-keyboard.h b/eek/eek-keyboard.h index dcf308c9..d841732e 100644 --- a/eek/eek-keyboard.h +++ b/eek/eek-keyboard.h @@ -195,5 +195,8 @@ void eek_modifier_key_free void eek_keyboard_press_key(EekKeyboard *keyboard, EekKey *key, guint32 timestamp); void eek_keyboard_release_key(EekKeyboard *keyboard, EekKey *key, guint32 timestamp); +gchar * eek_keyboard_get_keymap + (EekKeyboard *keyboard); + G_END_DECLS #endif /* EEK_KEYBOARD_H */ diff --git a/eek/eek-xml-layout.c b/eek/eek-xml-layout.c index 23fb49ca..f3d527b9 100644 --- a/eek/eek-xml-layout.c +++ b/eek/eek-xml-layout.c @@ -247,6 +247,7 @@ struct _GeometryParseData { gchar *name; EekOutline outline; gchar *oref; + gint keycode; GHashTable *key_oref_hash; GHashTable *oref_outline_hash; @@ -269,6 +270,7 @@ geometry_parse_data_new (EekKeyboard *keyboard) g_str_equal, g_free, (GDestroyNotify)eek_outline_free); + data->keycode = 8; return data; } @@ -396,17 +398,6 @@ geometry_start_element_callback (GMarkupParseContext *pcontext, if (g_strcmp0 (element_name, "key") == 0) { guint keycode; - attribute = get_attribute (attribute_names, attribute_values, - "keycode"); - if (attribute == NULL) { - g_set_error (error, - G_MARKUP_ERROR, - G_MARKUP_ERROR_MISSING_ATTRIBUTE, - "no \"keycode\" attribute for \"key\""); - return; - } - keycode = strtol (attribute, NULL, 10); - attribute = get_attribute (attribute_names, attribute_values, "name"); if (attribute == NULL) { @@ -416,9 +407,17 @@ geometry_start_element_callback (GMarkupParseContext *pcontext, "no \"name\" attribute for \"key\""); return; } + gchar *name = g_strdup (attribute); + + attribute = get_attribute (attribute_names, attribute_values, + "keycode"); + if (attribute != NULL) + keycode = strtol (attribute, NULL, 10); + else + keycode = data->keycode++; data->key = eek_section_create_key (data->section, - g_strdup (attribute), + name, keycode, data->num_columns, data->num_rows - 1); @@ -727,7 +726,6 @@ symbols_end_element_callback (GMarkupParseContext *pcontext, gint levels = num_symbols / data->groups; EekSymbolMatrix *matrix = eek_symbol_matrix_new (data->groups, levels); - head = data->symbols = g_slist_reverse (data->symbols); for (i = 0; i < num_symbols; i++) { if (head && head->data) { diff --git a/eek/keymap.h b/eek/keymap.h new file mode 100644 index 00000000..26bb648b --- /dev/null +++ b/eek/keymap.h @@ -0,0 +1,39 @@ +#include +#include + +gboolean +squeek_keymap_get_entries_for_keyval (struct xkb_keymap *xkb_keymap, + guint keyval, + GdkKeymapKey **keys, + guint *n_keys); + +static const char *keymap_header = "xkb_keymap {\n\ +\n"; + +static const char *keymap_keycodes_header = "\ + xkb_keycodes \"squeekboard\" {\n\n\ + minimum = 8;\n\ + maximum = 255;\n\ +\n"; + +static const char *keymap_symbols_header = "\ + xkb_symbols \"squeekboard\" {\n\ +\n\ + name[Group1] = \"Letters\";\n\ + name[Group2] = \"Numbers/Symbols\";\n\ +\n"; + +static const char *keymap_footer = "\ + xkb_types \"squeekboard\" {\n\ +\n\ + type \"TWO_LEVEL\" {\n\ + modifiers = Shift;\n\ + map[Shift] = Level2;\n\ + level_name[Level1] = \"Base\";\n\ + level_name[Level2] = \"Shift\";\n\ + };\n\ + };\n\ +\n\ + xkb_compatibility \"squeekboard\" {\n\ + };\n\ +};"; diff --git a/eekboard/eekboard-context-service.c b/eekboard/eekboard-context-service.c index 3dc96f1a..797837b0 100644 --- a/eekboard/eekboard-context-service.c +++ b/eekboard/eekboard-context-service.c @@ -28,7 +28,6 @@ #include "config.h" #include "eekboard/eekboard-context-service.h" -#include "keymap.h" #include #include @@ -85,55 +84,6 @@ struct _EekboardContextServicePrivate { G_DEFINE_TYPE_WITH_PRIVATE (EekboardContextService, eekboard_context_service, G_TYPE_OBJECT); -/*static Display *display = NULL; */ -gchar * -get_keymap_from_resource(const gchar *keyboard_type, gboolean fallback) -{ - g_autoptr (GFile) file = NULL; - g_autoptr (GFileInfo) info = NULL; - g_autoptr (GFileInputStream) stream = NULL; - goffset size = 0; - gsize bytes_read = 0; - g_autofree gchar *contents = NULL; - g_autofree gchar *path = NULL; - GError *error = NULL; - - if (fallback) - g_debug ("falling back to loading a %s keymap", keyboard_type); - - path = g_strconcat ("resource:///sm/puri/squeekboard/keyboards/keymaps/", - keyboard_type, ".xkb", NULL); - file = g_file_new_for_uri (path); - stream = g_file_read (file, NULL, &error); - - if (!stream) - goto keymap_error; - - info = g_file_input_stream_query_info (stream, - G_FILE_ATTRIBUTE_STANDARD_SIZE, - NULL, - &error); - - if (!info) - goto keymap_error; - - size = g_file_info_get_size (info); - contents = g_malloc0 (size); - - if (!g_input_stream_read_all (G_INPUT_STREAM(stream), contents, size, - &bytes_read, NULL, &error)) - goto keymap_error; - - return g_utf8_make_valid (contents, size); - -keymap_error: - if (fallback) - g_error ("failed to load keymap from resource: %s", error->message); - - g_error_free (error); - return NULL; -} - static EekKeyboard * eekboard_context_service_real_create_keyboard (EekboardContextService *self, const gchar *keyboard_type) @@ -193,13 +143,8 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self, if (!context) { g_error("No context created"); } -/* - struct xkb_rule_names rules = { 0 }; - rules.layout = strdup(keyboard_type); -*/ - char *keymap_str = get_keymap_from_resource(keyboard_type, FALSE); - if (!keymap_str) - keymap_str = get_keymap_from_resource("us", TRUE); + + gchar *keymap_str = eek_keyboard_get_keymap(keyboard); struct xkb_keymap *keymap = xkb_keymap_new_from_string(context, keymap_str, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); diff --git a/eekboard/key-emitter.c b/eekboard/key-emitter.c index d960c223..40d7c7b0 100644 --- a/eekboard/key-emitter.c +++ b/eekboard/key-emitter.c @@ -20,7 +20,6 @@ /* This file is responsible for managing keycode data and emitting keycodes. */ #include "eekboard/key-emitter.h" -#include "eekboard/keymap.h" #include @@ -39,98 +38,6 @@ typedef struct { } SeatEmitter; -/* The following functions for keyboard mapping change are direct - translation of the code in Caribou (in libcaribou/xadapter.vala): - - - get_replaced_keycode (Caribou: get_reserved_keycode) - - replace_keycode - - get_keycode_from_gdk_keymap (Caribou: best_keycode_keyval_match) -*/ - -/* Find an unused keycode where a keysym can be assigned. Restricted to Level 1 */ -static guint -get_replaced_keycode (SeatEmitter *client) -{ - guint keycode; -return 0; // FIXME: no xkb allocated yet - for (keycode = client->xkb->max_key_code; - keycode >= client->xkb->min_key_code; - --keycode) { - guint offset = client->xkb->map->key_sym_map[keycode].offset; - if (client->xkb->map->key_sym_map[keycode].kt_index[0] == XkbOneLevelIndex && - client->xkb->map->syms[offset] != NoSymbol) { - return keycode; - } - } - - return 0; -} - -/* Replace keysym assigned to KEYCODE to KEYSYM. Both args are used - as in-out. If KEYCODE points to 0, this function picks a keycode - from the current map and replace the associated keysym to KEYSYM. - In that case, the replaced keycode is stored in KEYCODE and the old - keysym is stored in KEYSYM. If otherwise (KEYCODE points to - non-zero keycode), it simply changes the current map with the - specified KEYCODE and KEYSYM. */ -static gboolean -replace_keycode (SeatEmitter *emitter, - guint keycode, - guint *keysym) -{ -/* GdkDisplay *display = gdk_display_get_default (); - Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); - guint old_keysym; - int keysyms_per_keycode; - KeySym *syms; -*/ -return TRUE; // FIXME: no xkb allocated at the moment, pretending all is fine - g_return_val_if_fail (emitter->xkb->min_key_code <= keycode && - keycode <= emitter->xkb->max_key_code, - FALSE); - g_return_val_if_fail (keysym != NULL, FALSE); -/* - * Update keyboard mapping. Wayland receives keyboard mapping as a string, so XChangeKeyboardMapping needs to translate from the symbol tbale t the string. TODO. - * - syms = XGetKeyboardMapping (xdisplay, keycode, 1, &keysyms_per_keycode); - old_keysym = syms[0]; - syms[0] = *keysym; - XChangeKeyboardMapping (xdisplay, keycode, 1, syms, 1); - XSync (xdisplay, False); - XFree (syms); - *keysym = old_keysym; -*/ - return TRUE; -} - -static gboolean -get_keycode_from_gdk_keymap (SeatEmitter *emitter, - guint keysym, - guint *keycode, - guint *modifiers) -{ - GdkKeymapKey *keys, *best_match = NULL; - guint n_keys, i; - - if (!squeek_keymap_get_entries_for_keyval (emitter->keymap, keysym, &keys, &n_keys)) - return FALSE; - - for (i = 0; i < n_keys; i++) - if ((guint)keys[i].group == emitter->group) - best_match = &keys[i]; - - if (!best_match) { - g_free (keys); - return FALSE; - } - - *keycode = best_match->keycode; - *modifiers = best_match->level == 1 ? EEK_SHIFT_MASK : 0; - - g_free (keys); - return TRUE; -} - int send_virtual_keyboard_key( struct zwp_virtual_keyboard_v1 *keyboard, unsigned int keycode, @@ -161,95 +68,6 @@ send_fake_modifiers_events (SeatEmitter *emitter, zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, proto_modifiers, 0, 0, emitter->group); } -static void -send_fake_key_event (SeatEmitter *emitter, - guint xkeysym, - guint keyboard_modifiers, - gboolean pressed, - uint32_t timestamp) -{ - EekModifierType modifiers; - guint old_keysym = xkeysym; - - g_return_if_fail (xkeysym > 0); - - guint keycode; - if (!get_keycode_from_gdk_keymap (emitter, xkeysym, &keycode, &modifiers)) { - keycode = get_replaced_keycode (emitter); - if (keycode == 0) { - g_warning ("no available keycode to replace"); - return; - } - - if (!replace_keycode (emitter, keycode, &old_keysym)) { - g_warning ("failed to lookup X keysym %X", xkeysym); - return; - } - } - /* Clear level shift modifiers */ - keyboard_modifiers &= (unsigned)~EEK_SHIFT_MASK; - keyboard_modifiers &= (unsigned)~EEK_LOCK_MASK; - /* FIXME: may need to remap ISO_Level3_Shift and NumLock */ - - modifiers |= keyboard_modifiers; - - send_fake_modifiers_events (emitter, modifiers, timestamp); - - // There's something magical about subtracting/adding 8 to keycodes for some reason - send_virtual_keyboard_key (emitter->virtual_keyboard, keycode - 8, (unsigned)pressed, timestamp); - send_fake_modifiers_events (emitter, modifiers, timestamp); - - if (old_keysym != xkeysym) - replace_keycode (emitter, keycode, &old_keysym); -} - -static void -send_fake_key_events (SeatEmitter *emitter, - EekSymbol *symbol, - EekModifierType keyboard_modifiers, - gboolean pressed, - uint32_t timestamp) -{ - /* Ignore modifier keys */ - if (eek_symbol_is_modifier (symbol)) - return; - - /* If symbol is a text, convert chars in it to keysym */ - if (EEK_IS_TEXT(symbol)) { - const gchar *utf8 = eek_text_get_text (EEK_TEXT(symbol)); - printf("Attempting to send text %s\n", utf8); - /* FIXME: - glong items_written; - gunichar *ucs4 = g_utf8_to_ucs4_fast (utf8, -1, &items_written); - gint i; - - for (i = 0; i < items_written; i++) { - guint xkeysym; - EekKeysym *keysym; - gchar *name; - - name = g_strdup_printf ("U%04X", ucs4[i]); - xkeysym = XStringToKeysym (name); // TODO: use xkb_get_keysym_from_name - g_free (name); - - keysym = eek_keysym_new (xkeysym); - send_fake_key_events (client, - EEK_SYMBOL(keysym), - keyboard_modifiers); - } - g_free (ucs4); - */ - return; - } - - if (EEK_IS_KEYSYM(symbol)) { - guint xkeysym = eek_keysym_get_xkeysym (EEK_KEYSYM(symbol)); - send_fake_key_event (emitter, xkeysym, keyboard_modifiers, pressed, timestamp); - } -} - - - /* Finds the first key code for each modifier and saves it in modifier_keycodes */ static void update_modifier_info (SeatEmitter *client) diff --git a/eekboard/keymap.c b/eekboard/keymap.c deleted file mode 100644 index 2aab1485..00000000 --- a/eekboard/keymap.c +++ /dev/null @@ -1,66 +0,0 @@ -/* GDK - The GIMP Drawing Kit - * Copyright (C) 2000 Red Hat, Inc. - * Copyright (C) 2019 Purism, SPC - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - */ -/* - * Modified for squeekboard based on GTK - */ - -#include "keymap.h" - -gboolean -squeek_keymap_get_entries_for_keyval (struct xkb_keymap *xkb_keymap, - guint keyval, - GdkKeymapKey **keys, - guint *n_keys) -{ - GArray *retval; - guint keycode; - xkb_keycode_t min_keycode, max_keycode; - retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey)); - min_keycode = xkb_keymap_min_keycode (xkb_keymap); - max_keycode = xkb_keymap_max_keycode (xkb_keymap); - for (keycode = min_keycode; keycode < max_keycode; keycode++) - { - xkb_layout_index_t num_layouts, layout; - num_layouts = xkb_keymap_num_layouts_for_key (xkb_keymap, keycode); - for (layout = 0; layout < num_layouts; layout++) - { - xkb_layout_index_t num_levels, level; - num_levels = xkb_keymap_num_levels_for_key (xkb_keymap, keycode, layout); - for (level = 0; level < num_levels; level++) - { - const xkb_keysym_t *syms; - gint num_syms, sym; - num_syms = xkb_keymap_key_get_syms_by_level (xkb_keymap, keycode, layout, level, &syms); - for (sym = 0; sym < num_syms; sym++) - { - if (syms[sym] == keyval) - { - GdkKeymapKey key; - key.keycode = keycode; - key.group = (gint)layout; - key.level = (gint)level; - g_array_append_val (retval, key); - } - } - } - } - } - *n_keys = retval->len; - *keys = (GdkKeymapKey*) g_array_free (retval, FALSE); - return TRUE; -} diff --git a/eekboard/keymap.h b/eekboard/keymap.h deleted file mode 100644 index e33c502e..00000000 --- a/eekboard/keymap.h +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include - -gboolean -squeek_keymap_get_entries_for_keyval (struct xkb_keymap *xkb_keymap, - guint keyval, - GdkKeymapKey **keys, - guint *n_keys); diff --git a/src/meson.build b/src/meson.build index 1f731fef..4e5e07ab 100644 --- a/src/meson.build +++ b/src/meson.build @@ -40,7 +40,6 @@ sources = [ enums, keysym_entries, marshalers, - '../eekboard/keymap.c', '../eekboard/key-emitter.c', '../eekboard/eekboard-context-service.c', '../eekboard/eekboard-context.c',