From 8087c3e5d421b4a7a88c74d1ba2575ddde08bed2 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Fri, 15 Mar 2019 17:34:52 +0000 Subject: [PATCH] build: Use only meson for squeekboard This breaks autoconf. The only resulting binary is the squeekboard GUI. It still needs the autotools-built eekboard client in order to do anything useful. That one needs to be built using a different branch, making this a WIP. --- .gitlab-ci.yml | 3 - data/meson.build | 54 +++++ eek/gen-keysym-entries.py | 12 +- eek/meson.build | 44 ++++ eekboard/eekboard-context-service.c | 20 +- eekboard/eekboard-context.c | 5 +- eekboard/key-emitter.c | 345 ++++++++++++++++++++++++++++ eekboard/key-emitter.h | 31 +++ meson.build | 9 +- src/meson.build | 48 +++- 10 files changed, 547 insertions(+), 24 deletions(-) create mode 100644 data/meson.build create mode 100644 eek/meson.build create mode 100644 eekboard/key-emitter.c create mode 100644 eekboard/key-emitter.h diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f0ca4d4d..7c71c627 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,9 +12,6 @@ build_automake: tags: - librem5 script: - - ./autogen.sh --enable-vala=no --enable-xtest=no --prefix=`pwd`/../eekboard-install/ - - make - - make install - mkdir -p ../build - PKG_CONFIG_PATH=`pwd`/../eekboard-install/lib/pkgconfig/ meson ../build/ --prefix=`pwd`/../squeekboard-install/ - cd ../build diff --git a/data/meson.build b/data/meson.build new file mode 100644 index 00000000..8118b234 --- /dev/null +++ b/data/meson.build @@ -0,0 +1,54 @@ + +install_data( + 'themes/default.css', + install_dir: pkgdatadir + '/themes', +) + +install_data( + 'keyboards/keyboards.xml', + install_dir: pkgdatadir + '/keyboards/', +) + +install_data( + 'keyboards/geometry/compact.xml', + install_dir: pkgdatadir + '/keyboards/geometry/', +) + +symbols = [ + 'ar.xml', + 'as-inscript.xml', + 'be.xml', + 'bn-inscript.xml', + 'fa.xml', + 'gu-inscript.xml', + 'he.xml', + 'hi-inscript.xml', + 'ja-kana.xml', + 'kk.xml', + 'kn-inscript.xml', + 'ks-inscript.xml', + 'ks.xml', + 'mai-inscript.xml', + 'ml-inscript.xml', + 'mr-inscript.xml', + 'my.xml', + 'or-inscript.xml', + 'pa-inscript.xml', + 'ru.xml', + 'sd-inscript.xml', + 'ta-inscript.xml', + 'te-inscript.xml', + 'th.xml', + 'ua.xml', + 'ug.xml', + 'us.xml', + 'zh-bopomofo.xml', +] + +foreach symbol: symbols + install_data( + 'keyboards/symbols/' + symbol, + install_dir: pkgdatadir + '/keyboards/symbols/', + ) +endforeach + diff --git a/eek/gen-keysym-entries.py b/eek/gen-keysym-entries.py index 889ca7ed..a3a0fdf9 100755 --- a/eek/gen-keysym-entries.py +++ b/eek/gen-keysym-entries.py @@ -2,6 +2,7 @@ # Copyright (C) 2010-2011 Daiki Ueno # Copyright (C) 2010-2011 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 @@ -21,12 +22,17 @@ import sys import re -if len(sys.argv) != 2: - print >> sys.stderr, "Usage: %s TABLE-NAME" % sys.argv[0] +if len(sys.argv) > 3: + print >> sys.stderr, "Usage: %s TABLE-NAME [INPUT_FILE]" % sys.argv[0] sys.exit(-1) +if len(sys.argv) < 3: + in_stream = sys.stdin +else: + in_stream = open(sys.argv[2]) + table = dict() -for line in sys.stdin: +for line in in_stream: line = line.decode('UTF-8') match = re.match(r'\s*(0x[0-9A-F]+)\s+(\S*)\s+(\S*)', line, re.I) if match: diff --git a/eek/meson.build b/eek/meson.build new file mode 100644 index 00000000..5a0f609f --- /dev/null +++ b/eek/meson.build @@ -0,0 +1,44 @@ +gnome = import('gnome') + +enum_headers = [ + 'eek-symbol.h', + 'eek-types.h', +] + +enums = gnome.mkenums_simple('eek-enumtypes', sources: enum_headers) + +marshalers = gnome.genmarshal( + 'eek-marshalers', + sources: ['eek-marshalers.list'], + prefix: '_eek_marshal', + internal: true, +) + +python = find_program('python2') + +gen_keysym_entries_special = generator( + python, + arguments: ['@CURRENT_SOURCE_DIR@/gen-keysym-entries.py', 'special_keysym_entries', '@INPUT@'], + capture: true, + output: 'eek-@BASENAME@.h', +) + +gen_keysym_entries_unicode = generator( + python, + arguments: ['@CURRENT_SOURCE_DIR@/gen-keysym-entries.py', 'unicode_keysym_entries', '@INPUT@'], + capture: true, + output: 'eek-@BASENAME@.h', +) + +gen_keysym_entries_xkeysym = generator( + python, + arguments: ['@CURRENT_SOURCE_DIR@/gen-keysym-entries.py', 'xkeysym_keysym_entries', '@INPUT@'], + capture: true, + output: 'eek-@BASENAME@.h', +) + +keysym_entries = [ + gen_keysym_entries_special.process('./special-keysym-entries.txt'), + gen_keysym_entries_unicode.process('./unicode-keysym-entries.txt'), + gen_keysym_entries_xkeysym.process('./xkeysym-keysym-entries.txt'), +] diff --git a/eekboard/eekboard-context-service.c b/eekboard/eekboard-context-service.c index 0082c5f2..42f65ba1 100644 --- a/eekboard/eekboard-context-service.c +++ b/eekboard/eekboard-context-service.c @@ -29,6 +29,7 @@ #include "config.h" #endif /* HAVE_CONFIG_H */ +#include "eekboard/key-emitter.h" #include "eekboard/eekboard-context-service.h" #include "eekboard/eekboard-xklutil.h" #include "eek/eek-xkl.h" @@ -62,6 +63,7 @@ static guint signals[LAST_SIGNAL] = { 0, }; struct _EekboardContextServicePrivate { GDBusConnection *connection; GDBusNodeInfo *introspection_data; + guint registration_id; char *object_path; char *client_name; @@ -166,6 +168,7 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self, GError *error; if (g_str_has_prefix (keyboard_type, "xkb:")) { + /* TODO: Depends on xklavier XklConfigRec *rec = eekboard_xkl_config_rec_from_string (&keyboard_type[4]); @@ -186,6 +189,8 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self, g_object_unref (layout); return NULL; } + */ + return NULL; } else { error = NULL; layout = eek_xml_layout_new (keyboard_type, &error); @@ -719,9 +724,20 @@ on_key_released (EekKeyboard *keyboard, g_source_remove (context->priv->repeat_timeout_id); context->priv->repeat_timeout_id = 0; + guint keycode = eek_key_get_keycode (key); + EekSymbol *symbol = eek_key_get_symbol_with_fallback (key, 0, 0); + + guint modifiers = eek_keyboard_get_modifiers (context->priv->keyboard); /* KeyActivated signal has not been emitted in repeat handler */ - emit_key_activated_dbus_signal (context, - context->priv->repeat_key); + + + // Insert + EekboardContext ec = {0}; + Client c = {&ec, 0, {0}}; + + emit_key_activated(&ec, keycode, symbol, modifiers, &c); + //emit_key_activated_dbus_signal (context, + // context->priv->repeat_key); } } diff --git a/eekboard/eekboard-context.c b/eekboard/eekboard-context.c index 6ecc78d8..f3d6cd8e 100644 --- a/eekboard/eekboard-context.c +++ b/eekboard/eekboard-context.c @@ -29,7 +29,7 @@ #endif /* HAVE_CONFIG_H */ #include "eekboard/eekboard-context.h" -#include "eekboard/eekboard-marshalers.h" +//#include "eekboard/eekboard-marshalers.h" #define I_(string) g_intern_static_string (string) @@ -251,6 +251,7 @@ eekboard_context_class_init (EekboardContextClass *klass) * The ::key-activated signal is emitted each time a key is * pressed in @context. */ + /* signals[KEY_ACTIVATED] = g_signal_new (I_("key-activated"), G_TYPE_FROM_CLASS(gobject_class), @@ -264,7 +265,7 @@ eekboard_context_class_init (EekboardContextClass *klass) G_TYPE_UINT, G_TYPE_OBJECT, G_TYPE_UINT); - +*/ /** * EekboardContext::destroyed: * @context: an #EekboardContext diff --git a/eekboard/key-emitter.c b/eekboard/key-emitter.c new file mode 100644 index 00000000..db214644 --- /dev/null +++ b/eekboard/key-emitter.c @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2011 Daiki Ueno + * Copyright (C) 2011 Red Hat, Inc. + * Copyright (C) 2019 Purism, SPC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* This file is responsible for managing keycode data and emitting keycodes. */ + +#include "eekboard/key-emitter.h" + +#include + +/* 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 (Client *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 (Client *client, + 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 (client->xkb->min_key_code <= keycode && + keycode <= client->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 (Client *client, + guint keysym, + guint *keycode, + guint *modifiers) +{ + GdkKeymap *keymap = gdk_keymap_get_default (); + GdkKeymapKey *keys, *best_match = NULL; + gint n_keys, i; + + if (!gdk_keymap_get_entries_for_keyval (keymap, keysym, &keys, &n_keys)) + return FALSE; + + for (i = 0; i < n_keys; i++) + if (keys[i].group == client->context->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 WaylandFakeKeyEvent( + Display* dpy, + unsigned int keycode, + Bool is_press, + unsigned long delay +) { + printf("Sending fake event %d press %d delay %d\n", keycode, is_press, delay); +} + +static void +send_fake_modifier_key_event (Client *client, + EekModifierType modifiers, + gboolean is_pressed) +{ + GdkDisplay *display = gdk_display_get_default (); + Display *xdisplay = NULL; //GDK_DISPLAY_XDISPLAY (display); + gint i; + + for (i = 0; i < G_N_ELEMENTS(client->modifier_keycodes); i++) { + if (modifiers & (1 << i)) { + guint keycode = client->modifier_keycodes[i]; + printf("Trying to send a modifier %d press %ld\n", i, is_pressed); + g_return_if_fail (keycode > 0); + + WaylandFakeKeyEvent (xdisplay, + keycode, + is_pressed, + CurrentTime); + } + } +} + +static void +send_fake_key_event (Client *client, + guint xkeysym, + guint keyboard_modifiers) +{ + GdkDisplay *display = gdk_display_get_default (); + Display *xdisplay = NULL; // GDK_DISPLAY_XDISPLAY (display); + EekModifierType modifiers; + guint keycode; + guint old_keysym = xkeysym; + + g_return_if_fail (xkeysym > 0); + + modifiers = 0; + if (!get_keycode_from_gdk_keymap (client, xkeysym, &keycode, &modifiers)) { + keycode = get_replaced_keycode (client); + if (keycode == 0) { + g_warning ("no available keycode to replace"); + return; + } + + if (!replace_keycode (client, keycode, &old_keysym)) { + g_warning ("failed to lookup X keysym %X", xkeysym); + return; + } + } + + /* Clear level shift modifiers */ + keyboard_modifiers &= ~EEK_SHIFT_MASK; + keyboard_modifiers &= ~EEK_LOCK_MASK; + /* FIXME: may need to remap ISO_Level3_Shift and NumLock */ +#if 0 + keyboard_modifiers &= ~EEK_MOD5_MASK; + keyboard_modifiers &= ~client->alt_gr_mask; + keyboard_modifiers &= ~client->num_lock_mask; +#endif + + modifiers |= keyboard_modifiers; + + send_fake_modifier_key_event (client, modifiers, TRUE); + WaylandFakeKeyEvent (xdisplay, keycode, TRUE, 20); + //XSync (xdisplay, False); + WaylandFakeKeyEvent (xdisplay, keycode, FALSE, 20); + // XSync (xdisplay, False); + send_fake_modifier_key_event (client, modifiers, FALSE); + + if (old_keysym != xkeysym) + replace_keycode (client, keycode, &old_keysym); +} + +static void +send_fake_key_events (Client *client, + EekSymbol *symbol, + guint keyboard_modifiers) +{ + /* 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 (client, xkeysym, keyboard_modifiers); + } +} + +void +emit_key_activated (EekboardContext *context, + guint keycode, + EekSymbol *symbol, + guint modifiers, + Client *client) +{ + /* FIXME: figure out how to deal with Client after key presses go through + if (g_strcmp0 (eek_symbol_get_name (symbol), "cycle-keyboard") == 0) { + client->keyboards_head = g_slist_next (client->keyboards_head); + if (client->keyboards_head == NULL) + client->keyboards_head = client->keyboards; + eekboard_context_set_keyboard (client->context, + GPOINTER_TO_UINT(client->keyboards_head->data), + NULL); + return; + } + + if (g_strcmp0 (eek_symbol_get_name (symbol), "preferences") == 0) { + gchar *argv[2]; + GError *error; + + argv[0] = g_build_filename (LIBEXECDIR, "eekboard-setup", NULL); + argv[1] = NULL; + + error = NULL; + if (!g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, &error)) { + g_warning ("can't spawn %s: %s", argv[0], error->message); + g_error_free (error); + } + g_free (argv[0]); + return; + } +*/ + send_fake_key_events (client, symbol, modifiers); +} + +/* Finds the first key code for each modifier and saves it in modifier_keycodes */ +static void +update_modifier_keycodes (Client *client) +{ + GdkDisplay *display = gdk_display_get_default (); + Display *xdisplay = NULL; // GDK_DISPLAY_XDISPLAY (display); + return; // FIXME: need to get those codes somehow + XModifierKeymap *mods; + gint i, j; + + //mods = XGetModifierMapping (xdisplay); + for (i = 0; i < 8; i++) { + client->modifier_keycodes[i] = 0; + for (j = 0; j < mods->max_keypermod; j++) { + KeyCode keycode = mods->modifiermap[mods->max_keypermod * i + j]; + if (keycode != 0) { + client->modifier_keycodes[i] = keycode; + break; + } + } + } + //XFreeModifiermap (mods); +} + +gboolean +client_enable_xtest (Client *client) +{ + //GdkDisplay *display = gdk_display_get_default (); + //Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); + int opcode, event_base, error_base, major_version, minor_version; + + /* FIXME: need at least to fetch an xkb keymap (but what for?) + g_assert (display); + + if (!XTestQueryExtension (xdisplay, + &event_base, &error_base, + &major_version, &minor_version)) { + g_warning ("XTest extension is not available"); + return FALSE; + } + + if (!XkbQueryExtension (xdisplay, + &opcode, &event_base, &error_base, + &major_version, &minor_version)) { + g_warning ("Xkb extension is not available"); + return FALSE; + } + + if (!client->xkb) + client->xkb = XkbGetMap (xdisplay, XkbKeySymsMask, XkbUseCoreKbd); + g_assert (client->xkb); +*/ + update_modifier_keycodes (client); + + return TRUE; +} + +void +client_disable_xtest (Client *client) +{ + //if (client->xkb) { + // XkbFreeKeyboard (client->xkb, 0, TRUE); /* free_all = TRUE */ + //client->xkb = NULL; + //} +} +//#endif /* HAVE_XTEST */ diff --git a/eekboard/key-emitter.h b/eekboard/key-emitter.h new file mode 100644 index 00000000..74df8e5c --- /dev/null +++ b/eekboard/key-emitter.h @@ -0,0 +1,31 @@ +#ifndef KEYEMITTER_H +#define KEYEMITTER_H + +#include +#include + +#include "eek/eek.h" + +typedef struct { + gint group; +} EekboardContext; + +typedef struct { + EekboardContext *context; + XkbDescRec *xkb; + guint modifier_keycodes[8]; +} Client; + +void +emit_key_activated (EekboardContext *context, + guint keycode, + EekSymbol *symbol, + guint modifiers, + Client *client); + +gboolean +client_enable_xtest (Client *client); + +void +client_disable_xtest (Client *client); +#endif // KEYEMITTER_H diff --git a/meson.build b/meson.build index c577d16e..2004b8f8 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ project( 'c', version: '1.0.9', license: 'GPLv3', - meson_version: '>=0.40.1', + meson_version: '>=0.43.0', default_options: [ 'warning_level=1', 'buildtype=debugoptimized', 'c_std=gnu11' ], ) @@ -11,9 +11,6 @@ prefix = get_option('prefix') datadir = join_paths(prefix, get_option('datadir')) pkgdatadir = join_paths(datadir, meson.project_name()) -install_data( - 'data/themes/default.css', - install_dir: pkgdatadir + '/themes', -) - +subdir('data') +subdir('eek') subdir('src') diff --git a/src/meson.build b/src/meson.build index a9445ded..56c5f8b3 100644 --- a/src/meson.build +++ b/src/meson.build @@ -2,27 +2,59 @@ sources = [ 'server-service.c', 'server-context-service.c', 'server-main.c', - '../eekboard/eekboard-service.c', + '../eek/eek.c', + '../eek/eek-container.c', + '../eek/eek-element.c', + '../eek/eek-gtk-keyboard.c', + '../eek/eek-gtk-renderer.c', + '../eek/eek-key.c', + '../eek/eek-keyboard.c', + '../eek/eek-keyboard-drawing.c', + '../eek/eek-keysym.c', + '../eek/eek-layout.c', + '../eek/eek-renderer.c', + '../eek/eek-section.c', + '../eek/eek-serializable.c', + '../eek/eek-symbol.c', + '../eek/eek-symbol-matrix.c', + '../eek/eek-text.c', + '../eek/eek-theme.c', + '../eek/eek-theme-context.c', + '../eek/eek-theme-node.c', + '../eek/eek-types.c', + '../eek/eek-xml-layout.c', + enums, + keysym_entries, + marshalers, + '../eekboard/key-emitter.c', '../eekboard/eekboard-context-service.c', -# $(srcdir)/eekboard-client.c \ -# $(srcdir)/eekboard-context.c \ - '../eekboard/eekboard-xklutil.c', + '../eekboard/eekboard-context.c', + '../eekboard/eekboard-service.c', +# '../eekboard/eekboard-xklutil.c', ] +cc = meson.get_compiler('c') + + deps = [ # dependency('glib-2.0', version: '>=2.26.0'), dependency('gio-2.0', version: '>=2.26.0'), dependency('gtk+-3.0', version: '>=3.0'), - dependency('eek-gtk-0.90'), - dependency('libxklavier'), # FIXME remove + dependency('libcroco-0.6'), + cc.find_library('m'), +# dependency('libxklavier'), # FIXME remove ] # Replacement for eekboard-server squeekboard = executable('squeekboard', sources, - include_directories: [include_directories('..')], + include_directories: [include_directories('..'), include_directories('../eek')], dependencies: deps, install: true, - c_args: ['-DTHEMESDIR="' + pkgdatadir + '/themes"', '-DEEKBOARD_COMPILATION=1'], + c_args: [ + '-DTHEMESDIR="' + pkgdatadir + '/themes"', + '-DKEYBOARDSDIR="' + pkgdatadir + '/keyboards"', + '-DEEKBOARD_COMPILATION=1', + '-DEEK_COMPILATION=1'], )