Enable Wayland's virtual-keyboard protocol
This commit includes a little restructuring necessary for keeping wayland objects properly. It doesn't fix broken modifier functionality yet.
This commit is contained in:
@ -5,7 +5,7 @@ stages:
|
||||
|
||||
before_script:
|
||||
- apt-get -y update
|
||||
- apt-get -y install gnome-common gtk-doc-tools libglib2.0-dev-bin gobject-introspection libglib2.0-dev libpango1.0-dev libgtk-3-dev libcroco3-dev meson
|
||||
- apt-get -y install gnome-common gtk-doc-tools libglib2.0-dev-bin gobject-introspection libglib2.0-dev libpango1.0-dev libgtk-3-dev libcroco3-dev libxkbcommon-dev meson
|
||||
|
||||
build_meson:
|
||||
stage: build
|
||||
|
||||
@ -21,9 +21,6 @@ Features
|
||||
- Use Wayland virtual keyboard protocol
|
||||
- Use Wayland text input protocol
|
||||
- Use Wayland input method protocol
|
||||
- Become a Wayland layer shell
|
||||
- Remove eekboard-client
|
||||
- Use sm.puri.OSK0 DBus interface
|
||||
- Pick up DBus interface files from /usr/share
|
||||
|
||||
Building
|
||||
|
||||
@ -425,15 +425,6 @@ eek_gtk_keyboard_new (EekKeyboard *keyboard)
|
||||
return g_object_new (EEK_TYPE_GTK_KEYBOARD, "keyboard", keyboard, NULL);
|
||||
}
|
||||
|
||||
static EekColor *
|
||||
color_from_gdk_color (GdkColor *gdk_color)
|
||||
{
|
||||
return eek_color_new (gdk_color->red / (gdouble)0xFFFF,
|
||||
gdk_color->green / (gdouble)0xFFFF,
|
||||
gdk_color->blue / (gdouble)0xFFFF,
|
||||
1.0);
|
||||
}
|
||||
|
||||
static void
|
||||
magnify_bounds (GtkWidget *self,
|
||||
EekBounds *bounds,
|
||||
@ -585,7 +576,7 @@ on_key_cancelled (EekKey *key,
|
||||
if (!priv->renderer)
|
||||
return;
|
||||
|
||||
render_released_key (self, key);
|
||||
render_released_key (GTK_WIDGET(self), key);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@ -256,18 +256,15 @@ set_modifiers_with_key (EekKeyboard *self,
|
||||
|
||||
void eek_keyboard_press_key(EekKeyboard *keyboard, EekKey *key, guint32 timestamp) {
|
||||
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(keyboard);
|
||||
EekSymbol *symbol;
|
||||
EekModifierType modifier;
|
||||
|
||||
eek_key_set_pressed(key, TRUE);
|
||||
key = EEK_KEY(key);
|
||||
priv->pressed_keys = g_list_prepend (priv->pressed_keys, key);
|
||||
|
||||
symbol = eek_key_get_symbol_with_fallback (key, 0, 0);
|
||||
EekSymbol *symbol = eek_key_get_symbol_with_fallback (key, 0, 0);
|
||||
if (!symbol)
|
||||
return;
|
||||
|
||||
modifier = eek_symbol_get_modifier_mask (symbol);
|
||||
EekModifierType modifier = eek_symbol_get_modifier_mask (symbol);
|
||||
if (priv->modifier_behavior == EEK_MODIFIER_BEHAVIOR_NONE) {
|
||||
set_modifiers_with_key (keyboard, key, priv->modifiers | modifier);
|
||||
set_level_from_modifiers (keyboard);
|
||||
@ -277,11 +274,8 @@ void eek_keyboard_press_key(EekKeyboard *keyboard, EekKey *key, guint32 timestam
|
||||
|
||||
guint keycode = eek_key_get_keycode (key);
|
||||
guint modifiers = eek_keyboard_get_modifiers (keyboard);
|
||||
// Insert
|
||||
EekboardContext ec = {0};
|
||||
Client c = {&ec, 0, {0}};
|
||||
|
||||
emit_key_activated(&ec, keycode, symbol, modifiers, &c, TRUE, timestamp);
|
||||
emit_key_activated(keyboard->manager, keyboard, keycode, symbol, modifiers, TRUE, timestamp);
|
||||
}
|
||||
|
||||
void eek_keyboard_release_key( EekKeyboard *keyboard,
|
||||
@ -328,11 +322,8 @@ void eek_keyboard_release_key( EekKeyboard *keyboard,
|
||||
|
||||
guint keycode = eek_key_get_keycode (key);
|
||||
guint modifiers = eek_keyboard_get_modifiers (keyboard);
|
||||
// Insert
|
||||
EekboardContext ec = {0};
|
||||
Client c = {&ec, 0, {0}};
|
||||
|
||||
emit_key_activated(&ec, keycode, symbol, modifiers, &c, FALSE, timestamp);
|
||||
emit_key_activated(keyboard->manager, keyboard, keycode, symbol, modifiers, FALSE, timestamp);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#define EEK_KEYBOARD_H 1
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include "eek-container.h"
|
||||
#include "eek-types.h"
|
||||
#include "eek-layout.h"
|
||||
@ -56,6 +57,11 @@ struct _EekKeyboard
|
||||
EekContainer parent;
|
||||
|
||||
EekKeyboardPrivate *priv;
|
||||
struct xkb_keymap *keymap;
|
||||
int keymap_fd; // keymap formatted as XKB string
|
||||
size_t keymap_len; // length of the data inside keymap_fd
|
||||
|
||||
EekboardContextService *manager; // unowned reference
|
||||
};
|
||||
|
||||
/**
|
||||
@ -115,12 +121,13 @@ struct _EekModifierKey {
|
||||
};
|
||||
typedef struct _EekModifierKey EekModifierKey;
|
||||
|
||||
GType eek_keyboard_get_type
|
||||
(void) G_GNUC_CONST;
|
||||
|
||||
EekKeyboard *eek_keyboard_new (EekLayout *layout,
|
||||
EekKeyboard *eek_keyboard_new (EekboardContextService *manager,
|
||||
EekLayout *layout,
|
||||
gdouble initial_width,
|
||||
gdouble initial_height);
|
||||
GType eek_keyboard_get_type
|
||||
(void) G_GNUC_CONST;
|
||||
EekLayout *eek_keyboard_get_layout
|
||||
(EekKeyboard *keyboard);
|
||||
void eek_keyboard_get_size
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
|
||||
#include "eek-layout.h"
|
||||
#include "eek-keyboard.h"
|
||||
#include "eekboard/eekboard-context-service.h"
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE (EekLayout, eek_layout, G_TYPE_OBJECT);
|
||||
|
||||
@ -55,14 +56,16 @@ eek_layout_init (EekLayout *self)
|
||||
* Create a new #EekKeyboard based on @layout.
|
||||
*/
|
||||
EekKeyboard *
|
||||
eek_keyboard_new (EekLayout *layout,
|
||||
eek_keyboard_new (EekboardContextService *manager,
|
||||
EekLayout *layout,
|
||||
gdouble initial_width,
|
||||
gdouble initial_height)
|
||||
{
|
||||
g_assert (EEK_IS_LAYOUT(layout));
|
||||
g_assert (EEK_LAYOUT_GET_CLASS(layout)->create_keyboard);
|
||||
|
||||
return EEK_LAYOUT_GET_CLASS(layout)->create_keyboard (layout,
|
||||
return EEK_LAYOUT_GET_CLASS(layout)->create_keyboard (manager,
|
||||
layout,
|
||||
initial_width,
|
||||
initial_height);
|
||||
}
|
||||
|
||||
@ -56,7 +56,8 @@ struct _EekLayoutClass
|
||||
GObjectClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
EekKeyboard* (* create_keyboard) (EekLayout *self,
|
||||
EekKeyboard* (* create_keyboard) (EekboardContextService *manager,
|
||||
EekLayout *self,
|
||||
gdouble initial_width,
|
||||
gdouble initial_height);
|
||||
|
||||
|
||||
@ -150,6 +150,8 @@ typedef struct _EekBounds EekBounds;
|
||||
typedef struct _EekOutline EekOutline;
|
||||
typedef struct _EekColor EekColor;
|
||||
|
||||
typedef struct _EekboardContextService EekboardContextService;
|
||||
|
||||
/**
|
||||
* EekPoint:
|
||||
* @x: X coordinate of the point
|
||||
|
||||
@ -320,21 +320,24 @@ create_keyboard (EekXkbLayout *layout, EekKeyboard *keyboard)
|
||||
}
|
||||
|
||||
static EekKeyboard *
|
||||
eek_xkb_layout_real_create_keyboard (EekLayout *self,
|
||||
eek_xkb_layout_real_create_keyboard (EekboardContextService *manager,
|
||||
EekLayout *self,
|
||||
gdouble initial_width,
|
||||
gdouble initial_height)
|
||||
{
|
||||
EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (self);
|
||||
EekBounds bounds;
|
||||
EekKeyboard *keyboard;
|
||||
EekKeyboard *keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", self, NULL);
|
||||
keyboard->manager = manager;
|
||||
|
||||
keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", self, NULL);
|
||||
bounds.x = bounds.y = 0.0;
|
||||
bounds.width = initial_width;
|
||||
bounds.height = initial_height;
|
||||
EekBounds bounds = {
|
||||
.x = 0.0,
|
||||
.y = 0.0,
|
||||
.width = initial_width,
|
||||
.height = initial_height
|
||||
};
|
||||
eek_element_set_bounds (EEK_ELEMENT(keyboard), &bounds);
|
||||
|
||||
/* resolve modifiers dynamically assigned at run time */
|
||||
EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (self);
|
||||
eek_keyboard_set_num_lock_mask (keyboard,
|
||||
XkbKeysymToModifiers (priv->display,
|
||||
XK_Num_Lock));
|
||||
|
||||
@ -896,27 +896,25 @@ static const GMarkupParser prerequisites_parser = {
|
||||
};
|
||||
|
||||
static EekKeyboard *
|
||||
eek_xml_layout_real_create_keyboard (EekLayout *self,
|
||||
eek_xml_layout_real_create_keyboard (EekboardContextService *manager,
|
||||
EekLayout *self,
|
||||
gdouble initial_width,
|
||||
gdouble initial_height)
|
||||
{
|
||||
EekXmlLayout *layout = EEK_XML_LAYOUT (self);
|
||||
EekKeyboard *keyboard;
|
||||
gchar *filename, *path;
|
||||
GList *loaded;
|
||||
GError *error;
|
||||
gboolean retval;
|
||||
|
||||
/* Create an empty keyboard to which geometry and symbols
|
||||
information are applied. */
|
||||
keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", layout, NULL);
|
||||
EekKeyboard *keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", layout, NULL);
|
||||
keyboard->manager = manager;
|
||||
|
||||
/* Read geometry information. */
|
||||
filename = g_strdup_printf ("%s.xml", layout->priv->desc->geometry);
|
||||
path = g_build_filename (layout->priv->keyboards_dir, "geometry", filename, NULL);
|
||||
gchar *filename = g_strdup_printf ("%s.xml", layout->priv->desc->geometry);
|
||||
gchar *path = g_build_filename (layout->priv->keyboards_dir, "geometry", filename, NULL);
|
||||
g_free (filename);
|
||||
|
||||
error = NULL;
|
||||
GError *error = NULL;
|
||||
retval = parse_geometry (path, keyboard, &error);
|
||||
g_free (path);
|
||||
if (!retval) {
|
||||
@ -929,7 +927,7 @@ eek_xml_layout_real_create_keyboard (EekLayout *self,
|
||||
}
|
||||
|
||||
/* Read symbols information. */
|
||||
loaded = NULL;
|
||||
GList *loaded = NULL;
|
||||
retval = parse_symbols_with_prerequisites (layout->priv->keyboards_dir,
|
||||
layout->priv->desc->symbols,
|
||||
keyboard,
|
||||
|
||||
@ -29,8 +29,17 @@
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "eekboard/key-emitter.h"
|
||||
#include "eekboard/eekboard-context-service.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/random.h> // TODO: this is Linux-specific
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include "eekboard/key-emitter.h"
|
||||
#include "wayland.h"
|
||||
//#include "eekboard/eekboard-xklutil.h"
|
||||
//#include "eek/eek-xkl.h"
|
||||
|
||||
@ -116,8 +125,9 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self,
|
||||
g_warning ("can't create keyboard %s: %s",
|
||||
keyboard_type, error->message);
|
||||
g_error_free (error);
|
||||
keyboard_type = "us";
|
||||
error = NULL;
|
||||
layout = eek_xml_layout_new ("us", &error);
|
||||
layout = eek_xml_layout_new (keyboard_type, &error);
|
||||
if (layout == NULL) {
|
||||
g_error ("failed to create fallback layout: %s", error->message);
|
||||
g_error_free (error);
|
||||
@ -125,9 +135,54 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self,
|
||||
}
|
||||
}
|
||||
}
|
||||
keyboard = eek_keyboard_new (layout, CSW, CSH);
|
||||
keyboard = eek_keyboard_new (self, layout, CSW, CSH);
|
||||
g_object_unref (layout);
|
||||
|
||||
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
if (!context) {
|
||||
g_error("No context created");
|
||||
}
|
||||
|
||||
struct xkb_rule_names rules = { 0 };
|
||||
rules.layout = strdup(keyboard_type);
|
||||
struct xkb_keymap *keymap = xkb_keymap_new_from_names(context, &rules,
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
if (!keymap) {
|
||||
g_error("Bad keymap");
|
||||
}
|
||||
keyboard->keymap = keymap;
|
||||
char *keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
|
||||
int f = open("km", O_CREAT|O_WRONLY);
|
||||
write(f, keymap_str, strlen(keymap_str) + 1);
|
||||
if (!keymap_str) {
|
||||
g_error("Keymap was not serialized");
|
||||
}
|
||||
keyboard->keymap_len = strlen(keymap_str) + 1;
|
||||
char *path = strdup("/eek_keymap-XXXXXX");
|
||||
char *r = &path[strlen(path) - 6];
|
||||
getrandom(r, 6, GRND_NONBLOCK);
|
||||
for (uint 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");
|
||||
}
|
||||
strcpy(ptr, keymap_str);
|
||||
munmap(ptr, keyboard->keymap_len);
|
||||
free(keymap_str);
|
||||
|
||||
return keyboard;
|
||||
}
|
||||
|
||||
@ -233,14 +288,10 @@ settings_get_layout(GSettings *settings, char **type, char **layout)
|
||||
g_variant_iter_free(iter);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
settings_update_layout(EekboardContextService *context) {
|
||||
EekboardContextServiceClass *klass = EEKBOARD_CONTEXT_SERVICE_GET_CLASS(context);
|
||||
static guint keyboard_id = 0;
|
||||
g_autofree gchar *keyboard_type = NULL;
|
||||
g_autofree gchar *keyboard_layout = NULL;
|
||||
|
||||
settings_get_layout(context->priv->settings, &keyboard_type, &keyboard_layout);
|
||||
|
||||
if (!keyboard_type) {
|
||||
@ -250,10 +301,13 @@ settings_update_layout(EekboardContextService *context) {
|
||||
keyboard_layout = g_strdup("undefined");
|
||||
}
|
||||
|
||||
// generic part follows
|
||||
static guint keyboard_id = 0;
|
||||
EekKeyboard *keyboard = g_hash_table_lookup(context->priv->keyboard_hash,
|
||||
GUINT_TO_POINTER(keyboard_id));
|
||||
// create a keyboard
|
||||
if (!keyboard) {
|
||||
EekboardContextServiceClass *klass = EEKBOARD_CONTEXT_SERVICE_GET_CLASS(context);
|
||||
keyboard = klass->create_keyboard (context, keyboard_layout);
|
||||
eek_keyboard_set_modifier_behavior (keyboard,
|
||||
EEK_MODIFIER_BEHAVIOR_LATCH);
|
||||
@ -270,7 +324,6 @@ settings_update_layout(EekboardContextService *context) {
|
||||
context->priv->keyboard = keyboard;
|
||||
// TODO: this used to save the group, why?
|
||||
//group = eek_element_get_group (EEK_ELEMENT(context->priv->keyboard));
|
||||
|
||||
g_object_notify (G_OBJECT(context), "keyboard");
|
||||
}
|
||||
|
||||
@ -278,16 +331,24 @@ static gboolean
|
||||
settings_handle_layout_changed(GSettings *s,
|
||||
gpointer keys, gint n_keys,
|
||||
gpointer user_data) {
|
||||
(void)s;
|
||||
(void)keys;
|
||||
(void)n_keys;
|
||||
EekboardContextService *context = user_data;
|
||||
settings_update_layout(context);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
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");
|
||||
}
|
||||
settings_update_layout(context);
|
||||
}
|
||||
|
||||
@ -563,3 +624,11 @@ eekboard_context_service_get_fullscreen (EekboardContextService *context)
|
||||
{
|
||||
return context->priv->fullscreen;
|
||||
}
|
||||
|
||||
void eekboard_context_service_set_keymap(EekboardContextService *context,
|
||||
const EekKeyboard *keyboard)
|
||||
{
|
||||
zwp_virtual_keyboard_v1_keymap(context->virtual_keyboard,
|
||||
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
|
||||
keyboard->keymap_fd, keyboard->keymap_len);
|
||||
}
|
||||
|
||||
@ -36,14 +36,15 @@ G_BEGIN_DECLS
|
||||
#define EEKBOARD_IS_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_CONTEXT_SERVICE))
|
||||
#define EEKBOARD_CONTEXT_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextServiceClass))
|
||||
|
||||
typedef struct _EekboardContextService EekboardContextService;
|
||||
|
||||
typedef struct _EekboardContextServiceClass EekboardContextServiceClass;
|
||||
typedef struct _EekboardContextServicePrivate EekboardContextServicePrivate;
|
||||
|
||||
/**
|
||||
* EekboardContextService:
|
||||
*
|
||||
* TODO: Restrict to managing keyboard layouts, and maybe button rerpeats.
|
||||
* TODO: Restrict to managing keyboard layouts, and maybe button repeats,
|
||||
* and the virtual keyboard protocol.
|
||||
*
|
||||
* The #EekboardContextService structure contains only private data
|
||||
* and should only be accessed using the provided API.
|
||||
@ -52,6 +53,8 @@ struct _EekboardContextService {
|
||||
GObject parent;
|
||||
|
||||
EekboardContextServicePrivate *priv;
|
||||
|
||||
struct zwp_virtual_keyboard_v1 *virtual_keyboard;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -96,5 +99,8 @@ EekKeyboard *eekboard_context_service_get_keyboard
|
||||
gboolean eekboard_context_service_get_fullscreen
|
||||
(EekboardContextService *context);
|
||||
|
||||
void eekboard_context_service_set_keymap(EekboardContextService *context,
|
||||
const EekKeyboard *keyboard);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* EEKBOARD_CONTEXT_SERVICE_H */
|
||||
|
||||
@ -41,6 +41,8 @@ typedef struct _EekboardServicePrivate EekboardServicePrivate;
|
||||
/**
|
||||
* EekboardService:
|
||||
*
|
||||
* Manages DBus interaction.
|
||||
*
|
||||
* The #EekboardService structure contains only private data and
|
||||
* should only be accessed using the provided API.
|
||||
*/
|
||||
|
||||
@ -20,9 +20,24 @@
|
||||
/* This file is responsible for managing keycode data and emitting keycodes. */
|
||||
|
||||
#include "eekboard/key-emitter.h"
|
||||
#include "eekboard/keymap.h"
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#include "eekboard/eekboard-context-service.h"
|
||||
|
||||
// TODO: decide whether it's this struct that carries the keyboard around in key-emitter or if the whole manager should be dragged around
|
||||
// if this is the carrier, then it should be made part of the manager
|
||||
// hint: check which fields need to be persisted between keypresses; which between keyboards
|
||||
typedef struct {
|
||||
struct zwp_virtual_keyboard_v1 *virtual_keyboard; // unowned copy
|
||||
struct xkb_keymap *keymap; // unowned copy
|
||||
XkbDescRec *xkb;
|
||||
guint modifier_keycodes[8];
|
||||
gint group;
|
||||
} SeatEmitter;
|
||||
|
||||
|
||||
/* The following functions for keyboard mapping change are direct
|
||||
translation of the code in Caribou (in libcaribou/xadapter.vala):
|
||||
|
||||
@ -33,7 +48,7 @@
|
||||
|
||||
/* Find an unused keycode where a keysym can be assigned. Restricted to Level 1 */
|
||||
static guint
|
||||
get_replaced_keycode (Client *client)
|
||||
get_replaced_keycode (SeatEmitter *client)
|
||||
{
|
||||
guint keycode;
|
||||
return 0; // FIXME: no xkb allocated yet
|
||||
@ -58,7 +73,7 @@ return 0; // FIXME: no xkb allocated yet
|
||||
non-zero keycode), it simply changes the current map with the
|
||||
specified KEYCODE and KEYSYM. */
|
||||
static gboolean
|
||||
replace_keycode (Client *client,
|
||||
replace_keycode (SeatEmitter *emitter,
|
||||
guint keycode,
|
||||
guint *keysym)
|
||||
{
|
||||
@ -68,8 +83,8 @@ replace_keycode (Client *client,
|
||||
int keysyms_per_keycode;
|
||||
KeySym *syms;
|
||||
return TRUE; // FIXME: no xkb allocated at the moment, pretending all is fine
|
||||
g_return_val_if_fail (client->xkb->min_key_code <= keycode &&
|
||||
keycode <= client->xkb->max_key_code,
|
||||
g_return_val_if_fail (emitter->xkb->min_key_code <= keycode &&
|
||||
keycode <= emitter->xkb->max_key_code,
|
||||
FALSE);
|
||||
g_return_val_if_fail (keysym != NULL, FALSE);
|
||||
/*
|
||||
@ -87,20 +102,19 @@ return TRUE; // FIXME: no xkb allocated at the moment, pretending all is fine
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_keycode_from_gdk_keymap (Client *client,
|
||||
get_keycode_from_gdk_keymap (SeatEmitter *emitter,
|
||||
guint keysym,
|
||||
guint *keycode,
|
||||
guint *modifiers)
|
||||
{
|
||||
GdkKeymap *keymap = gdk_keymap_get_default ();
|
||||
GdkKeymapKey *keys, *best_match = NULL;
|
||||
gint n_keys, i;
|
||||
guint n_keys, i;
|
||||
|
||||
if (!gdk_keymap_get_entries_for_keyval (keymap, keysym, &keys, &n_keys))
|
||||
if (!squeek_keymap_get_entries_for_keyval (emitter->keymap, keysym, &keys, &n_keys))
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < n_keys; i++)
|
||||
if (keys[i].group == client->context->group)
|
||||
if (keys[i].group == emitter->group)
|
||||
best_match = &keys[i];
|
||||
|
||||
if (!best_match) {
|
||||
@ -115,69 +129,63 @@ get_keycode_from_gdk_keymap (Client *client,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int WaylandFakeKeyEvent(
|
||||
Display* dpy,
|
||||
int send_virtual_keyboard_key(
|
||||
struct zwp_virtual_keyboard_v1 *keyboard,
|
||||
unsigned int keycode,
|
||||
Bool is_press,
|
||||
unsigned is_press,
|
||||
uint32_t timestamp
|
||||
) {
|
||||
printf("%d: Sending fake event %d press %d\n", timestamp, keycode, is_press);
|
||||
zwp_virtual_keyboard_v1_key(keyboard, timestamp, keycode, (unsigned)is_press);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
send_fake_modifier_key_event (Client *client,
|
||||
send_fake_modifier_key_event (SeatEmitter *emitter,
|
||||
EekModifierType modifiers,
|
||||
gboolean is_pressed,
|
||||
uint32_t timestamp)
|
||||
{
|
||||
GdkDisplay *display = gdk_display_get_default ();
|
||||
Display *xdisplay = NULL; //GDK_DISPLAY_XDISPLAY (display);
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(client->modifier_keycodes); i++) {
|
||||
for (i = 0; i < G_N_ELEMENTS(emitter->modifier_keycodes); i++) {
|
||||
if (modifiers & (1 << i)) {
|
||||
guint keycode = client->modifier_keycodes[i];
|
||||
guint keycode = emitter->modifier_keycodes[i];
|
||||
printf("Trying to send a modifier %ld press %d\n", i, is_pressed);
|
||||
g_return_if_fail (keycode > 0);
|
||||
|
||||
WaylandFakeKeyEvent (xdisplay,
|
||||
keycode,
|
||||
is_pressed,
|
||||
timestamp);
|
||||
send_virtual_keyboard_key (emitter->virtual_keyboard,
|
||||
keycode,
|
||||
is_pressed,
|
||||
timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
send_fake_key_event (Client *client,
|
||||
send_fake_key_event (SeatEmitter *emitter,
|
||||
guint xkeysym,
|
||||
guint keyboard_modifiers,
|
||||
gboolean pressed,
|
||||
uint32_t timestamp)
|
||||
{
|
||||
GdkDisplay *display = gdk_display_get_default ();
|
||||
Display *xdisplay = NULL; // GDK_DISPLAY_XDISPLAY (display);
|
||||
EekModifierType modifiers;
|
||||
guint keycode;
|
||||
guint old_keysym = xkeysym;
|
||||
|
||||
g_return_if_fail (xkeysym > 0);
|
||||
|
||||
modifiers = 0;
|
||||
if (!get_keycode_from_gdk_keymap (client, xkeysym, &keycode, &modifiers)) {
|
||||
keycode = get_replaced_keycode (client);
|
||||
guint keycode;
|
||||
if (!get_keycode_from_gdk_keymap (emitter, xkeysym, &keycode, &modifiers)) {
|
||||
keycode = get_replaced_keycode (emitter);
|
||||
if (keycode == 0) {
|
||||
g_warning ("no available keycode to replace");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!replace_keycode (client, keycode, &old_keysym)) {
|
||||
if (!replace_keycode (emitter, keycode, &old_keysym)) {
|
||||
g_warning ("failed to lookup X keysym %X", xkeysym);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear level shift modifiers */
|
||||
keyboard_modifiers &= (unsigned)~EEK_SHIFT_MASK;
|
||||
keyboard_modifiers &= (unsigned)~EEK_LOCK_MASK;
|
||||
@ -190,16 +198,18 @@ send_fake_key_event (Client *client,
|
||||
|
||||
modifiers |= keyboard_modifiers;
|
||||
|
||||
send_fake_modifier_key_event (client, modifiers, TRUE, timestamp);
|
||||
WaylandFakeKeyEvent (xdisplay, keycode, pressed, timestamp);
|
||||
send_fake_modifier_key_event (client, modifiers, FALSE, timestamp);
|
||||
send_fake_modifier_key_event (emitter, modifiers, TRUE, timestamp);
|
||||
|
||||
// There's something magical about subtracting/adding 8 to keycodes for some reason
|
||||
send_virtual_keyboard_key (emitter->virtual_keyboard, keycode - 8, (unsigned)pressed, timestamp);
|
||||
send_fake_modifier_key_event (emitter, modifiers, FALSE, timestamp);
|
||||
|
||||
if (old_keysym != xkeysym)
|
||||
replace_keycode (client, keycode, &old_keysym);
|
||||
replace_keycode (emitter, keycode, &old_keysym);
|
||||
}
|
||||
|
||||
static void
|
||||
send_fake_key_events (Client *client,
|
||||
send_fake_key_events (SeatEmitter *emitter,
|
||||
EekSymbol *symbol,
|
||||
guint keyboard_modifiers,
|
||||
gboolean pressed,
|
||||
@ -239,16 +249,16 @@ send_fake_key_events (Client *client,
|
||||
|
||||
if (EEK_IS_KEYSYM(symbol)) {
|
||||
guint xkeysym = eek_keysym_get_xkeysym (EEK_KEYSYM(symbol));
|
||||
send_fake_key_event (client, xkeysym, keyboard_modifiers, pressed, timestamp);
|
||||
send_fake_key_event (emitter, xkeysym, keyboard_modifiers, pressed, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
emit_key_activated (EekboardContext *context,
|
||||
emit_key_activated (EekboardContextService *manager,
|
||||
EekKeyboard *keyboard,
|
||||
guint keycode,
|
||||
EekSymbol *symbol,
|
||||
guint modifiers,
|
||||
Client *client,
|
||||
gboolean pressed,
|
||||
uint32_t timestamp)
|
||||
{
|
||||
@ -279,12 +289,15 @@ emit_key_activated (EekboardContext *context,
|
||||
return;
|
||||
}
|
||||
*/
|
||||
send_fake_key_events (client, symbol, modifiers, pressed, timestamp);
|
||||
SeatEmitter emitter = {0};
|
||||
emitter.virtual_keyboard = manager->virtual_keyboard;
|
||||
emitter.keymap = keyboard->keymap;
|
||||
send_fake_key_events (&emitter, symbol, modifiers, pressed, timestamp);
|
||||
}
|
||||
|
||||
/* Finds the first key code for each modifier and saves it in modifier_keycodes */
|
||||
static void
|
||||
update_modifier_keycodes (Client *client)
|
||||
update_modifier_keycodes (SeatEmitter *client)
|
||||
{
|
||||
GdkDisplay *display = gdk_display_get_default ();
|
||||
Display *xdisplay = NULL; // GDK_DISPLAY_XDISPLAY (display);
|
||||
@ -307,7 +320,7 @@ update_modifier_keycodes (Client *client)
|
||||
}
|
||||
|
||||
gboolean
|
||||
client_enable_xtest (Client *client)
|
||||
client_enable_xtest (SeatEmitter *client)
|
||||
{
|
||||
//GdkDisplay *display = gdk_display_get_default ();
|
||||
//Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
|
||||
@ -340,7 +353,7 @@ client_enable_xtest (Client *client)
|
||||
}
|
||||
|
||||
void
|
||||
client_disable_xtest (Client *client)
|
||||
client_disable_xtest (SeatEmitter *client)
|
||||
{
|
||||
//if (client->xkb) {
|
||||
// XkbFreeKeyboard (client->xkb, 0, TRUE); /* free_all = TRUE */
|
||||
|
||||
@ -7,26 +7,12 @@
|
||||
|
||||
#include "eek/eek.h"
|
||||
|
||||
typedef struct {
|
||||
gint group;
|
||||
} EekboardContext;
|
||||
|
||||
typedef struct {
|
||||
EekboardContext *context;
|
||||
XkbDescRec *xkb;
|
||||
guint modifier_keycodes[8];
|
||||
} Client;
|
||||
#include "virtual-keyboard-unstable-v1-client-protocol.h"
|
||||
|
||||
void
|
||||
emit_key_activated (EekboardContext *context,
|
||||
emit_key_activated (EekboardContextService *manager, EekKeyboard *keyboard,
|
||||
guint keycode,
|
||||
EekSymbol *symbol,
|
||||
guint modifiers,
|
||||
Client *client, gboolean pressed, uint32_t timestamp);
|
||||
|
||||
gboolean
|
||||
client_enable_xtest (Client *client);
|
||||
|
||||
void
|
||||
client_disable_xtest (Client *client);
|
||||
gboolean pressed, uint32_t timestamp);
|
||||
#endif // KEYEMITTER_H
|
||||
|
||||
66
eekboard/keymap.c
Normal file
66
eekboard/keymap.c
Normal file
@ -0,0 +1,66 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
* Copyright (C) 2000 Red Hat, Inc.
|
||||
* Copyright (C) 2019 Purism, SPC
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* Modified for squeekboard based on GTK
|
||||
*/
|
||||
|
||||
#include "keymap.h"
|
||||
|
||||
gboolean
|
||||
squeek_keymap_get_entries_for_keyval (struct xkb_keymap *xkb_keymap,
|
||||
guint keyval,
|
||||
GdkKeymapKey **keys,
|
||||
guint *n_keys)
|
||||
{
|
||||
GArray *retval;
|
||||
guint keycode;
|
||||
xkb_keycode_t min_keycode, max_keycode;
|
||||
retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
|
||||
min_keycode = xkb_keymap_min_keycode (xkb_keymap);
|
||||
max_keycode = xkb_keymap_max_keycode (xkb_keymap);
|
||||
for (keycode = min_keycode; keycode < max_keycode; keycode++)
|
||||
{
|
||||
xkb_layout_index_t num_layouts, layout;
|
||||
num_layouts = xkb_keymap_num_layouts_for_key (xkb_keymap, keycode);
|
||||
for (layout = 0; layout < num_layouts; layout++)
|
||||
{
|
||||
xkb_layout_index_t num_levels, level;
|
||||
num_levels = xkb_keymap_num_levels_for_key (xkb_keymap, keycode, layout);
|
||||
for (level = 0; level < num_levels; level++)
|
||||
{
|
||||
const xkb_keysym_t *syms;
|
||||
gint num_syms, sym;
|
||||
num_syms = xkb_keymap_key_get_syms_by_level (xkb_keymap, keycode, layout, level, &syms);
|
||||
for (sym = 0; sym < num_syms; sym++)
|
||||
{
|
||||
if (syms[sym] == keyval)
|
||||
{
|
||||
GdkKeymapKey key;
|
||||
key.keycode = keycode;
|
||||
key.group = (gint)layout;
|
||||
key.level = (gint)level;
|
||||
g_array_append_val (retval, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*n_keys = retval->len;
|
||||
*keys = (GdkKeymapKey*) g_array_free (retval, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
8
eekboard/keymap.h
Normal file
8
eekboard/keymap.h
Normal file
@ -0,0 +1,8 @@
|
||||
#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);
|
||||
@ -12,6 +12,7 @@ gen_scanner_client_code = generator(wl_scanner,
|
||||
wl_protos = [
|
||||
wl_protocol_dir + '/stable/xdg-shell/xdg-shell.xml',
|
||||
'wlr-layer-shell-unstable-v1.xml',
|
||||
'virtual-keyboard-unstable-v1.xml',
|
||||
]
|
||||
wl_proto_sources = []
|
||||
foreach proto: wl_protos
|
||||
|
||||
113
protocols/virtual-keyboard-unstable-v1.xml
Normal file
113
protocols/virtual-keyboard-unstable-v1.xml
Normal file
@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="virtual_keyboard_unstable_v1">
|
||||
<copyright>
|
||||
Copyright © 2008-2011 Kristian Høgsberg
|
||||
Copyright © 2010-2013 Intel Corporation
|
||||
Copyright © 2012-2013 Collabora, Ltd.
|
||||
Copyright © 2018 Purism SPC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next
|
||||
paragraph) shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<interface name="zwp_virtual_keyboard_v1" version="1">
|
||||
<description summary="virtual keyboard">
|
||||
The virtual keyboard provides an application with requests which emulate
|
||||
the behaviour of a physical keyboard.
|
||||
|
||||
This interface can be used by clients on its own to provide raw input
|
||||
events, or it can accompany the input method protocol.
|
||||
</description>
|
||||
|
||||
<request name="keymap">
|
||||
<description summary="keyboard mapping">
|
||||
Provide a file descriptor to the compositor which can be
|
||||
memory-mapped to provide a keyboard mapping description.
|
||||
|
||||
Format carries a value from the keymap_format enumeration.
|
||||
</description>
|
||||
<arg name="format" type="uint" summary="keymap format"/>
|
||||
<arg name="fd" type="fd" summary="keymap file descriptor"/>
|
||||
<arg name="size" type="uint" summary="keymap size, in bytes"/>
|
||||
</request>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="no_keymap" value="0" summary="No keymap was set"/>
|
||||
</enum>
|
||||
|
||||
<request name="key">
|
||||
<description summary="key event">
|
||||
A key was pressed or released.
|
||||
The time argument is a timestamp with millisecond granularity, with an
|
||||
undefined base. All requests regarding a single object must share the
|
||||
same clock.
|
||||
|
||||
Keymap must be set before issuing this request.
|
||||
|
||||
State carries a value from the key_state enumeration.
|
||||
</description>
|
||||
<arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
|
||||
<arg name="key" type="uint" summary="key that produced the event"/>
|
||||
<arg name="state" type="uint" summary="physical state of the key"/>
|
||||
</request>
|
||||
|
||||
<request name="modifiers">
|
||||
<description summary="modifier and group state">
|
||||
Notifies the compositor that the modifier and/or group state has
|
||||
changed, and it should update state.
|
||||
|
||||
The client should use wl_keyboard.modifiers event to synchronize its
|
||||
internal state with seat state.
|
||||
|
||||
Keymap must be set before issuing this request.
|
||||
</description>
|
||||
<arg name="mods_depressed" type="uint" summary="depressed modifiers"/>
|
||||
<arg name="mods_latched" type="uint" summary="latched modifiers"/>
|
||||
<arg name="mods_locked" type="uint" summary="locked modifiers"/>
|
||||
<arg name="group" type="uint" summary="keyboard layout"/>
|
||||
</request>
|
||||
|
||||
<request name="destroy" type="destructor" since="1">
|
||||
<description summary="destroy the virtual keyboard keyboard object"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zwp_virtual_keyboard_manager_v1" version="1">
|
||||
<description summary="virtual keyboard manager">
|
||||
A virtual keyboard manager allows an application to provide keyboard
|
||||
input events as if they came from a physical keyboard.
|
||||
</description>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="unauthorized" value="0" summary="client not authorized to use the interface"/>
|
||||
</enum>
|
||||
|
||||
<request name="create_virtual_keyboard">
|
||||
<description summary="Create a new virtual keyboard">
|
||||
Creates a new virtual keyboard associated to a seat.
|
||||
|
||||
If the compositor enables a keyboard to perform arbitrary actions, it
|
||||
should present an error when an untrusted client requests a new
|
||||
keyboard.
|
||||
</description>
|
||||
<arg name="seat" type="object" interface="wl_seat"/>
|
||||
<arg name="id" type="new_id" interface="zwp_virtual_keyboard_v1"/>
|
||||
</request>
|
||||
</interface>
|
||||
</protocol>
|
||||
@ -88,7 +88,7 @@ enum FocusListenerType {
|
||||
};
|
||||
|
||||
static gboolean
|
||||
set_keyboards (Client *client,
|
||||
set_keyboards (SeatEmitter *client,
|
||||
const gchar * const *keyboards)
|
||||
{
|
||||
if (g_strv_length ((gchar **)keyboards) == 0) {
|
||||
@ -110,7 +110,7 @@ set_keyboards (Client *client,
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
Client *client = NULL;
|
||||
SeatEmitter *client = NULL;
|
||||
EekboardClient *eekboard;
|
||||
EekboardContext *context;
|
||||
GBusType bus_type;
|
||||
|
||||
72
src/client.c
72
src/client.c
@ -101,7 +101,7 @@ struct _ClientClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (Client, client, G_TYPE_OBJECT);
|
||||
G_DEFINE_TYPE (SeatEmitter, client, G_TYPE_OBJECT);
|
||||
|
||||
#if ENABLE_FOCUS_LISTENER
|
||||
#define IS_KEYBOARD_VISIBLE(client) (!client->follows_focus)
|
||||
@ -128,10 +128,10 @@ static void focus_listener_cb (const AtspiEvent *event,
|
||||
static gboolean keystroke_listener_cb (const AtspiDeviceEvent *stroke,
|
||||
void *user_data);
|
||||
#endif /* HAVE_ATSPI */
|
||||
static gboolean set_keyboards (Client *client,
|
||||
static gboolean set_keyboards (SeatEmitter *client,
|
||||
const gchar * const *keyboard);
|
||||
static gboolean set_keyboards_from_xkl
|
||||
(Client *client);
|
||||
(SeatEmitter *client);
|
||||
#ifdef HAVE_XTEST
|
||||
static void update_modifier_keycodes
|
||||
(Client *client);
|
||||
@ -143,7 +143,7 @@ client_set_property (GObject *object,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
Client *client = CLIENT(object);
|
||||
SeatEmitter *client = CLIENT(object);
|
||||
GDBusConnection *connection;
|
||||
gchar **keyboards;
|
||||
|
||||
@ -188,7 +188,7 @@ client_get_property (GObject *object,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
Client *client = CLIENT(object);
|
||||
SeatEmitter *client = CLIENT(object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_EEKBOARD:
|
||||
@ -206,7 +206,7 @@ client_get_property (GObject *object,
|
||||
static void
|
||||
client_dispose (GObject *object)
|
||||
{
|
||||
Client *client = CLIENT(object);
|
||||
SeatEmitter *client = CLIENT(object);
|
||||
|
||||
client_disable_xkl (client);
|
||||
|
||||
@ -246,7 +246,7 @@ client_dispose (GObject *object)
|
||||
static void
|
||||
client_finalize (GObject *object)
|
||||
{
|
||||
Client *client = CLIENT(object);
|
||||
SeatEmitter *client = CLIENT(object);
|
||||
|
||||
g_slist_free (client->keyboards);
|
||||
G_OBJECT_CLASS (client_parent_class)->finalize (object);
|
||||
@ -301,13 +301,13 @@ client_class_init (ClientClass *klass)
|
||||
}
|
||||
|
||||
static void
|
||||
client_init (Client *client)
|
||||
client_init (SeatEmitter *client)
|
||||
{
|
||||
client->settings = g_settings_new ("org.fedorahosted.eekboard");
|
||||
}
|
||||
|
||||
gboolean
|
||||
client_set_keyboards (Client *client,
|
||||
client_set_keyboards (SeatEmitter *client,
|
||||
const gchar * const *keyboards)
|
||||
{
|
||||
gboolean retval;
|
||||
@ -318,7 +318,7 @@ client_set_keyboards (Client *client,
|
||||
}
|
||||
|
||||
gboolean
|
||||
client_enable_xkl (Client *client)
|
||||
client_enable_xkl (SeatEmitter *client)
|
||||
{
|
||||
GdkDisplay *display = gdk_display_get_default ();
|
||||
gboolean retval;
|
||||
@ -361,7 +361,7 @@ client_enable_xkl (Client *client)
|
||||
}
|
||||
|
||||
void
|
||||
client_disable_xkl (Client *client)
|
||||
client_disable_xkl (SeatEmitter *client)
|
||||
{
|
||||
if (client->xkl_engine) {
|
||||
xkl_engine_stop_listen (client->xkl_engine, XKLL_TRACK_KEYBOARD_STATE);
|
||||
@ -618,7 +618,7 @@ add_match_rule (GDBusConnection *connection,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_hide_keyboard_timeout (Client *client)
|
||||
on_hide_keyboard_timeout (SeatEmitter *client)
|
||||
{
|
||||
eekboard_client_hide_keyboard (client->eekboard, NULL);
|
||||
client->hide_keyboard_timeout_id = 0;
|
||||
@ -631,7 +631,7 @@ focus_message_filter (GDBusConnection *connection,
|
||||
gboolean incoming,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
SeatEmitter *client = user_data;
|
||||
|
||||
if (incoming &&
|
||||
g_strcmp0 (g_dbus_message_get_interface (message),
|
||||
@ -661,7 +661,7 @@ focus_message_filter (GDBusConnection *connection,
|
||||
static void
|
||||
_ibus_connect_focus_handlers (GDBusConnection *connection, gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
SeatEmitter *client = user_data;
|
||||
|
||||
add_match_rule (connection,
|
||||
"type='method_call',"
|
||||
@ -679,7 +679,7 @@ _ibus_connect_focus_handlers (GDBusConnection *connection, gpointer user_data)
|
||||
}
|
||||
|
||||
gboolean
|
||||
client_enable_ibus_focus (Client *client)
|
||||
client_enable_ibus_focus (SeatEmitter *client)
|
||||
{
|
||||
if (client->ibus_connection == NULL) {
|
||||
const gchar *ibus_address;
|
||||
@ -711,7 +711,7 @@ client_enable_ibus_focus (Client *client)
|
||||
}
|
||||
|
||||
void
|
||||
client_disable_ibus_focus (Client *client)
|
||||
client_disable_ibus_focus (SeatEmitter *client)
|
||||
{
|
||||
client->follows_focus = FALSE;
|
||||
|
||||
@ -725,10 +725,10 @@ client_disable_ibus_focus (Client *client)
|
||||
}
|
||||
}
|
||||
|
||||
Client *
|
||||
SeatEmitter *
|
||||
client_new (GDBusConnection *connection)
|
||||
{
|
||||
Client *client = g_object_new (TYPE_CLIENT,
|
||||
SeatEmitter *client = g_object_new (TYPE_CLIENT,
|
||||
"connection", connection,
|
||||
NULL);
|
||||
if (client->context)
|
||||
@ -741,7 +741,7 @@ filter_xkl_event (GdkXEvent *xev,
|
||||
GdkEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
SeatEmitter *client = user_data;
|
||||
XEvent *xevent = (XEvent *)xev;
|
||||
|
||||
xkl_engine_filter_events (client->xkl_engine, xevent);
|
||||
@ -752,7 +752,7 @@ static void
|
||||
on_xkl_config_changed (XklEngine *xklengine,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
SeatEmitter *client = user_data;
|
||||
gboolean retval;
|
||||
|
||||
retval = set_keyboards_from_xkl (client);
|
||||
@ -764,7 +764,7 @@ on_xkl_config_changed (XklEngine *xklengine,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_keyboards (Client *client,
|
||||
set_keyboards (SeatEmitter *client,
|
||||
const gchar * const *keyboards)
|
||||
{
|
||||
guint keyboard_id;
|
||||
@ -805,7 +805,7 @@ set_keyboards (Client *client,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_keyboards_from_xkl (Client *client)
|
||||
set_keyboards_from_xkl (SeatEmitter *client)
|
||||
{
|
||||
XklConfigRec *rec;
|
||||
gchar *layout, *keyboard;
|
||||
@ -837,7 +837,7 @@ on_xkl_state_changed (XklEngine *xklengine,
|
||||
gboolean restore,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
SeatEmitter *client = user_data;
|
||||
|
||||
if (type == GROUP_CHANGED)
|
||||
eekboard_context_set_group (client->context, value, NULL);
|
||||
@ -851,7 +851,7 @@ on_xkl_state_changed (XklEngine *xklengine,
|
||||
- get_keycode_from_gdk_keymap (Caribou: best_keycode_keyval_match)
|
||||
*/
|
||||
static guint
|
||||
get_replaced_keycode (Client *client)
|
||||
get_replaced_keycode (SeatEmitter *client)
|
||||
{
|
||||
guint keycode;
|
||||
|
||||
@ -876,7 +876,7 @@ get_replaced_keycode (Client *client)
|
||||
non-zero keycode), it simply changes the current map with the
|
||||
specified KEYCODE and KEYSYM. */
|
||||
static gboolean
|
||||
replace_keycode (Client *client,
|
||||
replace_keycode (SeatEmitter *client,
|
||||
guint keycode,
|
||||
guint *keysym)
|
||||
{
|
||||
@ -904,7 +904,7 @@ return TRUE; // FIXME: no xkb allocated at the moment, pretending all is fine
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_keycode_from_gdk_keymap (Client *client,
|
||||
get_keycode_from_gdk_keymap (SeatEmitter *client,
|
||||
guint keysym,
|
||||
guint *keycode,
|
||||
guint *modifiers)
|
||||
@ -932,7 +932,7 @@ get_keycode_from_gdk_keymap (Client *client,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int WaylandFakeKeyEvent(
|
||||
int send_virtual_keyboard_key(
|
||||
Display* dpy,
|
||||
unsigned int keycode,
|
||||
Bool is_press,
|
||||
@ -943,7 +943,7 @@ int WaylandFakeKeyEvent(
|
||||
|
||||
/* never actually used? */
|
||||
static void
|
||||
send_fake_modifier_key_event (Client *client,
|
||||
send_fake_modifier_key_event (SeatEmitter *client,
|
||||
EekModifierType modifiers,
|
||||
gboolean is_pressed)
|
||||
{
|
||||
@ -957,7 +957,7 @@ send_fake_modifier_key_event (Client *client,
|
||||
printf("Trying to send a modifier %d press %d\n", i, is_pressed);
|
||||
g_return_if_fail (keycode > 0);
|
||||
|
||||
WaylandFakeKeyEvent (xdisplay,
|
||||
send_virtual_keyboard_key (xdisplay,
|
||||
keycode,
|
||||
is_pressed,
|
||||
CurrentTime);
|
||||
@ -967,7 +967,7 @@ send_fake_modifier_key_event (Client *client,
|
||||
}
|
||||
|
||||
static void
|
||||
send_fake_key_event (Client *client,
|
||||
send_fake_key_event (SeatEmitter *client,
|
||||
guint xkeysym,
|
||||
guint keyboard_modifiers)
|
||||
{
|
||||
@ -1006,9 +1006,9 @@ send_fake_key_event (Client *client,
|
||||
modifiers |= keyboard_modifiers;
|
||||
|
||||
send_fake_modifier_key_event (client, modifiers, TRUE);
|
||||
WaylandFakeKeyEvent (xdisplay, keycode, TRUE, 20);
|
||||
send_virtual_keyboard_key (xdisplay, keycode, TRUE, 20);
|
||||
//XSync (xdisplay, False);
|
||||
WaylandFakeKeyEvent (xdisplay, keycode, FALSE, 20);
|
||||
send_virtual_keyboard_key (xdisplay, keycode, FALSE, 20);
|
||||
// XSync (xdisplay, False);
|
||||
send_fake_modifier_key_event (client, modifiers, FALSE);
|
||||
|
||||
@ -1017,7 +1017,7 @@ send_fake_key_event (Client *client,
|
||||
}
|
||||
|
||||
static void
|
||||
send_fake_key_events (Client *client,
|
||||
send_fake_key_events (SeatEmitter *client,
|
||||
EekSymbol *symbol,
|
||||
guint keyboard_modifiers)
|
||||
{
|
||||
@ -1063,7 +1063,7 @@ on_key_activated (EekboardContext *context,
|
||||
guint modifiers,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
SeatEmitter *client = user_data;
|
||||
|
||||
if (g_strcmp0 (eek_symbol_get_name (symbol), "cycle-keyboard") == 0) {
|
||||
client->keyboards_head = g_slist_next (client->keyboards_head);
|
||||
@ -1119,7 +1119,7 @@ update_modifier_keycodes (Client *client)
|
||||
}
|
||||
#endif
|
||||
gboolean
|
||||
client_enable_xtest (Client *client)
|
||||
client_enable_xtest (SeatEmitter *client)
|
||||
{
|
||||
//GdkDisplay *display = gdk_display_get_default ();
|
||||
//Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
|
||||
@ -1156,7 +1156,7 @@ client_enable_xtest (Client *client)
|
||||
}
|
||||
|
||||
void
|
||||
client_disable_xtest (Client *client)
|
||||
client_disable_xtest (SeatEmitter *client)
|
||||
{
|
||||
//if (client->xkb) {
|
||||
// XkbFreeKeyboard (client->xkb, 0, TRUE); /* free_all = TRUE */
|
||||
|
||||
26
src/client.h
26
src/client.h
@ -29,27 +29,27 @@ G_BEGIN_DECLS
|
||||
#define IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CLIENT))
|
||||
#define CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_CLIENT, ClientClass))
|
||||
|
||||
typedef struct _Client Client;
|
||||
typedef struct _Client SeatEmitter;
|
||||
|
||||
Client *client_new (GDBusConnection *connection);
|
||||
SeatEmitter *client_new (GDBusConnection *connection);
|
||||
|
||||
gboolean client_set_keyboards (Client *client,
|
||||
gboolean client_set_keyboards (SeatEmitter *client,
|
||||
const gchar * const *keyboard);
|
||||
|
||||
gboolean client_enable_xkl (Client *client);
|
||||
void client_disable_xkl (Client *client);
|
||||
gboolean client_enable_xkl (SeatEmitter *client);
|
||||
void client_disable_xkl (SeatEmitter *client);
|
||||
|
||||
gboolean client_enable_atspi_focus (Client *client);
|
||||
void client_disable_atspi_focus (Client *client);
|
||||
gboolean client_enable_atspi_focus (SeatEmitter *client);
|
||||
void client_disable_atspi_focus (SeatEmitter *client);
|
||||
|
||||
gboolean client_enable_atspi_keystroke (Client *client);
|
||||
void client_disable_atspi_keystroke (Client *client);
|
||||
gboolean client_enable_atspi_keystroke (SeatEmitter *client);
|
||||
void client_disable_atspi_keystroke (SeatEmitter *client);
|
||||
|
||||
gboolean client_enable_xtest (Client *client);
|
||||
void client_disable_xtest (Client *client);
|
||||
gboolean client_enable_xtest (SeatEmitter *client);
|
||||
void client_disable_xtest (SeatEmitter *client);
|
||||
|
||||
gboolean client_enable_ibus_focus (Client *client);
|
||||
void client_disable_ibus_focus (Client *client);
|
||||
gboolean client_enable_ibus_focus (SeatEmitter *client);
|
||||
void client_disable_ibus_focus (SeatEmitter *client);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* CLIENT_H */
|
||||
|
||||
@ -34,6 +34,7 @@ sources = [
|
||||
enums,
|
||||
keysym_entries,
|
||||
marshalers,
|
||||
'../eekboard/keymap.c',
|
||||
'../eekboard/key-emitter.c',
|
||||
'../eekboard/eekboard-context-service.c',
|
||||
'../eekboard/eekboard-context.c',
|
||||
@ -51,7 +52,9 @@ deps = [
|
||||
dependency('gtk+-3.0', version: '>=3.0'),
|
||||
dependency('libcroco-0.6'),
|
||||
dependency('wayland-client', version: '>=1.14'),
|
||||
dependency('xkbcommon'),
|
||||
cc.find_library('m'),
|
||||
cc.find_library('rt'),
|
||||
# dependency('libxklavier'), # FIXME remove
|
||||
]
|
||||
|
||||
|
||||
@ -95,6 +95,17 @@ on_notify_keyboard (GObject *object,
|
||||
const EekKeyboard *keyboard;
|
||||
|
||||
keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context));
|
||||
|
||||
if (!keyboard) {
|
||||
g_error("Programmer error: keyboard layout was unset!");
|
||||
}
|
||||
|
||||
// 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(EEKBOARD_CONTEXT_SERVICE(context),
|
||||
keyboard);
|
||||
|
||||
if (context->window) {
|
||||
if (keyboard == NULL) {
|
||||
gtk_widget_hide (context->window);
|
||||
@ -106,8 +117,9 @@ on_notify_keyboard (GObject *object,
|
||||
g_signal_handler_block (context->window,
|
||||
context->notify_visible_handler);
|
||||
update_widget (context);
|
||||
if (was_visible)
|
||||
if (was_visible) {
|
||||
gtk_widget_show_all (context->window);
|
||||
}
|
||||
g_signal_handler_unblock (context->window,
|
||||
context->notify_visible_handler);
|
||||
}
|
||||
@ -492,9 +504,9 @@ server_context_service_init (ServerContextService *context)
|
||||
context);
|
||||
}
|
||||
|
||||
ServerContextService *
|
||||
EekboardContextService *
|
||||
server_context_service_new ()
|
||||
{
|
||||
return g_object_new (SERVER_TYPE_CONTEXT_SERVICE,
|
||||
NULL);
|
||||
return EEKBOARD_CONTEXT_SERVICE(g_object_new (SERVER_TYPE_CONTEXT_SERVICE,
|
||||
NULL));
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ G_BEGIN_DECLS
|
||||
/** Manages the liecycle of the window displaying layouts. */
|
||||
typedef struct _ServerContextService ServerContextService;
|
||||
|
||||
ServerContextService *server_context_service_new ();
|
||||
EekboardContextService *server_context_service_new ();
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* SERVER_CONTEXT_SERVICE_H */
|
||||
|
||||
@ -38,6 +38,14 @@
|
||||
|
||||
#include <gdk/gdkwayland.h>
|
||||
|
||||
|
||||
/// Global application state
|
||||
struct squeekboard {
|
||||
struct squeek_wayland wayland;
|
||||
EekboardContextService *context;
|
||||
};
|
||||
|
||||
|
||||
static gboolean opt_system = FALSE;
|
||||
static gchar *opt_address = NULL;
|
||||
|
||||
@ -93,17 +101,25 @@ registry_handle_global (void *data,
|
||||
const char *interface,
|
||||
uint32_t version)
|
||||
{
|
||||
struct squeek_wayland *wayland = data;
|
||||
// currently only v1 supported for most interfaces,
|
||||
// so there's no reason to check for available versions.
|
||||
// Even when lower version would be served, it would not be supported,
|
||||
// causing a hard exit
|
||||
(void)version;
|
||||
struct squeekboard *instance = data;
|
||||
|
||||
if (!strcmp (interface, zwlr_layer_shell_v1_interface.name)) {
|
||||
wayland->layer_shell = wl_registry_bind (registry, name,
|
||||
instance->wayland.layer_shell = wl_registry_bind (registry, name,
|
||||
&zwlr_layer_shell_v1_interface, 1);
|
||||
} else if (!strcmp (interface, zwp_virtual_keyboard_manager_v1_interface.name)) {
|
||||
instance->wayland.virtual_keyboard_manager = wl_registry_bind(registry, name,
|
||||
&zwp_virtual_keyboard_manager_v1_interface, 1);
|
||||
} else if (!strcmp (interface, "wl_output")) {
|
||||
struct wl_output *output = wl_registry_bind (registry, name,
|
||||
&wl_output_interface, 2);
|
||||
g_ptr_array_add (wayland->outputs, output);
|
||||
g_ptr_array_add (instance->wayland.outputs, output);
|
||||
} else if (!strcmp(interface, "wl_seat")) {
|
||||
wayland->seat = wl_registry_bind(registry, name,
|
||||
instance->wayland.seat = wl_registry_bind(registry, name,
|
||||
&wl_seat_interface, 1);
|
||||
}
|
||||
}
|
||||
@ -139,17 +155,33 @@ main (int argc, char **argv)
|
||||
|
||||
if (display == NULL) {
|
||||
g_error ("Failed to get display: %m\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct squeek_wayland wayland = {0};
|
||||
squeek_wayland_init (&wayland);
|
||||
struct wl_registry *registry = wl_display_get_registry (display);
|
||||
wl_registry_add_listener (registry, ®istry_listener, &wayland);
|
||||
squeek_wayland_set_global(&wayland);
|
||||
|
||||
EekboardContextService *context = create_context();
|
||||
struct squeekboard instance = {0};
|
||||
squeek_wayland_init (&instance.wayland);
|
||||
struct wl_registry *registry = wl_display_get_registry (display);
|
||||
wl_registry_add_listener (registry, ®istry_listener, &instance);
|
||||
wl_display_roundtrip(display); // wait until the registry is actually populated
|
||||
squeek_wayland_set_global(&instance.wayland);
|
||||
|
||||
if (!instance.wayland.seat) {
|
||||
g_error("No seat Wayland global available.");
|
||||
exit(1);
|
||||
}
|
||||
if (!instance.wayland.virtual_keyboard_manager) {
|
||||
g_error("No virtual keyboard manager Wayland global available.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
instance.context = create_context();
|
||||
|
||||
// set up dbus
|
||||
|
||||
// TODO: make dbus errors non-always-fatal
|
||||
// dbus is not strictly necessary for the useful operation
|
||||
// if text-input is used, as it can bring the keyboard in and out
|
||||
GBusType bus_type;
|
||||
if (opt_system)
|
||||
bus_type = G_BUS_TYPE_SYSTEM;
|
||||
@ -191,16 +223,13 @@ main (int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: make dbus errors non-always-fatal
|
||||
// dbus is not strictly necessary for the useful operation
|
||||
// if text-input is used, as it can bring the keyboard in and out
|
||||
EekboardService *service = eekboard_service_new (connection, EEKBOARD_SERVICE_PATH);
|
||||
|
||||
if (service == NULL) {
|
||||
g_printerr ("Can't create server\n");
|
||||
g_printerr ("Can't create dbus server\n");
|
||||
exit (1);
|
||||
} else {
|
||||
eekboard_service_set_context(service, context);
|
||||
eekboard_service_set_context(service, instance.context);
|
||||
}
|
||||
|
||||
guint owner_id = g_bus_own_name_on_connection (connection,
|
||||
@ -226,6 +255,6 @@ main (int argc, char **argv)
|
||||
g_object_unref (connection);
|
||||
g_main_loop_unref (loop);
|
||||
|
||||
squeek_wayland_deinit (&wayland);
|
||||
squeek_wayland_deinit (&instance.wayland);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2,12 +2,14 @@
|
||||
#define WAYLAND_H
|
||||
|
||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||
#include "virtual-keyboard-unstable-v1-client-protocol.h"
|
||||
|
||||
#include <gmodule.h>
|
||||
|
||||
|
||||
struct squeek_wayland {
|
||||
struct zwlr_layer_shell_v1 *layer_shell;
|
||||
struct zwp_virtual_keyboard_manager_v1 *virtual_keyboard_manager;
|
||||
GPtrArray *outputs; // *wl_output
|
||||
struct wl_seat *seat;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user