diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index 43aa8137..94e7531d 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -39,6 +39,7 @@ #include "eekboard/eekboard-context-service.h" #include "src/layout.h" +#include "src/submission.h" enum { PROP_0, @@ -54,6 +55,8 @@ enum { typedef struct _EekGtkKeyboardPrivate { EekRenderer *renderer; + EekboardContextService *eekboard_context; // unowned reference + struct submission *submission; // unowned reference LevelKeyboard *keyboard; // unowned reference; it's kept in server-context (FIXME) GdkEventSequence *sequence; // unowned reference @@ -122,7 +125,8 @@ static void depress(EekGtkKeyboard *self, { EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); - squeek_layout_depress(priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard, + squeek_layout_depress(priv->keyboard->layout, + priv->submission, x, y, eek_renderer_get_transformation(priv->renderer), time, self); } @@ -130,18 +134,20 @@ static void drag(EekGtkKeyboard *self, gdouble x, gdouble y, guint32 time) { EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); - squeek_layout_drag(priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard, + squeek_layout_drag(priv->keyboard->layout, + priv->submission, x, y, eek_renderer_get_transformation(priv->renderer), time, - priv->keyboard->manager, self); + priv->eekboard_context, self); } static void release(EekGtkKeyboard *self, guint32 time) { EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); - squeek_layout_release(priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard, + squeek_layout_release(priv->keyboard->layout, + priv->submission, eek_renderer_get_transformation(priv->renderer), time, - priv->keyboard->manager, self); + priv->eekboard_context, self); } static gboolean @@ -229,7 +235,8 @@ eek_gtk_keyboard_real_unmap (GtkWidget *self) if (priv->keyboard) { squeek_layout_release_all_only( - priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard, + priv->keyboard->layout, + priv->submission, gdk_event_get_time(NULL)); } @@ -264,7 +271,8 @@ eek_gtk_keyboard_dispose (GObject *object) if (priv->keyboard) { squeek_layout_release_all_only( - priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard, + priv->keyboard->layout, + priv->submission, gdk_event_get_time(NULL)); priv->keyboard = NULL; } @@ -311,11 +319,14 @@ eek_gtk_keyboard_init (EekGtkKeyboard *self) * Returns: a #GtkWidget */ GtkWidget * -eek_gtk_keyboard_new (LevelKeyboard *keyboard) +eek_gtk_keyboard_new (LevelKeyboard *keyboard, EekboardContextService *eekservice, + struct submission *submission) { EekGtkKeyboard *ret = EEK_GTK_KEYBOARD(g_object_new (EEK_TYPE_GTK_KEYBOARD, NULL)); EekGtkKeyboardPrivate *priv = (EekGtkKeyboardPrivate*)eek_gtk_keyboard_get_instance_private (ret); priv->keyboard = keyboard; + priv->eekboard_context = eekservice; + priv->submission = submission; return GTK_WIDGET(ret); } diff --git a/eek/eek-gtk-keyboard.h b/eek/eek-gtk-keyboard.h index 35876b51..95647220 100644 --- a/eek/eek-gtk-keyboard.h +++ b/eek/eek-gtk-keyboard.h @@ -28,6 +28,9 @@ #include #include +#include "eek/eek-types.h" + +struct submission; typedef struct _LevelKeyboard LevelKeyboard; // including causes weird bugs G_BEGIN_DECLS @@ -45,7 +48,7 @@ struct _EekGtkKeyboardClass }; GType eek_gtk_keyboard_get_type (void) G_GNUC_CONST; -GtkWidget *eek_gtk_keyboard_new (LevelKeyboard *keyboard); +GtkWidget *eek_gtk_keyboard_new (LevelKeyboard *keyboard, EekboardContextService *eekservice, struct submission *submission); G_END_DECLS #endif /* EEK_GTK_KEYBOARD_H */ diff --git a/eek/eek-keyboard.c b/eek/eek-keyboard.c index 5245eb8e..24ef537b 100644 --- a/eek/eek-keyboard.c +++ b/eek/eek-keyboard.c @@ -18,40 +18,78 @@ * 02110-1301 USA */ -/** - * SECTION:eek-keyboard - * @short_description: Base class of a keyboard - * @see_also: #EekSection - * - * The #EekKeyboardClass class represents a keyboard, which consists - * of one or more sections of the #EekSectionClass class. - */ - #include "config.h" -#include -#include "eekboard/eekboard-context-service.h" -#include "keymap.h" +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include // TODO: this is Linux-specific +#include + + #include "eek-keyboard.h" -void level_keyboard_deinit(LevelKeyboard *self) { +void level_keyboard_free(LevelKeyboard *self) { xkb_keymap_unref(self->keymap); close(self->keymap_fd); squeek_layout_free(self->layout); -} - -void level_keyboard_free(LevelKeyboard *self) { - level_keyboard_deinit(self); g_free(self); } -void level_keyboard_init(LevelKeyboard *self, struct squeek_layout *layout) { - self->layout = layout; -} - -LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_layout *layout) { +LevelKeyboard* +level_keyboard_new (const gchar *keyboard_type, + enum squeek_arrangement_kind t) +{ + struct squeek_layout *layout = squeek_load_layout(keyboard_type, t); LevelKeyboard *keyboard = g_new0(LevelKeyboard, 1); - level_keyboard_init(keyboard, layout); - keyboard->manager = manager; + + if (!keyboard) { + g_error("Failed to create a keyboard"); + } + keyboard->layout = layout; + + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + g_error("No context created"); + } + + const gchar *keymap_str = squeek_layout_get_keymap(keyboard->layout); + + struct xkb_keymap *keymap = xkb_keymap_new_from_string(context, keymap_str, + XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + + if (!keymap) + g_error("Bad keymap:\n%s", keymap_str); + + xkb_context_unref(context); + keyboard->keymap = keymap; + + keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1); + keyboard->keymap_len = strlen(keymap_str) + 1; + + g_autofree char *path = strdup("/eek_keymap-XXXXXX"); + char *r = &path[strlen(path) - 6]; + getrandom(r, 6, GRND_NONBLOCK); + for (unsigned i = 0; i < 6; i++) { + r[i] = (r[i] & 0b1111111) | 0b1000000; // A-z + r[i] = r[i] > 'z' ? '?' : r[i]; // The randomizer doesn't need to be good... + } + int keymap_fd = shm_open(path, O_RDWR | O_CREAT | O_EXCL, 0600); + if (keymap_fd < 0) { + g_error("Failed to set up keymap fd"); + } + keyboard->keymap_fd = keymap_fd; + shm_unlink(path); + if (ftruncate(keymap_fd, (off_t)keyboard->keymap_len)) { + g_error("Failed to increase keymap fd size"); + } + char *ptr = mmap(NULL, keyboard->keymap_len, PROT_WRITE, MAP_SHARED, + keymap_fd, 0); + if ((void*)ptr == (void*)-1) { + g_error("Failed to set up mmap"); + } + strncpy(ptr, keymap_str, keyboard->keymap_len); + munmap(ptr, keyboard->keymap_len); return keyboard; } diff --git a/eek/eek-keyboard.h b/eek/eek-keyboard.h index 9bc5e2e0..fab549e1 100644 --- a/eek/eek-keyboard.h +++ b/eek/eek-keyboard.h @@ -40,16 +40,15 @@ struct _LevelKeyboard { size_t keymap_len; // length of the data inside keymap_fd guint id; // as a key to layout choices - - EekboardContextService *manager; // unowned reference }; typedef struct _LevelKeyboard LevelKeyboard; gchar * eek_keyboard_get_keymap (LevelKeyboard *keyboard); -LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_layout *layout); -void level_keyboard_deinit(LevelKeyboard *self); +LevelKeyboard* +level_keyboard_new (const gchar *keyboard_type, + enum squeek_arrangement_kind t); void level_keyboard_free(LevelKeyboard *self); G_END_DECLS diff --git a/eek/eek-types.h b/eek/eek-types.h index 6324094b..5d993191 100644 --- a/eek/eek-types.h +++ b/eek/eek-types.h @@ -38,6 +38,7 @@ G_BEGIN_DECLS typedef struct _EekBounds EekBounds; typedef struct _EekboardContextService EekboardContextService; +typedef struct _ServerContextService ServerContextService; typedef struct _LevelKeyboard LevelKeyboard; /** diff --git a/eek/eek-xml-layout.c b/eek/eek-xml-layout.c deleted file mode 100644 index 81d0302a..00000000 --- a/eek/eek-xml-layout.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2011 Daiki Ueno - * Copyright (C) 2011 Red Hat, Inc. - * - * 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 . - */ - -/** - * SECTION:eek-xml-layout - * @short_description: Layout engine which loads layout information from XML - */ - -#include "config.h" - -#include "eek-keyboard.h" -#include "src/layout.h" - -#include "eek-xml-layout.h" - -LevelKeyboard * -eek_xml_layout_real_create_keyboard (const char *keyboard_type, - EekboardContextService *manager, - enum squeek_arrangement_kind t) -{ - struct squeek_layout *layout = squeek_load_layout(keyboard_type, t); - return level_keyboard_new(manager, layout); -} diff --git a/eek/eek-xml-layout.h b/eek/eek-xml-layout.h deleted file mode 100644 index ed0bb346..00000000 --- a/eek/eek-xml-layout.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2011 Daiki Ueno - * Copyright (C) 2011 Red Hat, Inc. - * - * 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 . - */ - -#if !defined(__EEK_H_INSIDE__) && !defined(EEK_COMPILATION) -#error "Only can be included directly." -#endif - -#ifndef EEK_XML_LAYOUT_H -#define EEK_XML_LAYOUT_H 1 - -#include "eek-types.h" -#include "src/layout.h" - -G_BEGIN_DECLS - -LevelKeyboard * -eek_xml_layout_real_create_keyboard (const char *keyboard_type, - EekboardContextService *manager, - enum squeek_arrangement_kind t); -G_END_DECLS -#endif /* EEK_XML_LAYOUT_H */ diff --git a/eek/keymap.h b/eek/keymap.h deleted file mode 100644 index e33c502e..00000000 --- a/eek/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/eekboard/eekboard-context-service.c b/eekboard/eekboard-context-service.c index 94a6ae4c..e9f7b9db 100644 --- a/eekboard/eekboard-context-service.c +++ b/eekboard/eekboard-context-service.c @@ -16,30 +16,15 @@ * along with this program. If not, see . */ -/** - * SECTION:eekboard-context-service - * @short_description: base server implementation of eekboard input - * context service - * - * The #EekboardService class provides a base server side - * implementation of eekboard input context service. - */ - #include "config.h" -#include #include -#define _XOPEN_SOURCE 500 -#include -#include -#include // TODO: this is Linux-specific -#include #include #include "wayland.h" -#include "eek/eek-xml-layout.h" +#include "eek/eek-keyboard.h" #include "src/server-context-service.h" #include "eekboard/eekboard-context-service.h" @@ -73,65 +58,12 @@ struct _EekboardContextServicePrivate { // Maybe TODO: it's used only for fetching layout type. // Maybe let UI push the type to this structure? ServerContextService *ui; // unowned reference + /// Needed for keymap changes after keyboard updates + struct submission *submission; // unowned }; G_DEFINE_TYPE_WITH_PRIVATE (EekboardContextService, eekboard_context_service, G_TYPE_OBJECT); -static LevelKeyboard * -eekboard_context_service_real_create_keyboard (EekboardContextService *self, - const gchar *keyboard_type, - enum squeek_arrangement_kind t) -{ - LevelKeyboard *keyboard = eek_xml_layout_real_create_keyboard(keyboard_type, self, t); - if (!keyboard) { - g_error("Failed to create a keyboard"); - } - - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (!context) { - g_error("No context created"); - } - - const gchar *keymap_str = squeek_layout_get_keymap(keyboard->layout); - - struct xkb_keymap *keymap = xkb_keymap_new_from_string(context, keymap_str, - XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); - - if (!keymap) - g_error("Bad keymap:\n%s", keymap_str); - - xkb_context_unref(context); - keyboard->keymap = keymap; - - keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1); - keyboard->keymap_len = strlen(keymap_str) + 1; - - g_autofree char *path = strdup("/eek_keymap-XXXXXX"); - char *r = &path[strlen(path) - 6]; - getrandom(r, 6, GRND_NONBLOCK); - for (unsigned i = 0; i < 6; i++) { - r[i] = (r[i] & 0b1111111) | 0b1000000; // A-z - r[i] = r[i] > 'z' ? '?' : r[i]; // The randomizer doesn't need to be good... - } - int keymap_fd = shm_open(path, O_RDWR | O_CREAT | O_EXCL, 0600); - if (keymap_fd < 0) { - g_error("Failed to set up keymap fd"); - } - keyboard->keymap_fd = keymap_fd; - shm_unlink(path); - if (ftruncate(keymap_fd, (off_t)keyboard->keymap_len)) { - g_error("Failed to increase keymap fd size"); - } - char *ptr = mmap(NULL, keyboard->keymap_len, PROT_WRITE, MAP_SHARED, - keymap_fd, 0); - if ((void*)ptr == (void*)-1) { - g_error("Failed to set up mmap"); - } - strncpy(ptr, keymap_str, keyboard->keymap_len); - munmap(ptr, keyboard->keymap_len); - return keyboard; -} - static void eekboard_context_service_set_property (GObject *object, guint prop_id, @@ -217,15 +149,15 @@ eekboard_context_service_update_layout(EekboardContextService *context, enum squ } // generic part follows - LevelKeyboard *keyboard = eekboard_context_service_real_create_keyboard(context, keyboard_layout, t); + LevelKeyboard *keyboard = level_keyboard_new(keyboard_layout, t); // set as current LevelKeyboard *previous_keyboard = context->priv->keyboard; context->priv->keyboard = keyboard; - - // The keymap will get set even if the window is hidden. - // It's not perfect, - // but simpler than adding a check in the window showing procedure - eekboard_context_service_set_keymap(context, keyboard); + // Update the keymap if necessary. + // TODO: Update submission on change event + if (context->priv->submission) { + submission_set_keyboard(context->priv->submission, keyboard); + } g_object_notify (G_OBJECT(context), "keyboard"); @@ -262,12 +194,6 @@ static void eekboard_context_service_constructed (GObject *object) { EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE (object); - context->virtual_keyboard = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard( - squeek_wayland->virtual_keyboard_manager, - squeek_wayland->seat); - if (!context->virtual_keyboard) { - g_error("Programmer error: Failed to receive a virtual keyboard instance"); - } update_layout_and_type(context); } @@ -363,14 +289,6 @@ eekboard_context_service_get_keyboard (EekboardContextService *context) return context->priv->keyboard; } -void eekboard_context_service_set_keymap(EekboardContextService *context, - const LevelKeyboard *keyboard) -{ - zwp_virtual_keyboard_v1_keymap(context->virtual_keyboard, - WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, - keyboard->keymap_fd, keyboard->keymap_len); -} - void eekboard_context_service_set_hint_purpose(EekboardContextService *context, uint32_t hint, uint32_t purpose) { @@ -394,7 +312,13 @@ eekboard_context_service_get_overlay(EekboardContextService *context) { return context->priv->overlay; } -EekboardContextService *eekboard_context_service_new() +EekboardContextService *eekboard_context_service_new(void) { return g_object_new (EEKBOARD_TYPE_CONTEXT_SERVICE, NULL); } +void eekboard_context_service_set_submission(EekboardContextService *context, struct submission *submission) { + context->priv->submission = submission; + if (context->priv->submission) { + submission_set_keyboard(context->priv->submission, context->priv->keyboard); + } +} diff --git a/eekboard/eekboard-context-service.h b/eekboard/eekboard-context-service.h index dab830ce..383a6579 100644 --- a/eekboard/eekboard-context-service.h +++ b/eekboard/eekboard-context-service.h @@ -22,7 +22,8 @@ #ifndef EEKBOARD_CONTEXT_SERVICE_H #define EEKBOARD_CONTEXT_SERVICE_H 1 -#include +#include "src/submission.h" +#include "src/layout.h" #include "virtual-keyboard-unstable-v1-client-protocol.h" #include "text-input-unstable-v3-client-protocol.h" @@ -58,8 +59,6 @@ struct _EekboardContextService { GObject parent; EekboardContextServicePrivate *priv; - - struct zwp_virtual_keyboard_v1 *virtual_keyboard; }; /** @@ -84,10 +83,10 @@ struct _EekboardContextServiceClass { gpointer pdummy[24]; }; -EekboardContextService *eekboard_context_service_new(); GType eekboard_context_service_get_type (void) G_GNUC_CONST; EekboardContextService *eekboard_context_service_new(void); +void eekboard_context_service_set_submission(EekboardContextService *context, struct submission *submission); void eekboard_context_service_destroy (EekboardContextService *context); LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *context); diff --git a/src/imservice.c b/src/imservice.c index 595a3546..2a6184c8 100644 --- a/src/imservice.c +++ b/src/imservice.c @@ -1,28 +1,52 @@ -#include "imservice.h" +#include "submission.h" #include +struct imservice; + +void imservice_handle_input_method_activate(void *data, struct zwp_input_method_v2 *input_method); +void imservice_handle_input_method_deactivate(void *data, struct zwp_input_method_v2 *input_method); +void imservice_handle_surrounding_text(void *data, struct zwp_input_method_v2 *input_method, + const char *text, uint32_t cursor, uint32_t anchor); +void imservice_handle_done(void *data, struct zwp_input_method_v2 *input_method); +void imservice_handle_content_type(void *data, struct zwp_input_method_v2 *input_method, uint32_t hint, uint32_t purpose); +void imservice_handle_text_change_cause(void *data, struct zwp_input_method_v2 *input_method, uint32_t cause); +void imservice_handle_unavailable(void *data, struct zwp_input_method_v2 *input_method); + static const struct zwp_input_method_v2_listener input_method_listener = { .activate = imservice_handle_input_method_activate, .deactivate = imservice_handle_input_method_deactivate, .surrounding_text = imservice_handle_surrounding_text, .text_change_cause = imservice_handle_text_change_cause, .content_type = imservice_handle_content_type, - .done = imservice_handle_commit_state, + .done = imservice_handle_done, .unavailable = imservice_handle_unavailable, }; -struct imservice* get_imservice(struct zwp_input_method_manager_v2 *manager, - struct wl_seat *seat, - EekboardContextService *state) { - struct zwp_input_method_v2 *im = zwp_input_method_manager_v2_get_input_method(manager, seat); - struct imservice *imservice = imservice_new(im, state); +struct submission* get_submission(struct zwp_input_method_manager_v2 *immanager, + struct zwp_virtual_keyboard_manager_v1 *vkmanager, + struct wl_seat *seat, + EekboardContextService *state) { + struct zwp_input_method_v2 *im = NULL; + if (immanager) { + im = zwp_input_method_manager_v2_get_input_method(immanager, seat); + } + struct zwp_virtual_keyboard_v1 *vk = NULL; + if (vkmanager) { + vk = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(vkmanager, seat); + } + return submission_new(im, vk, state); +} - /* Add a listener, passing the imservice instance to make it available to - callbacks. */ +/// Un-inlined +struct zwp_input_method_v2 *imservice_manager_get_input_method(struct zwp_input_method_manager_v2 *manager, + struct wl_seat *seat) { + return zwp_input_method_manager_v2_get_input_method(manager, seat); +} + +/// Un-inlined to let Rust link to it +void imservice_connect_listeners(struct zwp_input_method_v2 *im, struct imservice* imservice) { zwp_input_method_v2_add_listener(im, &input_method_listener, imservice); - - return imservice; } /// Declared explicitly because _destroy is inline, diff --git a/src/imservice.h b/src/imservice.h index 5b879bfb..e69de29b 100644 --- a/src/imservice.h +++ b/src/imservice.h @@ -1,27 +0,0 @@ -#ifndef __IMSERVICE_H -#define __IMSERVICE_H - -#include "input-method-unstable-v2-client-protocol.h" -#include "eek/eek-types.h" -#include "src/server-context-service.h" - -struct imservice; - -struct imservice* get_imservice(struct zwp_input_method_manager_v2 *manager, - struct wl_seat *seat, - EekboardContextService *state); - -// Defined in Rust -struct imservice* imservice_new(struct zwp_input_method_v2 *im, EekboardContextService *state); -void imservice_set_ui(struct imservice *self, ServerContextService *ui_context); - -void imservice_handle_input_method_activate(void *data, struct zwp_input_method_v2 *input_method); -void imservice_handle_input_method_deactivate(void *data, struct zwp_input_method_v2 *input_method); -void imservice_handle_surrounding_text(void *data, struct zwp_input_method_v2 *input_method, - const char *text, uint32_t cursor, uint32_t anchor); -void imservice_handle_commit_state(void *data, struct zwp_input_method_v2 *input_method); -void imservice_handle_content_type(void *data, struct zwp_input_method_v2 *input_method, uint32_t hint, uint32_t purpose); -void imservice_handle_text_change_cause(void *data, struct zwp_input_method_v2 *input_method, uint32_t cause); -void imservice_handle_unavailable(void *data, struct zwp_input_method_v2 *input_method); - -#endif diff --git a/src/imservice.rs b/src/imservice.rs index cc30b01a..f5989a11 100644 --- a/src/imservice.rs +++ b/src/imservice.rs @@ -12,26 +12,23 @@ use std::convert::TryFrom; /// Gathers stuff defined in C or called by C pub mod c { use super::*; - + use std::os::raw::{c_char, c_void}; + pub use ::submission::c::UIManager; + pub use ::submission::c::StateManager; + // The following defined in C /// struct zwp_input_method_v2* #[repr(transparent)] pub struct InputMethod(*const c_void); - - /// ServerContextService* - #[repr(transparent)] - pub struct UIManager(*const c_void); - - /// EekboardContextService* - #[repr(transparent)] - pub struct StateManager(*const c_void); #[no_mangle] extern "C" { fn imservice_destroy_im(im: *mut c::InputMethod); + #[allow(improper_ctypes)] // IMService will never be dereferenced in C + pub fn imservice_connect_listeners(im: *mut InputMethod, imservice: *const IMService); fn eekboard_context_service_set_hint_purpose(state: *const StateManager, hint: u32, purpose: u32); fn server_context_service_show_keyboard(imservice: *const UIManager); fn server_context_service_hide_keyboard(imservice: *const UIManager); @@ -39,42 +36,9 @@ pub mod c { // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers - #[no_mangle] - pub extern "C" - fn imservice_new( - im: *const InputMethod, - state_manager: *const StateManager - ) -> *mut IMService { - Box::::into_raw(Box::new( - IMService { - im: im, - state_manager: state_manager, - ui_manager: None, - pending: IMProtocolState::default(), - current: IMProtocolState::default(), - preedit_string: String::new(), - serial: Wrapping(0u32), - } - )) - } - - #[no_mangle] - pub extern "C" - fn imservice_set_ui(imservice: *mut IMService, ui_manager: *const UIManager) { - if imservice.is_null() { - panic!("Null imservice pointer"); - } - let imservice: &mut IMService = unsafe { &mut *imservice }; - imservice.ui_manager = if ui_manager.is_null() { - None - } else { - Some(ui_manager) - }; - } - // TODO: is unsafe needed here? #[no_mangle] - pub unsafe extern "C" + pub extern "C" fn imservice_handle_input_method_activate(imservice: *mut IMService, im: *const InputMethod) { @@ -87,7 +51,7 @@ pub mod c { } #[no_mangle] - pub unsafe extern "C" + pub extern "C" fn imservice_handle_input_method_deactivate(imservice: *mut IMService, im: *const InputMethod) { @@ -99,7 +63,7 @@ pub mod c { } #[no_mangle] - pub unsafe extern "C" + pub extern "C" fn imservice_handle_surrounding_text(imservice: *mut IMService, im: *const InputMethod, text: *const c_char, cursor: u32, _anchor: u32) @@ -115,7 +79,7 @@ pub mod c { } #[no_mangle] - pub unsafe extern "C" + pub extern "C" fn imservice_handle_content_type(imservice: *mut IMService, im: *const InputMethod, hint: u32, purpose: u32) @@ -139,7 +103,7 @@ pub mod c { } #[no_mangle] - pub unsafe extern "C" + pub extern "C" fn imservice_handle_text_change_cause(imservice: *mut IMService, im: *const InputMethod, cause: u32) @@ -157,14 +121,13 @@ pub mod c { } #[no_mangle] - pub unsafe extern "C" - fn imservice_handle_commit_state(imservice: *mut IMService, + pub extern "C" + fn imservice_handle_done(imservice: *mut IMService, im: *const InputMethod) { let imservice = check_imservice(imservice, im).unwrap(); let active_changed = imservice.current.active ^ imservice.pending.active; - - imservice.serial += Wrapping(1u32); + imservice.current = imservice.pending.clone(); imservice.pending = IMProtocolState { active: imservice.current.active, @@ -174,36 +137,40 @@ pub mod c { if active_changed { if imservice.current.active { if let Some(ui) = imservice.ui_manager { - server_context_service_show_keyboard(ui); + unsafe { server_context_service_show_keyboard(ui); } + } + unsafe { + eekboard_context_service_set_hint_purpose( + imservice.state_manager, + imservice.current.content_hint.bits(), + imservice.current.content_purpose.clone() as u32, + ); } - eekboard_context_service_set_hint_purpose( - imservice.state_manager, - imservice.current.content_hint.bits(), - imservice.current.content_purpose.clone() as u32); } else { if let Some(ui) = imservice.ui_manager { - server_context_service_hide_keyboard(ui); + unsafe { server_context_service_hide_keyboard(ui); } } } } } + // TODO: this is really untested #[no_mangle] - pub unsafe extern "C" + pub extern "C" fn imservice_handle_unavailable(imservice: *mut IMService, im: *mut InputMethod) { let imservice = check_imservice(imservice, im).unwrap(); - imservice_destroy_im(im); + unsafe { imservice_destroy_im(im); } // no need to care about proper double-buffering, // the keyboard is already decommissioned imservice.current.active = false; if let Some(ui) = imservice.ui_manager { - server_context_service_hide_keyboard(ui); + unsafe { server_context_service_hide_keyboard(ui); } } - } + } // FIXME: destroy and deallocate @@ -349,12 +316,38 @@ pub struct IMService { /// Owned reference (still created and destroyed in C) pub im: *const c::InputMethod, /// Unowned reference. Be careful, it's shared with C at large - ui_manager: Option<*const c::UIManager>, - /// Unowned reference. Be careful, it's shared with C at large state_manager: *const c::StateManager, + /// Unowned reference. Be careful, it's shared with C at large + pub ui_manager: Option<*const c::UIManager>, pending: IMProtocolState, current: IMProtocolState, // turn current into an idiomatic representation? preedit_string: String, serial: Wrapping, } + +impl IMService { + pub fn new( + im: *mut c::InputMethod, + state_manager: *const c::StateManager, + ) -> Box { + // IMService will be referenced to by C, + // so it needs to stay in the same place in memory via Box + let imservice = Box::new(IMService { + im, + ui_manager: None, + state_manager, + pending: IMProtocolState::default(), + current: IMProtocolState::default(), + preedit_string: String::new(), + serial: Wrapping(0u32), + }); + unsafe { + c::imservice_connect_listeners( + im, + imservice.as_ref() as *const IMService, + ); + } + imservice + } +} diff --git a/src/layout.h b/src/layout.h index 9f1a4a71..eefcce36 100644 --- a/src/layout.h +++ b/src/layout.h @@ -33,17 +33,22 @@ const char *squeek_layout_get_keymap(const struct squeek_layout*); enum squeek_arrangement_kind squeek_layout_get_kind(const struct squeek_layout *); void squeek_layout_free(struct squeek_layout*); -void squeek_layout_release(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard, +void squeek_layout_release(struct squeek_layout *layout, + struct submission *submission, struct transformation widget_to_layout, uint32_t timestamp, EekboardContextService *manager, EekGtkKeyboard *ui_keyboard); -void squeek_layout_release_all_only(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard, uint32_t timestamp); -void squeek_layout_depress(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard, +void squeek_layout_release_all_only(struct squeek_layout *layout, + struct submission *submission, + uint32_t timestamp); +void squeek_layout_depress(struct squeek_layout *layout, + struct submission *submission, double x_widget, double y_widget, struct transformation widget_to_layout, uint32_t timestamp, EekGtkKeyboard *ui_keyboard); -void squeek_layout_drag(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard, +void squeek_layout_drag(struct squeek_layout *layout, + struct submission *submission, double x_widget, double y_widget, struct transformation widget_to_layout, uint32_t timestamp, EekboardContextService *manager, diff --git a/src/layout.rs b/src/layout.rs index c01226d5..413e924a 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -27,7 +27,7 @@ use ::action::Action; use ::drawing; use ::keyboard::{ KeyState, PressType }; use ::manager; -use ::submission::{ Timestamp, VirtualKeyboard }; +use ::submission::{ Submission, Timestamp }; use ::util::find_max_double; use std::borrow::Borrow; @@ -143,6 +143,11 @@ pub mod c { } } } + + // This is constructed only in C, no need for warnings + #[allow(dead_code)] + #[repr(transparent)] + pub struct LevelKeyboard(*const c_void); // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers @@ -244,19 +249,12 @@ pub mod c { pub mod procedures { use super::*; - use ::submission::c::ZwpVirtualKeyboardV1; - - // This is constructed only in C, no need for warnings - #[allow(dead_code)] - #[repr(transparent)] - pub struct LevelKeyboard(*const c_void); - /// Release pointer in the specified position #[no_mangle] pub extern "C" fn squeek_layout_release( layout: *mut Layout, - virtual_keyboard: ZwpVirtualKeyboardV1, // TODO: receive a reference to the backend + submission: *mut Submission, widget_to_layout: Transformation, time: u32, manager: manager::c::Manager, @@ -264,7 +262,7 @@ pub mod c { ) { let time = Timestamp(time); let layout = unsafe { &mut *layout }; - let virtual_keyboard = VirtualKeyboard(virtual_keyboard); + let submission = unsafe { &mut *submission }; let ui_backend = UIBackend { widget_to_layout, keyboard: ui_keyboard, @@ -276,7 +274,7 @@ pub mod c { let key: &Rc> = key.borrow(); seat::handle_release_key( layout, - &virtual_keyboard, + submission, Some(&ui_backend), time, Some(manager), @@ -291,18 +289,18 @@ pub mod c { pub extern "C" fn squeek_layout_release_all_only( layout: *mut Layout, - virtual_keyboard: ZwpVirtualKeyboardV1, // TODO: receive a reference to the backend + submission: *mut Submission, time: u32, ) { let layout = unsafe { &mut *layout }; - let virtual_keyboard = VirtualKeyboard(virtual_keyboard); + let submission = unsafe { &mut *submission }; // The list must be copied, // because it will be mutated in the loop for key in layout.pressed_keys.clone() { let key: &Rc> = key.borrow(); seat::handle_release_key( layout, - &virtual_keyboard, + submission, None, // don't update UI Timestamp(time), None, // don't switch layouts @@ -315,13 +313,14 @@ pub mod c { pub extern "C" fn squeek_layout_depress( layout: *mut Layout, - virtual_keyboard: ZwpVirtualKeyboardV1, // TODO: receive a reference to the backend + submission: *mut Submission, x_widget: f64, y_widget: f64, widget_to_layout: Transformation, time: u32, ui_keyboard: EekGtkKeyboard, ) { let layout = unsafe { &mut *layout }; + let submission = unsafe { &mut *submission }; let point = widget_to_layout.forward( Point { x: x_widget, y: y_widget } ); @@ -335,7 +334,7 @@ pub mod c { if let Some(state) = state { seat::handle_press_key( layout, - &VirtualKeyboard(virtual_keyboard), + submission, Timestamp(time), &state, ); @@ -351,7 +350,7 @@ pub mod c { pub extern "C" fn squeek_layout_drag( layout: *mut Layout, - virtual_keyboard: ZwpVirtualKeyboardV1, // TODO: receive a reference to the backend + submission: *mut Submission, x_widget: f64, y_widget: f64, widget_to_layout: Transformation, time: u32, @@ -360,7 +359,7 @@ pub mod c { ) { let time = Timestamp(time); let layout = unsafe { &mut *layout }; - let virtual_keyboard = VirtualKeyboard(virtual_keyboard); + let submission = unsafe { &mut *submission }; let ui_backend = UIBackend { widget_to_layout, keyboard: ui_keyboard, @@ -389,7 +388,7 @@ pub mod c { } else { seat::handle_release_key( layout, - &virtual_keyboard, + submission, Some(&ui_backend), time, Some(manager), @@ -400,7 +399,7 @@ pub mod c { if !found { seat::handle_press_key( layout, - &virtual_keyboard, + submission, time, &state, ); @@ -411,7 +410,7 @@ pub mod c { let key: &Rc> = wrapped_key.borrow(); seat::handle_release_key( layout, - &virtual_keyboard, + submission, Some(&ui_backend), time, Some(manager), @@ -854,7 +853,7 @@ mod seat { pub fn handle_press_key( layout: &mut Layout, - virtual_keyboard: &VirtualKeyboard, + submission: &mut Submission, time: Timestamp, rckey: &Rc>, ) { @@ -862,7 +861,7 @@ mod seat { eprintln!("Warning: key {:?} was already pressed", rckey); } let mut key = rckey.borrow_mut(); - virtual_keyboard.switch( + submission.virtual_keyboard.switch( &key.keycodes, PressType::Pressed, time, @@ -872,7 +871,7 @@ mod seat { pub fn handle_release_key( layout: &mut Layout, - virtual_keyboard: &VirtualKeyboard, + submission: &mut Submission, ui: Option<&UIBackend>, time: Timestamp, manager: Option, @@ -894,7 +893,7 @@ mod seat { match action { Action::Submit { text: _, keys: _ } => { unstick_locks(layout).apply(); - virtual_keyboard.switch( + submission.virtual_keyboard.switch( &key.keycodes, PressType::Released, time, diff --git a/src/lib.rs b/src/lib.rs index 7f422c6a..4b5b9480 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,8 +29,9 @@ mod manager; mod outputs; mod popover; mod resources; -mod submission; mod style; +mod submission; pub mod tests; pub mod util; +mod vkeyboard; mod xdg; diff --git a/src/meson.build b/src/meson.build index e43974a6..4537164b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -22,7 +22,6 @@ sources = [ '../eek/eek-keyboard.c', '../eek/eek-renderer.c', '../eek/eek-types.c', - '../eek/eek-xml-layout.c', '../eek/layersurface.c', dbus_src, '../eekboard/eekboard-context-service.c', diff --git a/src/server-context-service.c b/src/server-context-service.c index ce2052da..77022e62 100644 --- a/src/server-context-service.c +++ b/src/server-context-service.c @@ -24,6 +24,7 @@ #include "eek/eek-gtk-keyboard.h" #include "eek/layersurface.h" #include "eekboard/eekboard-context-service.h" +#include "submission.h" #include "wayland.h" #include "server-context-service.h" @@ -41,10 +42,12 @@ struct _ServerContextService { GObject parent; EekboardContextService *state; // unowned + /// Needed for instantiating the widget + struct submission *submission; // unowned gboolean visible; PhoshLayerSurface *window; - GtkWidget *widget; + GtkWidget *widget; // nullable guint hiding; guint last_requested_height; enum squeek_arrangement_kind last_type; @@ -224,7 +227,7 @@ make_widget (ServerContextService *context) LevelKeyboard *keyboard = eekboard_context_service_get_keyboard (context->state); - context->widget = eek_gtk_keyboard_new (keyboard); + context->widget = eek_gtk_keyboard_new (keyboard, context->state, context->submission); gtk_widget_set_has_tooltip (context->widget, TRUE); gtk_container_add (GTK_CONTAINER(context->window), context->widget); @@ -395,9 +398,10 @@ server_context_service_init (ServerContextService *state) { } ServerContextService * -server_context_service_new (EekboardContextService *state) +server_context_service_new (EekboardContextService *state, struct submission *submission) { ServerContextService *ui = g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL); + ui->submission = submission; ui->state = state; g_signal_connect (state, "notify::keyboard", diff --git a/src/server-context-service.h b/src/server-context-service.h index c316f6b7..b6806e2b 100644 --- a/src/server-context-service.h +++ b/src/server-context-service.h @@ -19,6 +19,7 @@ #define SERVER_CONTEXT_SERVICE_H 1 #include "src/layout.h" +#include "src/submission.h" G_BEGIN_DECLS @@ -35,7 +36,7 @@ typedef struct _ServerContextService ServerContextService; GType server_context_service_get_type (void) G_GNUC_CONST; -ServerContextService *server_context_service_new(EekboardContextService *state); +ServerContextService *server_context_service_new(EekboardContextService *state, struct submission *submission); enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *); void server_context_service_show_keyboard (ServerContextService *context); void server_context_service_hide_keyboard (ServerContextService *context); diff --git a/src/server-main.c b/src/server-main.c index 0fe5299f..9cf88eed 100644 --- a/src/server-main.c +++ b/src/server-main.c @@ -28,8 +28,8 @@ #include "eek/eek.h" #include "eekboard/eekboard-context-service.h" #include "dbus.h" -#include "imservice.h" #include "outputs.h" +#include "submission.h" #include "server-context-service.h" #include "wayland.h" @@ -42,7 +42,7 @@ struct squeekboard { DBusHandler *dbus_handler; EekboardContextService *settings_context; ServerContextService *ui_context; - struct imservice *imservice; + struct submission *submission; }; @@ -195,6 +195,10 @@ main (int argc, char **argv) exit(1); } + if (!instance.wayland.input_method_manager) { + g_warning("Wayland input method interface not available"); + } + instance.settings_context = eekboard_context_service_new(); // set up dbus @@ -263,26 +267,23 @@ main (int argc, char **argv) exit (1); } - struct imservice *imservice = NULL; - if (instance.wayland.input_method_manager) { - imservice = get_imservice(instance.wayland.input_method_manager, - instance.wayland.seat, - instance.settings_context); - if (imservice) { - instance.imservice = imservice; - } else { - g_warning("Failed to register as an input method"); - } - } + instance.submission = get_submission(instance.wayland.input_method_manager, + instance.wayland.virtual_keyboard_manager, + instance.wayland.seat, + instance.settings_context); - ServerContextService *ui_context = server_context_service_new(instance.settings_context); + eekboard_context_service_set_submission(instance.settings_context, instance.submission); + + ServerContextService *ui_context = server_context_service_new( + instance.settings_context, + instance.submission); if (!ui_context) { g_error("Could not initialize GUI"); exit(1); } instance.ui_context = ui_context; - if (instance.imservice) { - imservice_set_ui(instance.imservice, instance.ui_context); + if (instance.submission) { + submission_set_ui(instance.submission, instance.ui_context); } if (instance.dbus_handler) { dbus_handler_set_ui_context(instance.dbus_handler, instance.ui_context); diff --git a/src/submission.h b/src/submission.h new file mode 100644 index 00000000..e2ebbbfd --- /dev/null +++ b/src/submission.h @@ -0,0 +1,19 @@ +#ifndef __SUBMISSION_H +#define __SUBMISSION_H + +#include "input-method-unstable-v2-client-protocol.h" +#include "virtual-keyboard-unstable-v1-client-protocol.h" +#include "eek/eek-types.h" + +struct submission; + +struct submission* get_submission(struct zwp_input_method_manager_v2 *immanager, + struct zwp_virtual_keyboard_manager_v1 *vkmanager, + struct wl_seat *seat, + EekboardContextService *state); + +// Defined in Rust +struct submission* submission_new(struct zwp_input_method_v2 *im, struct zwp_virtual_keyboard_v1 *vk, EekboardContextService *state); +void submission_set_ui(struct submission *self, ServerContextService *ui_context); +void submission_set_keyboard(struct submission *self, LevelKeyboard *keyboard); +#endif diff --git a/src/submission.rs b/src/submission.rs index c931858d..db7e6cc4 100644 --- a/src/submission.rs +++ b/src/submission.rs @@ -1,67 +1,100 @@ -/*! Managing the events belonging to virtual-keyboard interface. */ +/*! Managing the state of text input in the application. + * + * This is a library module. + * + * It needs to combine text-input and virtual-keyboard protocols + * to achieve a consistent view of the text-input state, + * and to submit exactly what the user wanted. + * + * It must also not get tripped up by sudden disappearances of interfaces. + * + * The virtual-keyboard interface is always present. + * + * The text-input interface may not be presented, + * and, for simplicity, no further attempt to claim it is made. + * + * The text-input interface may be enabled and disabled at arbitrary times, + * and those events SHOULD NOT cause any lost events. + * */ -use ::keyboard::{ KeyCode, PressType }; +use ::imservice::IMService; +use ::vkeyboard::VirtualKeyboard; /// Gathers stuff defined in C or called by C pub mod c { + use super::*; + use std::os::raw::c_void; + use ::imservice::c::InputMethod; + use ::layout::c::LevelKeyboard; + use ::vkeyboard::c::ZwpVirtualKeyboardV1; + + // The following defined in C + + /// ServerContextService* #[repr(transparent)] - #[derive(Clone, Copy)] - pub struct ZwpVirtualKeyboardV1(*const c_void); + pub struct UIManager(*const c_void); + + /// EekboardContextService* + #[repr(transparent)] + pub struct StateManager(*const c_void); #[no_mangle] - extern "C" { - /// Checks if point falls within bounds, - /// which are relative to origin and rotated by angle (I think) - pub fn eek_virtual_keyboard_v1_key( - virtual_keyboard: ZwpVirtualKeyboardV1, - timestamp: u32, - keycode: u32, - press: u32, - ); + pub extern "C" + fn submission_new( + im: *mut InputMethod, + vk: ZwpVirtualKeyboardV1, + state_manager: *const StateManager + ) -> *mut Submission { + let imservice = if im.is_null() { + None + } else { + Some(IMService::new(im, state_manager)) + }; + // TODO: add vkeyboard too + Box::::into_raw(Box::new( + Submission { + imservice, + virtual_keyboard: VirtualKeyboard(vk), + } + )) + } + + /// Use to initialize the UI reference + #[no_mangle] + pub extern "C" + fn submission_set_ui(submission: *mut Submission, ui_manager: *const UIManager) { + if submission.is_null() { + panic!("Null submission pointer"); + } + let submission: &mut Submission = unsafe { &mut *submission }; + if let Some(ref mut imservice) = &mut submission.imservice { + imservice.ui_manager = if ui_manager.is_null() { + None + } else { + Some(ui_manager) + } + }; + } + + #[no_mangle] + pub extern "C" + fn submission_set_keyboard(submission: *mut Submission, keyboard: LevelKeyboard) { + if submission.is_null() { + panic!("Null submission pointer"); + } + let submission: &mut Submission = unsafe { &mut *submission }; + submission.virtual_keyboard.update_keymap(keyboard); } } #[derive(Clone, Copy)] pub struct Timestamp(pub u32); -/// Layout-independent backend. TODO: Have one instance per program or seat -pub struct VirtualKeyboard(pub c::ZwpVirtualKeyboardV1); - -impl VirtualKeyboard { - // TODO: split out keyboard state management - pub fn switch( - &self, - keycodes: &Vec, - action: PressType, - timestamp: Timestamp, - ) { - let keycodes_count = keycodes.len(); - for keycode in keycodes.iter() { - let keycode = keycode - 8; - match (action, keycodes_count) { - // Pressing a key made out of a single keycode is simple: - // press on press, release on release. - (_, 1) => unsafe { - c::eek_virtual_keyboard_v1_key( - self.0, timestamp.0, keycode, action.clone() as u32 - ); - }, - // A key made of multiple keycodes - // has to submit them one after the other - (PressType::Pressed, _) => unsafe { - c::eek_virtual_keyboard_v1_key( - self.0, timestamp.0, keycode, PressType::Pressed as u32 - ); - c::eek_virtual_keyboard_v1_key( - self.0, timestamp.0, keycode, PressType::Released as u32 - ); - }, - // Design choice here: submit multiple all at press time - // and do nothing at release time - (PressType::Released, _) => {}, - } - } - } +pub struct Submission { + // used by C callbacks internally, TODO: make use with virtual keyboard + #[allow(dead_code)] + imservice: Option>, + pub virtual_keyboard: VirtualKeyboard, } diff --git a/src/vkeyboard.rs b/src/vkeyboard.rs new file mode 100644 index 00000000..aac5d18f --- /dev/null +++ b/src/vkeyboard.rs @@ -0,0 +1,79 @@ +/*! Managing the events belonging to virtual-keyboard interface. */ + +use ::keyboard::{ KeyCode, PressType }; +use ::layout::c::LevelKeyboard; +use ::submission::Timestamp; + +/// Gathers stuff defined in C or called by C +pub mod c { + use super::*; + use std::os::raw::c_void; + + #[repr(transparent)] + #[derive(Clone, Copy)] + pub struct ZwpVirtualKeyboardV1(*const c_void); + + #[no_mangle] + extern "C" { + pub fn eek_virtual_keyboard_v1_key( + virtual_keyboard: ZwpVirtualKeyboardV1, + timestamp: u32, + keycode: u32, + press: u32, + ); + + pub fn eek_virtual_keyboard_update_keymap( + virtual_keyboard: ZwpVirtualKeyboardV1, + keyboard: LevelKeyboard, + ); + } +} + +/// Layout-independent backend. TODO: Have one instance per program or seat +pub struct VirtualKeyboard(pub c::ZwpVirtualKeyboardV1); + +impl VirtualKeyboard { + // TODO: split out keyboard state management + pub fn switch( + &self, + keycodes: &Vec, + action: PressType, + timestamp: Timestamp, + ) { + let keycodes_count = keycodes.len(); + for keycode in keycodes.iter() { + let keycode = keycode - 8; + match (action, keycodes_count) { + // Pressing a key made out of a single keycode is simple: + // press on press, release on release. + (_, 1) => unsafe { + c::eek_virtual_keyboard_v1_key( + self.0, timestamp.0, keycode, action.clone() as u32 + ); + }, + // A key made of multiple keycodes + // has to submit them one after the other + (PressType::Pressed, _) => unsafe { + c::eek_virtual_keyboard_v1_key( + self.0, timestamp.0, keycode, PressType::Pressed as u32 + ); + c::eek_virtual_keyboard_v1_key( + self.0, timestamp.0, keycode, PressType::Released as u32 + ); + }, + // Design choice here: submit multiple all at press time + // and do nothing at release time + (PressType::Released, _) => {}, + } + } + } + + pub fn update_keymap(&self, keyboard: LevelKeyboard) { + unsafe { + c::eek_virtual_keyboard_update_keymap( + self.0, + keyboard, + ); + } + } +} diff --git a/src/wayland.c b/src/wayland.c index 96b037f4..42ba59df 100644 --- a/src/wayland.c +++ b/src/wayland.c @@ -1,3 +1,5 @@ +#include "eek/eek-keyboard.h" + #include "wayland.h" struct squeek_wayland *squeek_wayland = NULL; @@ -11,6 +13,13 @@ eek_virtual_keyboard_v1_key(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard zwp_virtual_keyboard_v1_key(zwp_virtual_keyboard_v1, time, key, state); } + +void eek_virtual_keyboard_update_keymap(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, const LevelKeyboard *keyboard) { + zwp_virtual_keyboard_v1_keymap(zwp_virtual_keyboard_v1, + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, + keyboard->keymap_fd, keyboard->keymap_len); +} + int squeek_output_add_listener(struct wl_output *wl_output, const struct wl_output_listener *listener, void *data) { return wl_output_add_listener(wl_output, listener, data);