Merge branch 'text_input' into 'master'
Text input integration See merge request Librem5/squeekboard!302
This commit is contained in:
@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
#include "eekboard/eekboard-context-service.h"
|
#include "eekboard/eekboard-context-service.h"
|
||||||
#include "src/layout.h"
|
#include "src/layout.h"
|
||||||
|
#include "src/submission.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PROP_0,
|
PROP_0,
|
||||||
@ -54,6 +55,8 @@ enum {
|
|||||||
typedef struct _EekGtkKeyboardPrivate
|
typedef struct _EekGtkKeyboardPrivate
|
||||||
{
|
{
|
||||||
EekRenderer *renderer;
|
EekRenderer *renderer;
|
||||||
|
EekboardContextService *eekboard_context; // unowned reference
|
||||||
|
struct submission *submission; // unowned reference
|
||||||
LevelKeyboard *keyboard; // unowned reference; it's kept in server-context (FIXME)
|
LevelKeyboard *keyboard; // unowned reference; it's kept in server-context (FIXME)
|
||||||
|
|
||||||
GdkEventSequence *sequence; // unowned reference
|
GdkEventSequence *sequence; // unowned reference
|
||||||
@ -122,7 +125,8 @@ static void depress(EekGtkKeyboard *self,
|
|||||||
{
|
{
|
||||||
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (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);
|
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)
|
gdouble x, gdouble y, guint32 time)
|
||||||
{
|
{
|
||||||
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
|
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,
|
x, y, eek_renderer_get_transformation(priv->renderer), time,
|
||||||
priv->keyboard->manager, self);
|
priv->eekboard_context, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void release(EekGtkKeyboard *self, guint32 time)
|
static void release(EekGtkKeyboard *self, guint32 time)
|
||||||
{
|
{
|
||||||
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
|
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,
|
eek_renderer_get_transformation(priv->renderer), time,
|
||||||
priv->keyboard->manager, self);
|
priv->eekboard_context, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -229,7 +235,8 @@ eek_gtk_keyboard_real_unmap (GtkWidget *self)
|
|||||||
|
|
||||||
if (priv->keyboard) {
|
if (priv->keyboard) {
|
||||||
squeek_layout_release_all_only(
|
squeek_layout_release_all_only(
|
||||||
priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard,
|
priv->keyboard->layout,
|
||||||
|
priv->submission,
|
||||||
gdk_event_get_time(NULL));
|
gdk_event_get_time(NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +271,8 @@ eek_gtk_keyboard_dispose (GObject *object)
|
|||||||
|
|
||||||
if (priv->keyboard) {
|
if (priv->keyboard) {
|
||||||
squeek_layout_release_all_only(
|
squeek_layout_release_all_only(
|
||||||
priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard,
|
priv->keyboard->layout,
|
||||||
|
priv->submission,
|
||||||
gdk_event_get_time(NULL));
|
gdk_event_get_time(NULL));
|
||||||
priv->keyboard = NULL;
|
priv->keyboard = NULL;
|
||||||
}
|
}
|
||||||
@ -311,11 +319,14 @@ eek_gtk_keyboard_init (EekGtkKeyboard *self)
|
|||||||
* Returns: a #GtkWidget
|
* Returns: a #GtkWidget
|
||||||
*/
|
*/
|
||||||
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));
|
EekGtkKeyboard *ret = EEK_GTK_KEYBOARD(g_object_new (EEK_TYPE_GTK_KEYBOARD, NULL));
|
||||||
EekGtkKeyboardPrivate *priv = (EekGtkKeyboardPrivate*)eek_gtk_keyboard_get_instance_private (ret);
|
EekGtkKeyboardPrivate *priv = (EekGtkKeyboardPrivate*)eek_gtk_keyboard_get_instance_private (ret);
|
||||||
priv->keyboard = keyboard;
|
priv->keyboard = keyboard;
|
||||||
|
priv->eekboard_context = eekservice;
|
||||||
|
priv->submission = submission;
|
||||||
return GTK_WIDGET(ret);
|
return GTK_WIDGET(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,9 @@
|
|||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
#include "eek/eek-types.h"
|
||||||
|
|
||||||
|
struct submission;
|
||||||
typedef struct _LevelKeyboard LevelKeyboard; // including causes weird bugs
|
typedef struct _LevelKeyboard LevelKeyboard; // including causes weird bugs
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
@ -45,7 +48,7 @@ struct _EekGtkKeyboardClass
|
|||||||
};
|
};
|
||||||
|
|
||||||
GType eek_gtk_keyboard_get_type (void) G_GNUC_CONST;
|
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
|
G_END_DECLS
|
||||||
#endif /* EEK_GTK_KEYBOARD_H */
|
#endif /* EEK_GTK_KEYBOARD_H */
|
||||||
|
|||||||
@ -18,40 +18,78 @@
|
|||||||
* 02110-1301 USA
|
* 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 "config.h"
|
||||||
#include <glib/gprintf.h>
|
|
||||||
|
|
||||||
#include "eekboard/eekboard-context-service.h"
|
#define _XOPEN_SOURCE 500
|
||||||
#include "keymap.h"
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/random.h> // TODO: this is Linux-specific
|
||||||
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
||||||
|
|
||||||
#include "eek-keyboard.h"
|
#include "eek-keyboard.h"
|
||||||
|
|
||||||
void level_keyboard_deinit(LevelKeyboard *self) {
|
void level_keyboard_free(LevelKeyboard *self) {
|
||||||
xkb_keymap_unref(self->keymap);
|
xkb_keymap_unref(self->keymap);
|
||||||
close(self->keymap_fd);
|
close(self->keymap_fd);
|
||||||
squeek_layout_free(self->layout);
|
squeek_layout_free(self->layout);
|
||||||
}
|
|
||||||
|
|
||||||
void level_keyboard_free(LevelKeyboard *self) {
|
|
||||||
level_keyboard_deinit(self);
|
|
||||||
g_free(self);
|
g_free(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void level_keyboard_init(LevelKeyboard *self, struct squeek_layout *layout) {
|
LevelKeyboard*
|
||||||
self->layout = layout;
|
level_keyboard_new (const gchar *keyboard_type,
|
||||||
}
|
enum squeek_arrangement_kind t)
|
||||||
|
{
|
||||||
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_layout *layout) {
|
struct squeek_layout *layout = squeek_load_layout(keyboard_type, t);
|
||||||
LevelKeyboard *keyboard = g_new0(LevelKeyboard, 1);
|
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;
|
return keyboard;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,16 +40,15 @@ struct _LevelKeyboard {
|
|||||||
size_t keymap_len; // length of the data inside keymap_fd
|
size_t keymap_len; // length of the data inside keymap_fd
|
||||||
|
|
||||||
guint id; // as a key to layout choices
|
guint id; // as a key to layout choices
|
||||||
|
|
||||||
EekboardContextService *manager; // unowned reference
|
|
||||||
};
|
};
|
||||||
typedef struct _LevelKeyboard LevelKeyboard;
|
typedef struct _LevelKeyboard LevelKeyboard;
|
||||||
|
|
||||||
gchar * eek_keyboard_get_keymap
|
gchar * eek_keyboard_get_keymap
|
||||||
(LevelKeyboard *keyboard);
|
(LevelKeyboard *keyboard);
|
||||||
|
|
||||||
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_layout *layout);
|
LevelKeyboard*
|
||||||
void level_keyboard_deinit(LevelKeyboard *self);
|
level_keyboard_new (const gchar *keyboard_type,
|
||||||
|
enum squeek_arrangement_kind t);
|
||||||
void level_keyboard_free(LevelKeyboard *self);
|
void level_keyboard_free(LevelKeyboard *self);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|||||||
@ -38,6 +38,7 @@ G_BEGIN_DECLS
|
|||||||
typedef struct _EekBounds EekBounds;
|
typedef struct _EekBounds EekBounds;
|
||||||
|
|
||||||
typedef struct _EekboardContextService EekboardContextService;
|
typedef struct _EekboardContextService EekboardContextService;
|
||||||
|
typedef struct _ServerContextService ServerContextService;
|
||||||
typedef struct _LevelKeyboard LevelKeyboard;
|
typedef struct _LevelKeyboard LevelKeyboard;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if !defined(__EEK_H_INSIDE__) && !defined(EEK_COMPILATION)
|
|
||||||
#error "Only <eek/eek.h> 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 */
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
#include <gdk/gdk.h>
|
|
||||||
#include <xkbcommon/xkbcommon.h>
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
squeek_keymap_get_entries_for_keyval (struct xkb_keymap *xkb_keymap,
|
|
||||||
guint keyval,
|
|
||||||
GdkKeymapKey **keys,
|
|
||||||
guint *n_keys);
|
|
||||||
@ -16,30 +16,15 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 "config.h"
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#define _XOPEN_SOURCE 500
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/random.h> // TODO: this is Linux-specific
|
|
||||||
#include <xkbcommon/xkbcommon.h>
|
|
||||||
|
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
|
|
||||||
#include "wayland.h"
|
#include "wayland.h"
|
||||||
|
|
||||||
#include "eek/eek-xml-layout.h"
|
#include "eek/eek-keyboard.h"
|
||||||
#include "src/server-context-service.h"
|
#include "src/server-context-service.h"
|
||||||
|
|
||||||
#include "eekboard/eekboard-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 TODO: it's used only for fetching layout type.
|
||||||
// Maybe let UI push the type to this structure?
|
// Maybe let UI push the type to this structure?
|
||||||
ServerContextService *ui; // unowned reference
|
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);
|
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
|
static void
|
||||||
eekboard_context_service_set_property (GObject *object,
|
eekboard_context_service_set_property (GObject *object,
|
||||||
guint prop_id,
|
guint prop_id,
|
||||||
@ -217,15 +149,15 @@ eekboard_context_service_update_layout(EekboardContextService *context, enum squ
|
|||||||
}
|
}
|
||||||
|
|
||||||
// generic part follows
|
// 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
|
// set as current
|
||||||
LevelKeyboard *previous_keyboard = context->priv->keyboard;
|
LevelKeyboard *previous_keyboard = context->priv->keyboard;
|
||||||
context->priv->keyboard = keyboard;
|
context->priv->keyboard = keyboard;
|
||||||
|
// Update the keymap if necessary.
|
||||||
// The keymap will get set even if the window is hidden.
|
// TODO: Update submission on change event
|
||||||
// It's not perfect,
|
if (context->priv->submission) {
|
||||||
// but simpler than adding a check in the window showing procedure
|
submission_set_keyboard(context->priv->submission, keyboard);
|
||||||
eekboard_context_service_set_keymap(context, keyboard);
|
}
|
||||||
|
|
||||||
g_object_notify (G_OBJECT(context), "keyboard");
|
g_object_notify (G_OBJECT(context), "keyboard");
|
||||||
|
|
||||||
@ -262,12 +194,6 @@ static void
|
|||||||
eekboard_context_service_constructed (GObject *object)
|
eekboard_context_service_constructed (GObject *object)
|
||||||
{
|
{
|
||||||
EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE (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);
|
update_layout_and_type(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,14 +289,6 @@ eekboard_context_service_get_keyboard (EekboardContextService *context)
|
|||||||
return context->priv->keyboard;
|
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,
|
void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
|
||||||
uint32_t hint, uint32_t purpose)
|
uint32_t hint, uint32_t purpose)
|
||||||
{
|
{
|
||||||
@ -394,7 +312,13 @@ eekboard_context_service_get_overlay(EekboardContextService *context) {
|
|||||||
return context->priv->overlay;
|
return context->priv->overlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
EekboardContextService *eekboard_context_service_new()
|
EekboardContextService *eekboard_context_service_new(void)
|
||||||
{
|
{
|
||||||
return g_object_new (EEKBOARD_TYPE_CONTEXT_SERVICE, NULL);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -22,7 +22,8 @@
|
|||||||
#ifndef EEKBOARD_CONTEXT_SERVICE_H
|
#ifndef EEKBOARD_CONTEXT_SERVICE_H
|
||||||
#define EEKBOARD_CONTEXT_SERVICE_H 1
|
#define EEKBOARD_CONTEXT_SERVICE_H 1
|
||||||
|
|
||||||
#include <eek/eek.h>
|
#include "src/submission.h"
|
||||||
|
#include "src/layout.h"
|
||||||
|
|
||||||
#include "virtual-keyboard-unstable-v1-client-protocol.h"
|
#include "virtual-keyboard-unstable-v1-client-protocol.h"
|
||||||
#include "text-input-unstable-v3-client-protocol.h"
|
#include "text-input-unstable-v3-client-protocol.h"
|
||||||
@ -58,8 +59,6 @@ struct _EekboardContextService {
|
|||||||
GObject parent;
|
GObject parent;
|
||||||
|
|
||||||
EekboardContextServicePrivate *priv;
|
EekboardContextServicePrivate *priv;
|
||||||
|
|
||||||
struct zwp_virtual_keyboard_v1 *virtual_keyboard;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -84,10 +83,10 @@ struct _EekboardContextServiceClass {
|
|||||||
gpointer pdummy[24];
|
gpointer pdummy[24];
|
||||||
};
|
};
|
||||||
|
|
||||||
EekboardContextService *eekboard_context_service_new();
|
|
||||||
GType eekboard_context_service_get_type
|
GType eekboard_context_service_get_type
|
||||||
(void) G_GNUC_CONST;
|
(void) G_GNUC_CONST;
|
||||||
EekboardContextService *eekboard_context_service_new(void);
|
EekboardContextService *eekboard_context_service_new(void);
|
||||||
|
void eekboard_context_service_set_submission(EekboardContextService *context, struct submission *submission);
|
||||||
void eekboard_context_service_destroy (EekboardContextService *context);
|
void eekboard_context_service_destroy (EekboardContextService *context);
|
||||||
LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *context);
|
LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *context);
|
||||||
|
|
||||||
|
|||||||
@ -1,28 +1,52 @@
|
|||||||
#include "imservice.h"
|
#include "submission.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
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 = {
|
static const struct zwp_input_method_v2_listener input_method_listener = {
|
||||||
.activate = imservice_handle_input_method_activate,
|
.activate = imservice_handle_input_method_activate,
|
||||||
.deactivate = imservice_handle_input_method_deactivate,
|
.deactivate = imservice_handle_input_method_deactivate,
|
||||||
.surrounding_text = imservice_handle_surrounding_text,
|
.surrounding_text = imservice_handle_surrounding_text,
|
||||||
.text_change_cause = imservice_handle_text_change_cause,
|
.text_change_cause = imservice_handle_text_change_cause,
|
||||||
.content_type = imservice_handle_content_type,
|
.content_type = imservice_handle_content_type,
|
||||||
.done = imservice_handle_commit_state,
|
.done = imservice_handle_done,
|
||||||
.unavailable = imservice_handle_unavailable,
|
.unavailable = imservice_handle_unavailable,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct imservice* get_imservice(struct zwp_input_method_manager_v2 *manager,
|
struct submission* get_submission(struct zwp_input_method_manager_v2 *immanager,
|
||||||
|
struct zwp_virtual_keyboard_manager_v1 *vkmanager,
|
||||||
struct wl_seat *seat,
|
struct wl_seat *seat,
|
||||||
EekboardContextService *state) {
|
EekboardContextService *state) {
|
||||||
struct zwp_input_method_v2 *im = zwp_input_method_manager_v2_get_input_method(manager, seat);
|
struct zwp_input_method_v2 *im = NULL;
|
||||||
struct imservice *imservice = imservice_new(im, state);
|
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
|
/// Un-inlined
|
||||||
callbacks. */
|
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);
|
zwp_input_method_v2_add_listener(im, &input_method_listener, imservice);
|
||||||
|
|
||||||
return imservice;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Declared explicitly because _destroy is inline,
|
/// Declared explicitly because _destroy is inline,
|
||||||
|
|||||||
@ -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
|
|
||||||
|
|||||||
107
src/imservice.rs
107
src/imservice.rs
@ -15,23 +15,20 @@ pub mod c {
|
|||||||
|
|
||||||
use std::os::raw::{c_char, c_void};
|
use std::os::raw::{c_char, c_void};
|
||||||
|
|
||||||
|
pub use ::submission::c::UIManager;
|
||||||
|
pub use ::submission::c::StateManager;
|
||||||
|
|
||||||
// The following defined in C
|
// The following defined in C
|
||||||
|
|
||||||
/// struct zwp_input_method_v2*
|
/// struct zwp_input_method_v2*
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct InputMethod(*const c_void);
|
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]
|
#[no_mangle]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn imservice_destroy_im(im: *mut c::InputMethod);
|
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 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_show_keyboard(imservice: *const UIManager);
|
||||||
fn server_context_service_hide_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
|
// 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::<IMService>::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?
|
// TODO: is unsafe needed here?
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C"
|
pub extern "C"
|
||||||
fn imservice_handle_input_method_activate(imservice: *mut IMService,
|
fn imservice_handle_input_method_activate(imservice: *mut IMService,
|
||||||
im: *const InputMethod)
|
im: *const InputMethod)
|
||||||
{
|
{
|
||||||
@ -87,7 +51,7 @@ pub mod c {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C"
|
pub extern "C"
|
||||||
fn imservice_handle_input_method_deactivate(imservice: *mut IMService,
|
fn imservice_handle_input_method_deactivate(imservice: *mut IMService,
|
||||||
im: *const InputMethod)
|
im: *const InputMethod)
|
||||||
{
|
{
|
||||||
@ -99,7 +63,7 @@ pub mod c {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C"
|
pub extern "C"
|
||||||
fn imservice_handle_surrounding_text(imservice: *mut IMService,
|
fn imservice_handle_surrounding_text(imservice: *mut IMService,
|
||||||
im: *const InputMethod,
|
im: *const InputMethod,
|
||||||
text: *const c_char, cursor: u32, _anchor: u32)
|
text: *const c_char, cursor: u32, _anchor: u32)
|
||||||
@ -115,7 +79,7 @@ pub mod c {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C"
|
pub extern "C"
|
||||||
fn imservice_handle_content_type(imservice: *mut IMService,
|
fn imservice_handle_content_type(imservice: *mut IMService,
|
||||||
im: *const InputMethod,
|
im: *const InputMethod,
|
||||||
hint: u32, purpose: u32)
|
hint: u32, purpose: u32)
|
||||||
@ -139,7 +103,7 @@ pub mod c {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C"
|
pub extern "C"
|
||||||
fn imservice_handle_text_change_cause(imservice: *mut IMService,
|
fn imservice_handle_text_change_cause(imservice: *mut IMService,
|
||||||
im: *const InputMethod,
|
im: *const InputMethod,
|
||||||
cause: u32)
|
cause: u32)
|
||||||
@ -157,14 +121,13 @@ pub mod c {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C"
|
pub extern "C"
|
||||||
fn imservice_handle_commit_state(imservice: *mut IMService,
|
fn imservice_handle_done(imservice: *mut IMService,
|
||||||
im: *const InputMethod)
|
im: *const InputMethod)
|
||||||
{
|
{
|
||||||
let imservice = check_imservice(imservice, im).unwrap();
|
let imservice = check_imservice(imservice, im).unwrap();
|
||||||
let active_changed = imservice.current.active ^ imservice.pending.active;
|
let active_changed = imservice.current.active ^ imservice.pending.active;
|
||||||
|
|
||||||
imservice.serial += Wrapping(1u32);
|
|
||||||
imservice.current = imservice.pending.clone();
|
imservice.current = imservice.pending.clone();
|
||||||
imservice.pending = IMProtocolState {
|
imservice.pending = IMProtocolState {
|
||||||
active: imservice.current.active,
|
active: imservice.current.active,
|
||||||
@ -174,34 +137,38 @@ pub mod c {
|
|||||||
if active_changed {
|
if active_changed {
|
||||||
if imservice.current.active {
|
if imservice.current.active {
|
||||||
if let Some(ui) = imservice.ui_manager {
|
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(
|
eekboard_context_service_set_hint_purpose(
|
||||||
imservice.state_manager,
|
imservice.state_manager,
|
||||||
imservice.current.content_hint.bits(),
|
imservice.current.content_hint.bits(),
|
||||||
imservice.current.content_purpose.clone() as u32);
|
imservice.current.content_purpose.clone() as u32,
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Some(ui) = imservice.ui_manager {
|
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]
|
#[no_mangle]
|
||||||
pub unsafe extern "C"
|
pub extern "C"
|
||||||
fn imservice_handle_unavailable(imservice: *mut IMService,
|
fn imservice_handle_unavailable(imservice: *mut IMService,
|
||||||
im: *mut InputMethod)
|
im: *mut InputMethod)
|
||||||
{
|
{
|
||||||
let imservice = check_imservice(imservice, im).unwrap();
|
let imservice = check_imservice(imservice, im).unwrap();
|
||||||
imservice_destroy_im(im);
|
unsafe { imservice_destroy_im(im); }
|
||||||
|
|
||||||
// no need to care about proper double-buffering,
|
// no need to care about proper double-buffering,
|
||||||
// the keyboard is already decommissioned
|
// the keyboard is already decommissioned
|
||||||
imservice.current.active = false;
|
imservice.current.active = false;
|
||||||
|
|
||||||
if let Some(ui) = imservice.ui_manager {
|
if let Some(ui) = imservice.ui_manager {
|
||||||
server_context_service_hide_keyboard(ui);
|
unsafe { server_context_service_hide_keyboard(ui); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,12 +316,38 @@ pub struct IMService {
|
|||||||
/// Owned reference (still created and destroyed in C)
|
/// Owned reference (still created and destroyed in C)
|
||||||
pub im: *const c::InputMethod,
|
pub im: *const c::InputMethod,
|
||||||
/// Unowned reference. Be careful, it's shared with C at large
|
/// 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,
|
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,
|
pending: IMProtocolState,
|
||||||
current: IMProtocolState, // turn current into an idiomatic representation?
|
current: IMProtocolState, // turn current into an idiomatic representation?
|
||||||
preedit_string: String,
|
preedit_string: String,
|
||||||
serial: Wrapping<u32>,
|
serial: Wrapping<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IMService {
|
||||||
|
pub fn new(
|
||||||
|
im: *mut c::InputMethod,
|
||||||
|
state_manager: *const c::StateManager,
|
||||||
|
) -> Box<IMService> {
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
13
src/layout.h
13
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 *);
|
enum squeek_arrangement_kind squeek_layout_get_kind(const struct squeek_layout *);
|
||||||
void squeek_layout_free(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,
|
struct transformation widget_to_layout,
|
||||||
uint32_t timestamp,
|
uint32_t timestamp,
|
||||||
EekboardContextService *manager,
|
EekboardContextService *manager,
|
||||||
EekGtkKeyboard *ui_keyboard);
|
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_release_all_only(struct squeek_layout *layout,
|
||||||
void squeek_layout_depress(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard,
|
struct submission *submission,
|
||||||
|
uint32_t timestamp);
|
||||||
|
void squeek_layout_depress(struct squeek_layout *layout,
|
||||||
|
struct submission *submission,
|
||||||
double x_widget, double y_widget,
|
double x_widget, double y_widget,
|
||||||
struct transformation widget_to_layout,
|
struct transformation widget_to_layout,
|
||||||
uint32_t timestamp, EekGtkKeyboard *ui_keyboard);
|
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,
|
double x_widget, double y_widget,
|
||||||
struct transformation widget_to_layout,
|
struct transformation widget_to_layout,
|
||||||
uint32_t timestamp, EekboardContextService *manager,
|
uint32_t timestamp, EekboardContextService *manager,
|
||||||
|
|||||||
@ -27,7 +27,7 @@ use ::action::Action;
|
|||||||
use ::drawing;
|
use ::drawing;
|
||||||
use ::keyboard::{ KeyState, PressType };
|
use ::keyboard::{ KeyState, PressType };
|
||||||
use ::manager;
|
use ::manager;
|
||||||
use ::submission::{ Timestamp, VirtualKeyboard };
|
use ::submission::{ Submission, Timestamp };
|
||||||
use ::util::find_max_double;
|
use ::util::find_max_double;
|
||||||
|
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
@ -144,6 +144,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
|
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -244,19 +249,12 @@ pub mod c {
|
|||||||
pub mod procedures {
|
pub mod procedures {
|
||||||
use super::*;
|
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
|
/// Release pointer in the specified position
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_layout_release(
|
fn squeek_layout_release(
|
||||||
layout: *mut Layout,
|
layout: *mut Layout,
|
||||||
virtual_keyboard: ZwpVirtualKeyboardV1, // TODO: receive a reference to the backend
|
submission: *mut Submission,
|
||||||
widget_to_layout: Transformation,
|
widget_to_layout: Transformation,
|
||||||
time: u32,
|
time: u32,
|
||||||
manager: manager::c::Manager,
|
manager: manager::c::Manager,
|
||||||
@ -264,7 +262,7 @@ pub mod c {
|
|||||||
) {
|
) {
|
||||||
let time = Timestamp(time);
|
let time = Timestamp(time);
|
||||||
let layout = unsafe { &mut *layout };
|
let layout = unsafe { &mut *layout };
|
||||||
let virtual_keyboard = VirtualKeyboard(virtual_keyboard);
|
let submission = unsafe { &mut *submission };
|
||||||
let ui_backend = UIBackend {
|
let ui_backend = UIBackend {
|
||||||
widget_to_layout,
|
widget_to_layout,
|
||||||
keyboard: ui_keyboard,
|
keyboard: ui_keyboard,
|
||||||
@ -276,7 +274,7 @@ pub mod c {
|
|||||||
let key: &Rc<RefCell<KeyState>> = key.borrow();
|
let key: &Rc<RefCell<KeyState>> = key.borrow();
|
||||||
seat::handle_release_key(
|
seat::handle_release_key(
|
||||||
layout,
|
layout,
|
||||||
&virtual_keyboard,
|
submission,
|
||||||
Some(&ui_backend),
|
Some(&ui_backend),
|
||||||
time,
|
time,
|
||||||
Some(manager),
|
Some(manager),
|
||||||
@ -291,18 +289,18 @@ pub mod c {
|
|||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_layout_release_all_only(
|
fn squeek_layout_release_all_only(
|
||||||
layout: *mut Layout,
|
layout: *mut Layout,
|
||||||
virtual_keyboard: ZwpVirtualKeyboardV1, // TODO: receive a reference to the backend
|
submission: *mut Submission,
|
||||||
time: u32,
|
time: u32,
|
||||||
) {
|
) {
|
||||||
let layout = unsafe { &mut *layout };
|
let layout = unsafe { &mut *layout };
|
||||||
let virtual_keyboard = VirtualKeyboard(virtual_keyboard);
|
let submission = unsafe { &mut *submission };
|
||||||
// The list must be copied,
|
// The list must be copied,
|
||||||
// because it will be mutated in the loop
|
// because it will be mutated in the loop
|
||||||
for key in layout.pressed_keys.clone() {
|
for key in layout.pressed_keys.clone() {
|
||||||
let key: &Rc<RefCell<KeyState>> = key.borrow();
|
let key: &Rc<RefCell<KeyState>> = key.borrow();
|
||||||
seat::handle_release_key(
|
seat::handle_release_key(
|
||||||
layout,
|
layout,
|
||||||
&virtual_keyboard,
|
submission,
|
||||||
None, // don't update UI
|
None, // don't update UI
|
||||||
Timestamp(time),
|
Timestamp(time),
|
||||||
None, // don't switch layouts
|
None, // don't switch layouts
|
||||||
@ -315,13 +313,14 @@ pub mod c {
|
|||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_layout_depress(
|
fn squeek_layout_depress(
|
||||||
layout: *mut Layout,
|
layout: *mut Layout,
|
||||||
virtual_keyboard: ZwpVirtualKeyboardV1, // TODO: receive a reference to the backend
|
submission: *mut Submission,
|
||||||
x_widget: f64, y_widget: f64,
|
x_widget: f64, y_widget: f64,
|
||||||
widget_to_layout: Transformation,
|
widget_to_layout: Transformation,
|
||||||
time: u32,
|
time: u32,
|
||||||
ui_keyboard: EekGtkKeyboard,
|
ui_keyboard: EekGtkKeyboard,
|
||||||
) {
|
) {
|
||||||
let layout = unsafe { &mut *layout };
|
let layout = unsafe { &mut *layout };
|
||||||
|
let submission = unsafe { &mut *submission };
|
||||||
let point = widget_to_layout.forward(
|
let point = widget_to_layout.forward(
|
||||||
Point { x: x_widget, y: y_widget }
|
Point { x: x_widget, y: y_widget }
|
||||||
);
|
);
|
||||||
@ -335,7 +334,7 @@ pub mod c {
|
|||||||
if let Some(state) = state {
|
if let Some(state) = state {
|
||||||
seat::handle_press_key(
|
seat::handle_press_key(
|
||||||
layout,
|
layout,
|
||||||
&VirtualKeyboard(virtual_keyboard),
|
submission,
|
||||||
Timestamp(time),
|
Timestamp(time),
|
||||||
&state,
|
&state,
|
||||||
);
|
);
|
||||||
@ -351,7 +350,7 @@ pub mod c {
|
|||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_layout_drag(
|
fn squeek_layout_drag(
|
||||||
layout: *mut Layout,
|
layout: *mut Layout,
|
||||||
virtual_keyboard: ZwpVirtualKeyboardV1, // TODO: receive a reference to the backend
|
submission: *mut Submission,
|
||||||
x_widget: f64, y_widget: f64,
|
x_widget: f64, y_widget: f64,
|
||||||
widget_to_layout: Transformation,
|
widget_to_layout: Transformation,
|
||||||
time: u32,
|
time: u32,
|
||||||
@ -360,7 +359,7 @@ pub mod c {
|
|||||||
) {
|
) {
|
||||||
let time = Timestamp(time);
|
let time = Timestamp(time);
|
||||||
let layout = unsafe { &mut *layout };
|
let layout = unsafe { &mut *layout };
|
||||||
let virtual_keyboard = VirtualKeyboard(virtual_keyboard);
|
let submission = unsafe { &mut *submission };
|
||||||
let ui_backend = UIBackend {
|
let ui_backend = UIBackend {
|
||||||
widget_to_layout,
|
widget_to_layout,
|
||||||
keyboard: ui_keyboard,
|
keyboard: ui_keyboard,
|
||||||
@ -389,7 +388,7 @@ pub mod c {
|
|||||||
} else {
|
} else {
|
||||||
seat::handle_release_key(
|
seat::handle_release_key(
|
||||||
layout,
|
layout,
|
||||||
&virtual_keyboard,
|
submission,
|
||||||
Some(&ui_backend),
|
Some(&ui_backend),
|
||||||
time,
|
time,
|
||||||
Some(manager),
|
Some(manager),
|
||||||
@ -400,7 +399,7 @@ pub mod c {
|
|||||||
if !found {
|
if !found {
|
||||||
seat::handle_press_key(
|
seat::handle_press_key(
|
||||||
layout,
|
layout,
|
||||||
&virtual_keyboard,
|
submission,
|
||||||
time,
|
time,
|
||||||
&state,
|
&state,
|
||||||
);
|
);
|
||||||
@ -411,7 +410,7 @@ pub mod c {
|
|||||||
let key: &Rc<RefCell<KeyState>> = wrapped_key.borrow();
|
let key: &Rc<RefCell<KeyState>> = wrapped_key.borrow();
|
||||||
seat::handle_release_key(
|
seat::handle_release_key(
|
||||||
layout,
|
layout,
|
||||||
&virtual_keyboard,
|
submission,
|
||||||
Some(&ui_backend),
|
Some(&ui_backend),
|
||||||
time,
|
time,
|
||||||
Some(manager),
|
Some(manager),
|
||||||
@ -854,7 +853,7 @@ mod seat {
|
|||||||
|
|
||||||
pub fn handle_press_key(
|
pub fn handle_press_key(
|
||||||
layout: &mut Layout,
|
layout: &mut Layout,
|
||||||
virtual_keyboard: &VirtualKeyboard,
|
submission: &mut Submission,
|
||||||
time: Timestamp,
|
time: Timestamp,
|
||||||
rckey: &Rc<RefCell<KeyState>>,
|
rckey: &Rc<RefCell<KeyState>>,
|
||||||
) {
|
) {
|
||||||
@ -862,7 +861,7 @@ mod seat {
|
|||||||
eprintln!("Warning: key {:?} was already pressed", rckey);
|
eprintln!("Warning: key {:?} was already pressed", rckey);
|
||||||
}
|
}
|
||||||
let mut key = rckey.borrow_mut();
|
let mut key = rckey.borrow_mut();
|
||||||
virtual_keyboard.switch(
|
submission.virtual_keyboard.switch(
|
||||||
&key.keycodes,
|
&key.keycodes,
|
||||||
PressType::Pressed,
|
PressType::Pressed,
|
||||||
time,
|
time,
|
||||||
@ -872,7 +871,7 @@ mod seat {
|
|||||||
|
|
||||||
pub fn handle_release_key(
|
pub fn handle_release_key(
|
||||||
layout: &mut Layout,
|
layout: &mut Layout,
|
||||||
virtual_keyboard: &VirtualKeyboard,
|
submission: &mut Submission,
|
||||||
ui: Option<&UIBackend>,
|
ui: Option<&UIBackend>,
|
||||||
time: Timestamp,
|
time: Timestamp,
|
||||||
manager: Option<manager::c::Manager>,
|
manager: Option<manager::c::Manager>,
|
||||||
@ -894,7 +893,7 @@ mod seat {
|
|||||||
match action {
|
match action {
|
||||||
Action::Submit { text: _, keys: _ } => {
|
Action::Submit { text: _, keys: _ } => {
|
||||||
unstick_locks(layout).apply();
|
unstick_locks(layout).apply();
|
||||||
virtual_keyboard.switch(
|
submission.virtual_keyboard.switch(
|
||||||
&key.keycodes,
|
&key.keycodes,
|
||||||
PressType::Released,
|
PressType::Released,
|
||||||
time,
|
time,
|
||||||
|
|||||||
@ -29,8 +29,9 @@ mod manager;
|
|||||||
mod outputs;
|
mod outputs;
|
||||||
mod popover;
|
mod popover;
|
||||||
mod resources;
|
mod resources;
|
||||||
mod submission;
|
|
||||||
mod style;
|
mod style;
|
||||||
|
mod submission;
|
||||||
pub mod tests;
|
pub mod tests;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
mod vkeyboard;
|
||||||
mod xdg;
|
mod xdg;
|
||||||
|
|||||||
@ -22,7 +22,6 @@ sources = [
|
|||||||
'../eek/eek-keyboard.c',
|
'../eek/eek-keyboard.c',
|
||||||
'../eek/eek-renderer.c',
|
'../eek/eek-renderer.c',
|
||||||
'../eek/eek-types.c',
|
'../eek/eek-types.c',
|
||||||
'../eek/eek-xml-layout.c',
|
|
||||||
'../eek/layersurface.c',
|
'../eek/layersurface.c',
|
||||||
dbus_src,
|
dbus_src,
|
||||||
'../eekboard/eekboard-context-service.c',
|
'../eekboard/eekboard-context-service.c',
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
#include "eek/eek-gtk-keyboard.h"
|
#include "eek/eek-gtk-keyboard.h"
|
||||||
#include "eek/layersurface.h"
|
#include "eek/layersurface.h"
|
||||||
#include "eekboard/eekboard-context-service.h"
|
#include "eekboard/eekboard-context-service.h"
|
||||||
|
#include "submission.h"
|
||||||
#include "wayland.h"
|
#include "wayland.h"
|
||||||
#include "server-context-service.h"
|
#include "server-context-service.h"
|
||||||
|
|
||||||
@ -41,10 +42,12 @@ struct _ServerContextService {
|
|||||||
GObject parent;
|
GObject parent;
|
||||||
|
|
||||||
EekboardContextService *state; // unowned
|
EekboardContextService *state; // unowned
|
||||||
|
/// Needed for instantiating the widget
|
||||||
|
struct submission *submission; // unowned
|
||||||
|
|
||||||
gboolean visible;
|
gboolean visible;
|
||||||
PhoshLayerSurface *window;
|
PhoshLayerSurface *window;
|
||||||
GtkWidget *widget;
|
GtkWidget *widget; // nullable
|
||||||
guint hiding;
|
guint hiding;
|
||||||
guint last_requested_height;
|
guint last_requested_height;
|
||||||
enum squeek_arrangement_kind last_type;
|
enum squeek_arrangement_kind last_type;
|
||||||
@ -224,7 +227,7 @@ make_widget (ServerContextService *context)
|
|||||||
|
|
||||||
LevelKeyboard *keyboard = eekboard_context_service_get_keyboard (context->state);
|
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_widget_set_has_tooltip (context->widget, TRUE);
|
||||||
gtk_container_add (GTK_CONTAINER(context->window), context->widget);
|
gtk_container_add (GTK_CONTAINER(context->window), context->widget);
|
||||||
@ -395,9 +398,10 @@ server_context_service_init (ServerContextService *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ServerContextService *
|
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);
|
ServerContextService *ui = g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL);
|
||||||
|
ui->submission = submission;
|
||||||
ui->state = state;
|
ui->state = state;
|
||||||
g_signal_connect (state,
|
g_signal_connect (state,
|
||||||
"notify::keyboard",
|
"notify::keyboard",
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
#define SERVER_CONTEXT_SERVICE_H 1
|
#define SERVER_CONTEXT_SERVICE_H 1
|
||||||
|
|
||||||
#include "src/layout.h"
|
#include "src/layout.h"
|
||||||
|
#include "src/submission.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
@ -35,7 +36,7 @@ typedef struct _ServerContextService ServerContextService;
|
|||||||
GType server_context_service_get_type
|
GType server_context_service_get_type
|
||||||
(void) G_GNUC_CONST;
|
(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 *);
|
enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *);
|
||||||
void server_context_service_show_keyboard (ServerContextService *context);
|
void server_context_service_show_keyboard (ServerContextService *context);
|
||||||
void server_context_service_hide_keyboard (ServerContextService *context);
|
void server_context_service_hide_keyboard (ServerContextService *context);
|
||||||
|
|||||||
@ -28,8 +28,8 @@
|
|||||||
#include "eek/eek.h"
|
#include "eek/eek.h"
|
||||||
#include "eekboard/eekboard-context-service.h"
|
#include "eekboard/eekboard-context-service.h"
|
||||||
#include "dbus.h"
|
#include "dbus.h"
|
||||||
#include "imservice.h"
|
|
||||||
#include "outputs.h"
|
#include "outputs.h"
|
||||||
|
#include "submission.h"
|
||||||
#include "server-context-service.h"
|
#include "server-context-service.h"
|
||||||
#include "wayland.h"
|
#include "wayland.h"
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ struct squeekboard {
|
|||||||
DBusHandler *dbus_handler;
|
DBusHandler *dbus_handler;
|
||||||
EekboardContextService *settings_context;
|
EekboardContextService *settings_context;
|
||||||
ServerContextService *ui_context;
|
ServerContextService *ui_context;
|
||||||
struct imservice *imservice;
|
struct submission *submission;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -195,6 +195,10 @@ main (int argc, char **argv)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!instance.wayland.input_method_manager) {
|
||||||
|
g_warning("Wayland input method interface not available");
|
||||||
|
}
|
||||||
|
|
||||||
instance.settings_context = eekboard_context_service_new();
|
instance.settings_context = eekboard_context_service_new();
|
||||||
|
|
||||||
// set up dbus
|
// set up dbus
|
||||||
@ -263,26 +267,23 @@ main (int argc, char **argv)
|
|||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct imservice *imservice = NULL;
|
instance.submission = get_submission(instance.wayland.input_method_manager,
|
||||||
if (instance.wayland.input_method_manager) {
|
instance.wayland.virtual_keyboard_manager,
|
||||||
imservice = get_imservice(instance.wayland.input_method_manager,
|
|
||||||
instance.wayland.seat,
|
instance.wayland.seat,
|
||||||
instance.settings_context);
|
instance.settings_context);
|
||||||
if (imservice) {
|
|
||||||
instance.imservice = imservice;
|
|
||||||
} else {
|
|
||||||
g_warning("Failed to register as an input method");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
if (!ui_context) {
|
||||||
g_error("Could not initialize GUI");
|
g_error("Could not initialize GUI");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
instance.ui_context = ui_context;
|
instance.ui_context = ui_context;
|
||||||
if (instance.imservice) {
|
if (instance.submission) {
|
||||||
imservice_set_ui(instance.imservice, instance.ui_context);
|
submission_set_ui(instance.submission, instance.ui_context);
|
||||||
}
|
}
|
||||||
if (instance.dbus_handler) {
|
if (instance.dbus_handler) {
|
||||||
dbus_handler_set_ui_context(instance.dbus_handler, instance.ui_context);
|
dbus_handler_set_ui_context(instance.dbus_handler, instance.ui_context);
|
||||||
|
|||||||
19
src/submission.h
Normal file
19
src/submission.h
Normal file
@ -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
|
||||||
@ -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
|
/// Gathers stuff defined in C or called by C
|
||||||
pub mod c {
|
pub mod c {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
use std::os::raw::c_void;
|
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)]
|
#[repr(transparent)]
|
||||||
#[derive(Clone, Copy)]
|
pub struct UIManager(*const c_void);
|
||||||
pub struct ZwpVirtualKeyboardV1(*const c_void);
|
|
||||||
|
/// EekboardContextService*
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct StateManager(*const c_void);
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" {
|
pub extern "C"
|
||||||
/// Checks if point falls within bounds,
|
fn submission_new(
|
||||||
/// which are relative to origin and rotated by angle (I think)
|
im: *mut InputMethod,
|
||||||
pub fn eek_virtual_keyboard_v1_key(
|
vk: ZwpVirtualKeyboardV1,
|
||||||
virtual_keyboard: ZwpVirtualKeyboardV1,
|
state_manager: *const StateManager
|
||||||
timestamp: u32,
|
) -> *mut Submission {
|
||||||
keycode: u32,
|
let imservice = if im.is_null() {
|
||||||
press: u32,
|
None
|
||||||
);
|
} else {
|
||||||
|
Some(IMService::new(im, state_manager))
|
||||||
|
};
|
||||||
|
// TODO: add vkeyboard too
|
||||||
|
Box::<Submission>::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)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Timestamp(pub u32);
|
pub struct Timestamp(pub u32);
|
||||||
|
|
||||||
/// Layout-independent backend. TODO: Have one instance per program or seat
|
pub struct Submission {
|
||||||
pub struct VirtualKeyboard(pub c::ZwpVirtualKeyboardV1);
|
// used by C callbacks internally, TODO: make use with virtual keyboard
|
||||||
|
#[allow(dead_code)]
|
||||||
impl VirtualKeyboard {
|
imservice: Option<Box<IMService>>,
|
||||||
// TODO: split out keyboard state management
|
pub virtual_keyboard: VirtualKeyboard,
|
||||||
pub fn switch(
|
|
||||||
&self,
|
|
||||||
keycodes: &Vec<KeyCode>,
|
|
||||||
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, _) => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
79
src/vkeyboard.rs
Normal file
79
src/vkeyboard.rs
Normal file
@ -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<KeyCode>,
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,5 @@
|
|||||||
|
#include "eek/eek-keyboard.h"
|
||||||
|
|
||||||
#include "wayland.h"
|
#include "wayland.h"
|
||||||
|
|
||||||
struct squeek_wayland *squeek_wayland = NULL;
|
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);
|
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,
|
int squeek_output_add_listener(struct wl_output *wl_output,
|
||||||
const struct wl_output_listener *listener, void *data) {
|
const struct wl_output_listener *listener, void *data) {
|
||||||
return wl_output_add_listener(wl_output, listener, data);
|
return wl_output_add_listener(wl_output, listener, data);
|
||||||
|
|||||||
Reference in New Issue
Block a user