Load keyboard key caps from key map

This commit is contained in:
DanyLE 2025-03-13 23:15:49 +01:00
parent 8020954fed
commit 24f47dfd7f
15 changed files with 2724 additions and 1985 deletions

View File

@ -52,11 +52,16 @@ endforeach
gnome=import('gnome')
incdir = include_directories([
'src'
])
base = [
'src/base.c',
'src/shell.c',
'src/wayland.c',
'src/virtual-keyboard.c',
'src/vkb/virtual-keyboard.c',
'src/vkb/virtual-keyboard-widgets.c',
wayland_targets
]
@ -77,7 +82,8 @@ executable(
'diya-shell',
dm_src,
session_resource,
dependencies: buil_dep)
dependencies: buil_dep,
include_directories : incdir)
login_src = [
base,
@ -91,4 +97,5 @@ executable(
'diya-login-shell',
login_src,
login_resource,
dependencies: buil_dep)
dependencies: buil_dep,
include_directories : incdir)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,9 @@
@import url("resource:///dev/iohub/diya/shell/virtual-keyboard.css");
/*
* {
font-family:DejaVuSans;
}
*/
.diya-login-header {
font-size: 16px;

7
resources/tpl.keymap Normal file
View File

@ -0,0 +1,7 @@
xkb_keymap {
xkb_keycodes { include "evdev+aliases(azerty)" };
xkb_types { include "complete" };
xkb_compat { include "complete" };
xkb_symbols { include "pc+fr+inet(evdev)" };
xkb_geometry { include "pc(pc105)" };
};

View File

@ -8,7 +8,7 @@
background-color: white;
border: 1px solid #CDC7C2;
border-radius: 3px;
min-width: 20px;
min-width: 30px;
/*min-height: 30px;*/
}
@ -19,20 +19,22 @@
/*
.diya-vkb-btn label {
border: 1px solid #b81f2b;
}*/
.diya-vkb-btn-level-1 {
color: black;
padding-top: 2px;
}
.diya-vkb-btn-level-2 {
color: gray;
font-size: 10px;
font-size: 9px;
padding-left: 3px;
}
.diya-vkb-btn-level-3 {
color: gray;
font-size: 10px;
font-size: 9px;
padding-right: 3px;
}

View File

@ -3,7 +3,7 @@
#include <gio/gio.h>
#include "login-shell.h"
#include "virtual-keyboard.h"
#include "vkb/virtual-keyboard-widgets.h"
#define DBUS_SERVER_NAME "dev.iohub.diya.SessionManager"
#define DBUS_SERVER_PATH "/dev/iohub/diya/SessionManager"
@ -17,8 +17,8 @@ struct _DiyaLoginShell
GtkWidget *password;
GtkWidget *status;
guint bus_watch_id;
//GtkWindow *window;
GList * windows;
// GtkWindow *window;
GList *windows;
};
G_DEFINE_FINAL_TYPE(DiyaLoginShell, diya_login_shell, DIYA_TYPE_SHELL);
@ -35,13 +35,13 @@ static void diya_login_shell_dispose(GObject *object)
}
g_object_unref(self->lock);
}
if(self->windows)
if (self->windows)
{
// destroyed all windows and free list
GList * it = NULL;
for(it = self->windows; it; it = it->next)
GList *it = NULL;
for (it = self->windows; it; it = it->next)
{
if(it->data)
if (it->data)
{
gtk_window_destroy(GTK_WINDOW(it->data));
}
@ -66,7 +66,6 @@ static void diya_login_shell_init(DiyaLoginShell *self)
self->bus_watch_id = 0;
}
static void on_method_call_return(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
(void)source_object;
@ -102,7 +101,7 @@ static void on_method_call_return(GObject *source_object, GAsyncResult *res, gpo
gtk_label_set_text(GTK_LABEL(self->status), "Login failed! Please try again.");
}
g_variant_unref(result);
//g_object_unref(reply);
// g_object_unref(reply);
}
static void on_name_appeared(GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data)
@ -123,7 +122,7 @@ static void on_name_appeared(GDBusConnection *connection, const gchar *name, con
g_dbus_message_set_body(request, g_variant_new("(ss)", username, password));
g_dbus_connection_send_message_with_reply(connection, request, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, on_method_call_return, self);
g_object_unref(request);
g_bus_unwatch_name (self->bus_watch_id);
g_bus_unwatch_name(self->bus_watch_id);
self->bus_watch_id = 0;
}
@ -168,25 +167,22 @@ static void do_login(GtkButton *button, DiyaLoginShell *self)
static void open_vkb(GtkButton *button, DiyaLoginShell *self)
{
(void) button;
DiyaVirtualKeyboard* vkb = diya_virtual_keyboard_new(DIYA_SHELL(self), NULL);
if(!vkb)
(void)button;
DiyaVirtualKeyboard *vkb = diya_shell_get_virtual_keyboard(DIYA_SHELL(self));
if (!vkb)
{
return;
}
g_warning("Sending A to: %s", diya_object_to_string(DIYA_OBJECT(vkb)));
diya_virtual_keyboard_send_key(vkb,30, VKB_KEY_STATE_PRESSED);
diya_virtual_keyboard_send_key(vkb, 30, VKB_KEY_STATE_PRESSED);
g_usleep(10000);
diya_virtual_keyboard_send_key(vkb,30, VKB_KEY_STATE_RELEASED);
diya_virtual_keyboard_send_key(vkb, 30, VKB_KEY_STATE_RELEASED);
g_usleep(10000);
// send example key
g_object_unref(vkb);
}
static void add_new_monitor(DiyaLoginShell* self, GdkMonitor* monitor, gint position)
static void add_new_monitor(DiyaLoginShell *self, GdkMonitor *monitor, gint position)
{
GtkWindow* window = GTK_WINDOW(gtk_application_window_new(diya_shell_get_application(DIYA_SHELL(self))));
GtkWindow *window = GTK_WINDOW(gtk_application_window_new(diya_shell_get_application(DIYA_SHELL(self))));
gtk_session_lock_instance_assign_window_to_monitor(self->lock, window, monitor);
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
@ -231,7 +227,7 @@ static void add_new_monitor(DiyaLoginShell* self, GdkMonitor* monitor, gint posi
GtkWidget *button = gtk_button_new_with_label("Login");
g_signal_connect(button, "clicked", G_CALLBACK(do_login), self);
//gtk_widget_set_can_focus(GTK_WIDGET(button), false);
// gtk_widget_set_can_focus(GTK_WIDGET(button), false);
gtk_box_append(GTK_BOX(box), button);
// Not displayed, but allows testing that creating popups doesn't crash GTK
@ -246,46 +242,45 @@ static void add_new_monitor(DiyaLoginShell* self, GdkMonitor* monitor, gint posi
gtk_widget_set_can_focus(GTK_WIDGET(button), false);
gtk_box_append(GTK_BOX(box), button);
DiyaVirtualKeyboardWidget* vkb_widget = diya_virtual_keyboard_widget_new();
DiyaVirtualKeyboardWidget *vkb_widget = diya_virtual_keyboard_widget_new(diya_shell_get_virtual_keyboard(DIYA_SHELL(self)));
gtk_box_append(GTK_BOX(box), GTK_WIDGET(vkb_widget));
gtk_window_set_child(GTK_WINDOW(window), box);
gtk_window_present(window);
self->windows = g_list_insert(self->windows,window, position);
self->windows = g_list_insert(self->windows, window, position);
}
static void on_monitor_changed(GListModel* monitor_lists,guint position, guint removed,guint added, gpointer object)
static void on_monitor_changed(GListModel *monitor_lists, guint position, guint removed, guint added, gpointer object)
{
g_debug("Monitor list changed at %d: added %d, removed %d", position, added, removed);
DiyaLoginShell* self = DIYA_LOGIN_SHELL(object);
if(removed > 0)
DiyaLoginShell *self = DIYA_LOGIN_SHELL(object);
if (removed > 0)
{
for (guint i = 0; i < removed; i++)
{
GtkWindow* win = GTK_WINDOW(g_list_nth(self->windows, position));
if(win)
GtkWindow *win = GTK_WINDOW(g_list_nth(self->windows, position));
if (win)
{
gtk_window_destroy(win);
self->windows = g_list_remove(self->windows, win);
}
}
}
if(added > 0)
if (added > 0)
{
for (guint i = 0; i < added; i++)
{
GdkMonitor * monitor = g_list_model_get_item(monitor_lists,position + i);
GdkMonitor *monitor = g_list_model_get_item(monitor_lists, position + i);
add_new_monitor(self, monitor, position + i);
}
}
}
static void diya_login_shell_startup(DiyaShell* shell)
static void diya_login_shell_startup(DiyaShell *shell)
{
DiyaLoginShell* self = DIYA_LOGIN_SHELL(shell);
DiyaLoginShell *self = DIYA_LOGIN_SHELL(shell);
if (!gtk_session_lock_instance_lock(self->lock))
{
g_error("gtk_session_lock_instance_lock: Unable to lock the display");
@ -312,10 +307,10 @@ static void diya_login_shell_startup(DiyaShell* shell)
GTK_STYLE_PROVIDER_PRIORITY_USER);
g_bytes_unref(bytes);
}
GListModel * list = gdk_display_get_monitors(gdk_display_get_default());
for(guint i = 0; i < g_list_model_get_n_items(list); i++)
GListModel *list = gdk_display_get_monitors(gdk_display_get_default());
for (guint i = 0; i < g_list_model_get_n_items(list); i++)
{
GdkMonitor * monitor = g_list_model_get_item(list,i);
GdkMonitor *monitor = g_list_model_get_item(list, i);
add_new_monitor(self, monitor, -1);
}
}
@ -330,6 +325,5 @@ static void diya_login_shell_class_init(DiyaLoginShellClass *class)
DiyaShellClass *base_shell_class = DIYA_SHELL_CLASS(class);
base_shell_class->monitor_changed_handle = on_monitor_changed;
base_shell_class->startup_handle = diya_login_shell_startup;
//base_shell_class->foreign_register = diya_session_shell_foreign_toplevel_register;
// base_shell_class->foreign_register = diya_session_shell_foreign_toplevel_register;
}

View File

@ -1,7 +1,7 @@
#include <glib-unix.h>
#include "shell.h"
#include "wayland.h"
#include "virtual-keyboard.h"
#include "vkb/virtual-keyboard.h"
enum
{
NO_PROP,
@ -41,6 +41,10 @@ static void diya_shell_dispose(GObject* object)
g_free(priv->name);
priv->name = NULL;
}
if(priv->vkb)
{
g_object_unref(priv->vkb);
}
G_OBJECT_CLASS(diya_shell_parent_class)->dispose(object);
if (priv->app)
{
@ -147,6 +151,7 @@ static void diya_shell_init(DiyaShell *self)
priv->wayland = NULL;
priv->app = NULL;
priv->name = NULL;
priv->vkb = NULL;
}
DiyaWayland * diya_shell_get_wayland(DiyaShell* shell)
@ -197,6 +202,16 @@ static void diya_shell_class_init(DiyaShellClass *class)
g_object_class_install_properties (gobject_class, N_PROPERTIES, shell_properties);
}
DiyaVirtualKeyboard* diya_shell_get_virtual_keyboard(DiyaShell* self)
{
DiyaShellPrivate* priv = diya_shell_get_instance_private(self);
if(!priv->vkb)
{
priv->vkb = diya_virtual_keyboard_new(self, "/home/diya/tpl.keymap");
}
return priv->vkb;
}
int diya_shell_run(DiyaShell* shell, int argc, char **argv)
{
DiyaShellPrivate* priv = diya_shell_get_instance_private(shell);

View File

@ -11,6 +11,9 @@ G_DECLARE_DERIVABLE_TYPE(DiyaShell, diya_shell, DIYA, SHELL, DiyaObject)
#define DIYA_TYPE_WAYLAND (diya_wayland_get_type ())
G_DECLARE_FINAL_TYPE (DiyaWayland, diya_wayland, DIYA, WAYLAND, DiyaShellObject)
#define DIYA_TYPE_VIRTUAL_KEYBOARD (diya_virtual_keyboard_get_type ())
G_DECLARE_FINAL_TYPE (DiyaVirtualKeyboard, diya_virtual_keyboard, DIYA, VIRTUAL_KEYBOARD, DiyaShellObject)
struct wl_registry;
typedef void (*wl_protocol_manager_register_t)(struct wl_registry*, uint32_t,DiyaShell*);
@ -29,5 +32,7 @@ DiyaWayland * diya_shell_get_wayland(DiyaShell* shell);
GtkApplication* diya_shell_get_application(DiyaShell* shell);
const char* diya_shell_get_name(DiyaShell* shell);
DiyaVirtualKeyboard* diya_shell_get_virtual_keyboard(DiyaShell* shell);
int diya_shell_run(DiyaShell* shell, int argc, char **argv);
#endif

View File

@ -1,443 +0,0 @@
#include <xkbcommon/xkbcommon.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <gio/gio.h>
#include "virtual-keyboard-unstable-v1.h"
#include "virtual-keyboard.h"
#include "wayland.h"
/**
* @brief DiyaVkbButton: virtual keyboard button
*/
struct _DiyaVkbButton
{
GtkWidget super;
GtkWidget *labels[3];
};
G_DEFINE_FINAL_TYPE(DiyaVkbButton, diya_vkb_button, GTK_TYPE_WIDGET);
static void diya_vkb_button_dispose(GObject *object)
{
DiyaVkbButton *self = DIYA_VKB_BUTTON(object);
g_debug("diya_vkb_button_dispose");
for (int i = 0; i < 3; i++)
{
g_clear_pointer(&self->labels[i], gtk_widget_unparent);
}
// g_clear_pointer (&demo->label, gtk_widget_unparent);
G_OBJECT_CLASS(diya_vkb_button_parent_class)->dispose(object);
}
static void diya_vkb_button_init(DiyaVkbButton *self)
{
gchar class_name[32]; /*diya-vkb-btn-level-%d */
GtkLayoutManager *grid_layout;
grid_layout = gtk_widget_get_layout_manager(GTK_WIDGET(self));
//gtk_orientable_set_orientation(GTK_ORIENTABLE(box_layout), GTK_ORIENTATION_VERTICAL);
// gtk_box_layout_set_spacing (GTK_BOX_LAYOUT (box_layout), 3);
gtk_widget_add_css_class(GTK_WIDGET(self),"diya-vkb-btn");
gtk_widget_set_can_focus(GTK_WIDGET(self), false);
// init labels
for (int i = 0; i < 3; i++)
{
self->labels[i] = gtk_label_new(i==0?"X":"x");
g_snprintf(class_name, sizeof(class_name),"diya-vkb-btn-level-%d",i + 1);
gtk_widget_add_css_class(self->labels[i], class_name);
gtk_widget_set_hexpand(self->labels[i], true);
gtk_widget_set_parent(self->labels[i], GTK_WIDGET(self));
GtkGridLayoutChild *grid_child = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(grid_layout,self->labels[i]));
switch (i)
{
case 0:
/* code */
gtk_grid_layout_child_set_row(grid_child,0);
gtk_grid_layout_child_set_column(grid_child,0);
gtk_grid_layout_child_set_column_span (grid_child,2);
break;
case 1:
gtk_grid_layout_child_set_row(grid_child,1);
gtk_grid_layout_child_set_column(grid_child,0);
gtk_widget_set_halign(self->labels[i],GTK_ALIGN_START);
break;
case 2:
gtk_grid_layout_child_set_row(grid_child,1);
gtk_grid_layout_child_set_column(grid_child,1);
gtk_widget_set_halign(self->labels[i],GTK_ALIGN_END);
break;
default:
break;
}
}
}
static void diya_vkb_button_class_init(DiyaVkbButtonClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_vkb_button_dispose;
gtk_widget_class_set_layout_manager_type(GTK_WIDGET_CLASS(class), GTK_TYPE_GRID_LAYOUT);
}
DiyaVkbButton* diya_vkb_button_new(/**with prameter */)
{
return DIYA_VKB_BUTTON(g_object_new(DIYA_TYPE_VKB_BUTTON, NULL));
}
/**
* @brief DiyaVirtualKeyboardWidget: Virtual keyboard GTK widget
*
*/
#define VKB_N_CELLS 145
#define VKB_ROW_NUM(i) (i/29)
#define VKB_COL_NUM(i) (i % 29)
struct _DiyaVirtualKeyboardWidget
{
GtkWidget super;
/**
* row 0: 00 - 13
* row 1: 14 - 27
* row 2: 28 - 40
* row 3: 41 - 53
* row 4: 54 - 62
*/
GList *buttons;
};
G_DEFINE_FINAL_TYPE(DiyaVirtualKeyboardWidget, diya_virtual_keyboard_widget, GTK_TYPE_WIDGET);
static void diya_virtual_keyboard_widget_dispose(GObject *object)
{
DiyaVirtualKeyboardWidget *self = DIYA_VIRTUAL_KEYBOARD_WIDGET(object);
g_debug("diya_virtual_keyboard_widget_dispose");
if(self->buttons)
{
GList * it = NULL;
for(it = self->buttons; it; it = it->next)
{
if(it->data)
{
g_clear_pointer(&it->data, gtk_widget_unparent);
}
}
}
// g_clear_pointer (&demo->label, gtk_widget_unparent);
G_OBJECT_CLASS(diya_virtual_keyboard_widget_parent_class)->dispose(object);
}
static void diya_virtual_keyboard_widget_init(DiyaVirtualKeyboardWidget *self)
{
// gtk_widget_set_size_request(GTK_WIDGET(self), 600, 400);
g_debug("diya_virtual_keyboard_widget_init: Create new widget");
GtkLayoutManager *grid_layout;
gtk_widget_add_css_class(GTK_WIDGET(self),"diya-vkb");
grid_layout = gtk_widget_get_layout_manager(GTK_WIDGET(self));
// gtk_orientable_set_orientation(GTK_ORIENTABLE(grid_layout), GTK_ORIENTATION_VERTICAL);
gtk_grid_layout_set_row_spacing(GTK_GRID_LAYOUT(grid_layout), 2);
gtk_grid_layout_set_column_spacing(GTK_GRID_LAYOUT(grid_layout), 2);
//gtk_grid_layout_set_baseline_row(GTK_GRID_LAYOUT(grid_layout), 4);
// init buttons
for (int i = 0; i < VKB_N_CELLS; i++)
{
gboolean skip = false;
int row = VKB_ROW_NUM(i);
int col = VKB_COL_NUM(i);
switch (row)
{
case 0:
skip = (col %2 != 0) || (col > 26);
break;
case 1:
skip = (col == 1) || (col == 2) || (col != 0 && col % 2 == 0);
break;
case 2:
skip = (col == 1) || (col == 2) || (col != 0 && col%2 == 0) || (col > 25);
break;
case 3:
skip = (col > 0 && col < 5) || (col != 0 && col % 2 == 0);
break;
case 4:
skip = (col > 0 && col < 3) || (col == 4) || (col==6) || (col>7 && col < 19) || (col > 19 && col %2 == 0);
break;
default:
break;
}
if(skip)
{
continue;
}
GtkWidget* button = GTK_WIDGET(diya_vkb_button_new());
self->buttons = g_list_append(self->buttons, button);
gtk_widget_set_parent(button, GTK_WIDGET(self));
gtk_widget_set_hexpand(button, true);
GtkGridLayoutChild *grid_child = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(grid_layout,button));
gtk_grid_layout_child_set_row(grid_child,row);
gtk_grid_layout_child_set_column(grid_child,col);
switch (i)
{
case 26:
case 29:
case 58:
case 116:
gtk_grid_layout_child_set_column_span (grid_child,3);
break;
case 83:
gtk_grid_layout_child_set_column_span (grid_child,4);
break;
case 87:
gtk_grid_layout_child_set_column_span (grid_child,5);
break;
case 123:
gtk_grid_layout_child_set_column_span (grid_child,12);
break;
default:
if(i > 0)
gtk_grid_layout_child_set_column_span (grid_child,2);
break;
}
}
}
static void diya_virtual_keyboard_widget_class_init(DiyaVirtualKeyboardWidgetClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_virtual_keyboard_widget_dispose;
gtk_widget_class_set_layout_manager_type(GTK_WIDGET_CLASS(class), GTK_TYPE_GRID_LAYOUT);
}
DiyaVirtualKeyboardWidget *diya_virtual_keyboard_widget_new()
{
DiyaVirtualKeyboardWidget *vkb_widget = g_object_new(DIYA_TYPE_VIRTUAL_KEYBOARD_WIDGET, NULL);
return vkb_widget;
}
/**
* @brief DiyaVirtualKeyboard class: lowlevel wayland virtual keyboard handle
*
*/
static struct zwp_virtual_keyboard_manager_v1 *g_virtual_keyboard_manager = NULL;
struct _DiyaVirtualKeyboard
{
DiyaShellObject parent;
struct zwp_virtual_keyboard_v1 *keyboard;
};
G_DEFINE_FINAL_TYPE(DiyaVirtualKeyboard, diya_virtual_keyboard, DIYA_TYPE_SHELL_OBJECT);
static void diya_virtual_keyboard_dispose(GObject *object)
{
DiyaVirtualKeyboard *self = DIYA_VIRTUAL_KEYBOARD(object);
g_debug("diya_virtual_keyboard_dispose");
if (self->keyboard)
{
zwp_virtual_keyboard_v1_destroy(self->keyboard);
}
G_OBJECT_CLASS(diya_virtual_keyboard_parent_class)->dispose(object);
}
static void diya_virtual_keyboard_init(DiyaVirtualKeyboard *self)
{
self->keyboard = NULL;
}
static const gchar *diya_virtual_keyboard_to_string(DiyaObject *object)
{
(void)object;
return "Diya virtual keyboard instance";
}
static void diya_virtual_keyboard_class_init(DiyaVirtualKeyboardClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->dispose = diya_virtual_keyboard_dispose;
// gobject_class->set_property = diya_lock_session_set_property;
// gobject_class->get_property = diya_lock_session_get_property;
base_class->to_string = diya_virtual_keyboard_to_string;
}
/*
static void randname(char *buf)
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
long r = ts.tv_nsec;
for (int i = 0; i < 6; ++i)
{
buf[i] = 'A' + (r & 15) + (r & 16) * 2;
r >>= 5;
}
}
*/
static int create_keymap_fd(off_t size)
{
static const char name[] = "/diya-shell-keymap-XXXXXX";
const char *base;
char *path;
int fd;
int ret;
// randname(name + sizeof(name) - 7);
base = getenv("XDG_RUNTIME_DIR");
if (!base)
{
errno = ENOENT;
return -1;
}
path = malloc(strlen(base) + sizeof(name) + 1);
if (!path)
return -1;
strcpy(path, base);
strcat(path, name);
g_debug("Create temp file for keymap: %s", path);
fd = mkstemp(path);
if (fd >= 0)
{
long flags;
flags = fcntl(fd, F_GETFD);
if (flags == -1)
{
g_critical("fcntl Unable to F_GETFD: %s", strerror(errno));
close(fd);
fd = -1;
}
else if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
{
g_critical("fcntl Unable to F_SETFD(FD_CLOEXEC): %s", strerror(errno));
close(fd);
fd = -1;
}
unlink(path);
}
else
{
g_critical("mkstemp Unable to create temp file %s: %s", path, strerror(errno));
}
free(path);
if (fd < 0)
return -1;
do
{
ret = ftruncate(fd, size);
} while (ret < 0 && errno == EINTR);
if (ret < 0)
{
close(fd);
return -1;
}
return fd;
}
DiyaVirtualKeyboard *diya_virtual_keyboard_new(DiyaShell *shell, const gchar *keymap_file)
{
gchar *content = NULL;
GError *error = NULL;
GBytes *bytes = NULL;
gsize len = 0;
if (keymap_file)
{
g_file_get_contents(keymap_file, &content, &len, &error);
if (error != NULL)
{
g_critical("diya_virtual_keyboard_new: Unable to read file %s: %s", keymap_file, error->message);
g_error_free(error);
return NULL;
}
}
else
{
g_warning("No keymap file specified. Loading default keymap from resource");
GBytes *bytes = g_resources_lookup_data("/dev/iohub/diya/shell/default.keymap", 0, &error);
if (error != NULL)
{
g_critical("Unable to read keymap file from resource %s", error->message);
g_error_free(error);
return NULL;
}
content = (gchar *)g_bytes_get_data(bytes, &len);
}
g_debug("Using default keymap configuration: \n%s", content);
int fd = create_keymap_fd(len);
if (fd == -1)
{
g_critical("diya_virtual_keyboard_new: create temp file");
if (bytes)
{
g_bytes_unref(bytes);
content = NULL;
}
if (content)
{
g_free(content);
}
}
void *ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == (void *)-1)
{
g_critical("diya_virtual_keyboard_new: error mmap: %s", strerror(errno));
close(fd);
if (bytes)
{
g_bytes_unref(bytes);
content = NULL;
}
if (content)
{
g_free(content);
}
}
strcpy((char *)ptr, content);
DiyaVirtualKeyboard *vkb = g_object_new(DIYA_TYPE_VIRTUAL_KEYBOARD, "shell", shell, NULL);
DiyaWayland *wayland = diya_shell_get_wayland(shell);
struct wl_seat *seat = diya_wayland_get_seat(wayland);
vkb->keyboard = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(g_virtual_keyboard_manager, seat);
zwp_virtual_keyboard_v1_keymap(vkb->keyboard, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, fd, len);
return vkb;
}
void diya_virtual_keyboard_register(struct wl_registry *registry, uint32_t name, DiyaShell *shell)
{
(void)shell;
g_virtual_keyboard_manager = wl_registry_bind(registry, name, &zwp_virtual_keyboard_manager_v1_interface, 1);
}
void diya_virtual_keyboard_send_key(DiyaVirtualKeyboard *self, uint32_t key, diya_vkb_state_t state)
{
GDateTime *now = g_date_time_new_now_local();
uint32_t current_time_ms = g_date_time_get_microsecond(now) / 1000;
g_date_time_unref(now);
zwp_virtual_keyboard_v1_key(self->keyboard, current_time_ms, key, (uint32_t)state);
}

View File

@ -1,31 +0,0 @@
#ifndef DIYA_VIRTUAL_KEYBOARD_H
#define DIYA_VIRTUAL_KEYBOARD_H
#include "shell.h"
typedef enum
{
VKB_KEY_STATE_RELEASED = 0 /*WL_KEYBOARD_KEY_STATE_RELEASED*/,
VKB_KEY_STATE_PRESSED = 1 /*WL_KEYBOARD_KEY_STATE_PRESSED*/,
} diya_vkb_state_t;
#define DIYA_TYPE_VIRTUAL_KEYBOARD (diya_virtual_keyboard_get_type ())
G_DECLARE_FINAL_TYPE (DiyaVirtualKeyboard, diya_virtual_keyboard, DIYA, VIRTUAL_KEYBOARD, DiyaShellObject)
DiyaVirtualKeyboard* diya_virtual_keyboard_new(DiyaShell* shell, const gchar* keymap_file);
void diya_virtual_keyboard_register(struct wl_registry *registry, uint32_t name, DiyaShell *shell);
void diya_virtual_keyboard_send_key(DiyaVirtualKeyboard* vkb, uint32_t key, diya_vkb_state_t state);
#define DIYA_TYPE_VIRTUAL_KEYBOARD_WIDGET (diya_virtual_keyboard_widget_get_type())
G_DECLARE_FINAL_TYPE (DiyaVirtualKeyboardWidget, diya_virtual_keyboard_widget, DIYA, VIRTUAL_KEYBOARD_WIDGET, GtkWidget)
DiyaVirtualKeyboardWidget* diya_virtual_keyboard_widget_new();
#define DIYA_TYPE_VKB_BUTTON (diya_vkb_button_get_type())
G_DECLARE_FINAL_TYPE (DiyaVkbButton, diya_vkb_button, DIYA, VKB_BUTTON, GtkWidget)
DiyaVkbButton* diya_vkb_button_new(/**with prameter */);
#endif

View File

@ -0,0 +1,253 @@
#include "virtual-keyboard-widgets.h"
/**
* @brief DiyaVkbButton: virtual keyboard button
*/
struct _DiyaVkbButton
{
GtkWidget super;
GtkWidget *labels[3];
DiyaVkbKey *key;
};
G_DEFINE_FINAL_TYPE(DiyaVkbButton, diya_vkb_button, GTK_TYPE_WIDGET);
static void diya_vkb_button_dispose(GObject *object)
{
DiyaVkbButton *self = DIYA_VKB_BUTTON(object);
g_debug("diya_vkb_button_dispose");
for (int i = 0; i < 3; i++)
{
g_clear_pointer(&self->labels[i], gtk_widget_unparent);
}
if (self->key)
{
g_object_unref(self->key);
self->key = NULL;
}
// g_clear_pointer (&demo->label, gtk_widget_unparent);
G_OBJECT_CLASS(diya_vkb_button_parent_class)->dispose(object);
}
static void diya_vkb_button_init(DiyaVkbButton *self)
{
gchar class_name[32]; /*diya-vkb-btn-level-%d */
GtkLayoutManager *grid_layout;
self->key = NULL;
grid_layout = gtk_widget_get_layout_manager(GTK_WIDGET(self));
// gtk_orientable_set_orientation(GTK_ORIENTABLE(box_layout), GTK_ORIENTATION_VERTICAL);
// gtk_box_layout_set_spacing (GTK_BOX_LAYOUT (box_layout), 3);
gtk_widget_add_css_class(GTK_WIDGET(self), "diya-vkb-btn");
gtk_widget_set_can_focus(GTK_WIDGET(self), false);
// init labels
for (int i = 0; i < 3; i++)
{
self->labels[i] = gtk_label_new(NULL);
g_snprintf(class_name, sizeof(class_name), "diya-vkb-btn-level-%d", i + 1);
gtk_widget_add_css_class(self->labels[i], class_name);
gtk_widget_set_hexpand(self->labels[i], true);
gtk_widget_set_parent(self->labels[i], GTK_WIDGET(self));
GtkGridLayoutChild *grid_child = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(grid_layout, self->labels[i]));
switch (i)
{
case 0:
/* code */
gtk_grid_layout_child_set_row(grid_child, 0);
gtk_grid_layout_child_set_column(grid_child, 0);
gtk_grid_layout_child_set_column_span(grid_child, 2);
break;
case 1:
gtk_grid_layout_child_set_row(grid_child, 1);
gtk_grid_layout_child_set_column(grid_child, 0);
gtk_widget_set_halign(self->labels[i], GTK_ALIGN_START);
break;
case 2:
gtk_grid_layout_child_set_row(grid_child, 1);
gtk_grid_layout_child_set_column(grid_child, 1);
gtk_widget_set_halign(self->labels[i], GTK_ALIGN_END);
break;
default:
break;
}
}
}
static void diya_vkb_button_class_init(DiyaVkbButtonClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_vkb_button_dispose;
gtk_widget_class_set_layout_manager_type(GTK_WIDGET_CLASS(class), GTK_TYPE_GRID_LAYOUT);
}
DiyaVkbButton *diya_vkb_button_new(DiyaVkbKey *key)
{
DiyaVkbButton *btn = DIYA_VKB_BUTTON(g_object_new(DIYA_TYPE_VKB_BUTTON, NULL));
btn->key = key;
for (uint32_t i = 0; i < 3; i++)
{
const char *cap = diya_vkb_key_get_keycap(key, i);
if (cap)
{
if(i == 1 && diya_vkb_key_is_alphabet(key))
{
continue;
}
gtk_label_set_text(GTK_LABEL(btn->labels[i]), cap);
}
}
return btn;
}
/**
* @brief DiyaVirtualKeyboardWidget: Virtual keyboard GTK widget
*
*/
#define VKB_N_CELLS 145
#define VKB_ROW_NUM(i) (i / 29)
#define VKB_COL_NUM(i) (i % 29)
static uint32_t g_vkb_layout[] = {
49, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 51,
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 36,
50, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 111, 66,
9, 206, 64, 65, 0, 108, 113, 116, 114};
struct _DiyaVirtualKeyboardWidget
{
GtkWidget super;
/**
* row 0: 00 - 13
* row 1: 14 - 27
* row 2: 28 - 40
* row 3: 41 - 53
* row 4: 54 - 62
*/
GList *buttons;
DiyaVirtualKeyboard *vkb;
};
G_DEFINE_FINAL_TYPE(DiyaVirtualKeyboardWidget, diya_virtual_keyboard_widget, GTK_TYPE_WIDGET);
static void diya_virtual_keyboard_widget_dispose(GObject *object)
{
DiyaVirtualKeyboardWidget *self = DIYA_VIRTUAL_KEYBOARD_WIDGET(object);
g_debug("diya_virtual_keyboard_widget_dispose");
if (self->buttons)
{
GList *it = NULL;
for (it = self->buttons; it; it = it->next)
{
if (it->data)
{
g_clear_pointer(&it->data, gtk_widget_unparent);
}
}
}
// g_clear_pointer (&demo->label, gtk_widget_unparent);
G_OBJECT_CLASS(diya_virtual_keyboard_widget_parent_class)->dispose(object);
}
static void diya_virtual_keyboard_widget_init(DiyaVirtualKeyboardWidget *self)
{
//gtk_widget_set_size_request(GTK_WIDGET(self), 600, 400);
g_debug("diya_virtual_keyboard_widget_init: Create new widget");
gtk_widget_add_css_class(GTK_WIDGET(self), "diya-vkb");
GtkLayoutManager *grid_layout = gtk_widget_get_layout_manager(GTK_WIDGET(self));
// gtk_orientable_set_orientation(GTK_ORIENTABLE(grid_layout), GTK_ORIENTATION_VERTICAL);
gtk_grid_layout_set_row_spacing(GTK_GRID_LAYOUT(grid_layout), 2);
gtk_grid_layout_set_column_spacing(GTK_GRID_LAYOUT(grid_layout), 2);
// gtk_grid_layout_set_baseline_row(GTK_GRID_LAYOUT(grid_layout), 4);
// init buttons
self->vkb = NULL;
}
static void diya_virtual_keyboard_widget_class_init(DiyaVirtualKeyboardWidgetClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_virtual_keyboard_widget_dispose;
gtk_widget_class_set_layout_manager_type(GTK_WIDGET_CLASS(class), GTK_TYPE_GRID_LAYOUT);
}
DiyaVirtualKeyboardWidget *diya_virtual_keyboard_widget_new(DiyaVirtualKeyboard *kb)
{
DiyaVirtualKeyboardWidget *self = g_object_new(DIYA_TYPE_VIRTUAL_KEYBOARD_WIDGET, NULL);
GtkLayoutManager *grid_layout = gtk_widget_get_layout_manager(GTK_WIDGET(self));
self->vkb = kb;
int btn_index = 0;
for (int i = 0; i < VKB_N_CELLS; i++)
{
gboolean skip = false;
int row = VKB_ROW_NUM(i);
int col = VKB_COL_NUM(i);
switch (row)
{
case 0:
skip = (col % 2 != 0) || (col > 26);
break;
case 1:
skip = (col == 1) || (col == 2) || (col != 0 && col % 2 == 0);
break;
case 2:
skip = (col == 1) || (col == 2) || (col != 0 && col % 2 == 0) || (col > 25);
break;
case 3:
skip = (col > 0 && col < 5) || (col != 0 && col % 2 == 0);
break;
case 4:
skip = (col > 0 && col < 3) || (col == 4) || (col == 6) || (col > 7 && col < 19) || (col > 19 && col % 2 == 0);
break;
default:
break;
}
if (skip)
{
continue;
}
DiyaVkbKey *key = diya_virtual_keyboard_get_key(self->vkb, g_vkb_layout[btn_index]);
g_debug("add: %s", diya_object_to_string(key));
btn_index++;
GtkWidget *button = GTK_WIDGET(diya_vkb_button_new(key));
self->buttons = g_list_append(self->buttons, button);
gtk_widget_set_parent(button, GTK_WIDGET(self));
gtk_widget_set_hexpand(button, true);
GtkGridLayoutChild *grid_child = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(grid_layout, button));
gtk_grid_layout_child_set_row(grid_child, row);
gtk_grid_layout_child_set_column(grid_child, col);
switch (i)
{
case 26:
case 29:
case 58:
case 116:
gtk_grid_layout_child_set_column_span(grid_child, 3);
break;
case 83:
gtk_grid_layout_child_set_column_span(grid_child, 4);
break;
case 87:
gtk_grid_layout_child_set_column_span(grid_child, 5);
break;
case 123:
gtk_grid_layout_child_set_column_span(grid_child, 12);
break;
default:
if (i > 0)
gtk_grid_layout_child_set_column_span(grid_child, 2);
break;
}
}
return self;
}

View File

@ -0,0 +1,18 @@
#ifndef DIYA_VIRTUAL_KEYBOARD_WIDGETS_H
#define DIYA_VIRTUAL_KEYBOARD_WIDGETS_H
#include "shell.h"
#include "virtual-keyboard.h"
#define DIYA_TYPE_VIRTUAL_KEYBOARD_WIDGET (diya_virtual_keyboard_widget_get_type())
G_DECLARE_FINAL_TYPE (DiyaVirtualKeyboardWidget, diya_virtual_keyboard_widget, DIYA, VIRTUAL_KEYBOARD_WIDGET, GtkWidget)
DiyaVirtualKeyboardWidget* diya_virtual_keyboard_widget_new();
#define DIYA_TYPE_VKB_BUTTON (diya_vkb_button_get_type())
G_DECLARE_FINAL_TYPE (DiyaVkbButton, diya_vkb_button, DIYA, VKB_BUTTON, GtkWidget)
DiyaVkbButton* diya_vkb_button_new(DiyaVkbKey* key);
#endif

440
src/vkb/virtual-keyboard.c Normal file
View File

@ -0,0 +1,440 @@
#include <xkbcommon/xkbcommon.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <gio/gio.h>
#include "virtual-keyboard-unstable-v1.h"
#include "virtual-keyboard.h"
#include "wayland.h"
struct _DiyaVkbKey
{
DiyaObject parent;
uint32_t code;
gchar *key_caps[3];
uint32_t syms[3];
gchar *info;
};
G_DEFINE_FINAL_TYPE(DiyaVkbKey, diya_vkb_key, DIYA_TYPE_OBJECT)
static void diya_vkb_key_dispose(GObject *object)
{
DiyaVkbKey *self = DIYA_VKB_KEY(object);
g_debug("diya_vkb_key_dispose: %s", diya_object_to_string(object));
for (int i = 0; i < 3; i++)
{
if (self->key_caps[i])
{
free(self->key_caps[i]);
}
}
self->code = 0;
if (self->info)
{
free(self->info);
self->info = NULL;
}
G_OBJECT_CLASS(diya_vkb_key_parent_class)->dispose(object);
}
static void diya_vkb_key_init(DiyaVkbKey *self)
{
self->code = 0;
memset(self->key_caps, 0, sizeof(self->key_caps));
memset(self->syms, 0, sizeof(self->syms));
self->info = NULL;
}
static const gchar *diya_vkb_key_to_string(DiyaObject *object)
{
DiyaVkbKey *self = DIYA_VKB_KEY(object);
if (!self->info && self->code != 0)
{
self->info = (char *)malloc(128);
g_snprintf(self->info, 128,
"DiyaVkbKey: %d (0x%.4x: %s, 0x%.4x: %s, 0x%.4x: %s)",
self->code,
self->syms[0],
self->key_caps[0],
self->syms[1],
self->key_caps[1],
self->syms[2],
self->key_caps[2]);
}
return self->info;
}
static void diya_vkb_key_class_init(DiyaVkbKeyClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->dispose = diya_vkb_key_dispose;
// gobject_class->set_property = diya_lock_session_set_property;
// gobject_class->get_property = diya_lock_session_get_property;
base_class->to_string = diya_vkb_key_to_string;
}
const gchar *diya_vkb_key_get_keycap(DiyaVkbKey *key, uint32_t shift_level)
{
if (shift_level > 2)
{
return NULL;
}
return key->key_caps[shift_level];
}
uint32_t diya_vkb_key_get_code(DiyaVkbKey *key)
{
return key->code;
}
uint32_t diya_vkb_key_is_alphabet(DiyaVkbKey* self)
{
return (self->code >= 24 && self->code <= 33) ||
(self->code >= 38 && self->code <= 46) ||
(self->code >= 52 && self->code <= 58);
}
/**
* @brief DiyaVirtualKeyboard class: lowlevel wayland virtual keyboard handle
*
*/
static struct zwp_virtual_keyboard_manager_v1 *g_virtual_keyboard_manager = NULL;
struct _DiyaVirtualKeyboard
{
DiyaShellObject parent;
struct zwp_virtual_keyboard_v1 *keyboard;
struct xkb_context *vkb_ctx;
struct xkb_keymap *vkb_keymap;
};
G_DEFINE_FINAL_TYPE(DiyaVirtualKeyboard, diya_virtual_keyboard, DIYA_TYPE_SHELL_OBJECT);
static void diya_virtual_keyboard_dispose(GObject *object)
{
DiyaVirtualKeyboard *self = DIYA_VIRTUAL_KEYBOARD(object);
g_debug("diya_virtual_keyboard_dispose");
if (self->keyboard)
{
zwp_virtual_keyboard_v1_destroy(self->keyboard);
}
if (self->vkb_keymap)
{
xkb_keymap_unref(self->vkb_keymap);
}
if (self->vkb_ctx)
{
xkb_context_unref(self->vkb_ctx);
}
G_OBJECT_CLASS(diya_virtual_keyboard_parent_class)->dispose(object);
}
static void diya_virtual_keyboard_init(DiyaVirtualKeyboard *self)
{
self->keyboard = NULL;
self->vkb_ctx = NULL;
self->vkb_keymap = NULL;
}
static const gchar *diya_virtual_keyboard_to_string(DiyaObject *object)
{
(void)object;
return "Diya virtual keyboard instance";
}
static void diya_virtual_keyboard_class_init(DiyaVirtualKeyboardClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->dispose = diya_virtual_keyboard_dispose;
// gobject_class->set_property = diya_lock_session_set_property;
// gobject_class->get_property = diya_lock_session_get_property;
base_class->to_string = diya_virtual_keyboard_to_string;
}
/*
static void randname(char *buf)
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
long r = ts.tv_nsec;
for (int i = 0; i < 6; ++i)
{
buf[i] = 'A' + (r & 15) + (r & 16) * 2;
r >>= 5;
}
}
*/
static int create_keymap_fd(off_t size)
{
static const char name[] = "/diya-shell-keymap-XXXXXX";
const char *base;
char *path;
int fd;
int ret;
// randname(name + sizeof(name) - 7);
base = getenv("XDG_RUNTIME_DIR");
if (!base)
{
errno = ENOENT;
return -1;
}
path = malloc(strlen(base) + sizeof(name) + 1);
if (!path)
return -1;
strcpy(path, base);
strcat(path, name);
g_debug("Create temp file for keymap: %s", path);
fd = mkstemp(path);
if (fd >= 0)
{
long flags;
flags = fcntl(fd, F_GETFD);
if (flags == -1)
{
g_critical("fcntl Unable to F_GETFD: %s", strerror(errno));
close(fd);
fd = -1;
}
else if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
{
g_critical("fcntl Unable to F_SETFD(FD_CLOEXEC): %s", strerror(errno));
close(fd);
fd = -1;
}
unlink(path);
}
else
{
g_critical("mkstemp Unable to create temp file %s: %s", path, strerror(errno));
}
free(path);
if (fd < 0)
return -1;
do
{
ret = ftruncate(fd, size);
} while (ret < 0 && errno == EINTR);
if (ret < 0)
{
close(fd);
return -1;
}
return fd;
}
DiyaVirtualKeyboard *diya_virtual_keyboard_new(DiyaShell *shell, const gchar *keymap_file)
{
struct xkb_context *vkb_ctx = NULL;
struct xkb_keymap *vkb_keymap = NULL;
gsize len = 0;
vkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!vkb_ctx)
{
g_critical("diya_virtual_keyboard_new: Failed to create XKB context: %s", strerror(errno));
return NULL;
}
if (keymap_file)
{
g_debug("diya_virtual_keyboard_new: Load keymap from file: %s", keymap_file);
FILE *fp = fopen(keymap_file, "r");
if (!fp)
{
g_critical("diya_virtual_keyboard_new: Failed to open file %s: %s", keymap_file, strerror(errno));
xkb_context_unref(vkb_ctx);
return NULL;
}
vkb_keymap = xkb_keymap_new_from_file(vkb_ctx, fp, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
fclose(fp);
}
else
{
GError *error = NULL;
g_warning("No keymap file specified. Loading default keymap from resource");
GBytes *bytes = g_resources_lookup_data("/dev/iohub/diya/shell/default.keymap", 0, &error);
if (error != NULL)
{
g_critical("Unable to read keymap file from resource %s", error->message);
g_error_free(error);
xkb_context_unref(vkb_ctx);
return NULL;
}
vkb_keymap = xkb_keymap_new_from_string(vkb_ctx, (gchar *)g_bytes_get_data(bytes, &len), XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
g_bytes_unref(bytes);
}
if (!vkb_keymap)
{
g_critical("diya_virtual_keyboard_new: Unable to load keymap: %s", strerror(errno));
xkb_context_unref(vkb_ctx);
return NULL;
}
char *content = xkb_keymap_get_as_string(vkb_keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
len = strlen(content);
if (!content)
{
g_critical("diya_virtual_keyboard_new: xkb_keymap_get_as_string: %s", strerror(errno));
xkb_context_unref(vkb_ctx);
xkb_keymap_unref(vkb_keymap);
return NULL;
}
int fd = create_keymap_fd(len);
if (fd == -1)
{
g_critical("diya_virtual_keyboard_new: create temp file");
xkb_context_unref(vkb_ctx);
xkb_keymap_unref(vkb_keymap);
return NULL;
}
void *ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == (void *)-1)
{
g_critical("diya_virtual_keyboard_new: error mmap: %s", strerror(errno));
xkb_context_unref(vkb_ctx);
xkb_keymap_unref(vkb_keymap);
close(fd);
return NULL;
}
// g_debug("Using keymap configuration: \n%s", content);
strcpy((char *)ptr, content);
free(content);
DiyaVirtualKeyboard *vkb = g_object_new(DIYA_TYPE_VIRTUAL_KEYBOARD, "shell", shell, NULL);
vkb->vkb_ctx = vkb_ctx;
vkb->vkb_keymap = vkb_keymap;
DiyaWayland *wayland = diya_shell_get_wayland(shell);
struct wl_seat *seat = diya_wayland_get_seat(wayland);
vkb->keyboard = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(g_virtual_keyboard_manager, seat);
zwp_virtual_keyboard_v1_keymap(vkb->keyboard, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, fd, len);
return vkb;
}
void diya_virtual_keyboard_register(struct wl_registry *registry, uint32_t name, DiyaShell *shell)
{
(void)shell;
g_virtual_keyboard_manager = wl_registry_bind(registry, name, &zwp_virtual_keyboard_manager_v1_interface, 1);
}
void diya_virtual_keyboard_send_key(DiyaVirtualKeyboard *self, uint32_t key, diya_vkb_state_t state)
{
GDateTime *now = g_date_time_new_now_local();
uint32_t current_time_ms = g_date_time_get_microsecond(now) / 1000;
g_date_time_unref(now);
zwp_virtual_keyboard_v1_key(self->keyboard, current_time_ms, key, (uint32_t)state);
}
gchar *diya_virtual_keyboard_get_keycap(const xkb_keysym_t *sym)
{
char buf[32];
switch (*sym)
{
case XKB_KEY_Escape:
g_snprintf(buf, sizeof(buf), "%s", "Esc");
break;
case XKB_KEY_BackSpace:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Tab:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Return:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Control_L:
g_snprintf(buf, sizeof(buf), "%s", "Ctrl");
break;
case XKB_KEY_Shift_L:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Caps_Lock:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Alt_L:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Alt_R:
case XKB_KEY_ISO_Level3_Shift:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_space:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Up:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Down:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Left:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Right:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_function:
g_snprintf(buf, sizeof(buf), "%s", "Fn");
break;
case XKB_KEY_Meta_L:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Super_L:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_dead_circumflex:
g_snprintf(buf, sizeof(buf), "%s", "^");
break;
case XKB_KEY_dead_diaeresis:
g_snprintf(buf, sizeof(buf), "%s", "¨");
break;
default:
if (xkb_keysym_to_utf8(*sym, buf, sizeof(buf)) == 0)
{
return NULL;
}
break;
}
return g_strdup(buf);
}
DiyaVkbKey *diya_virtual_keyboard_get_key(DiyaVirtualKeyboard *self, uint32_t code)
{
DiyaVkbKey *key = g_object_new(DIYA_TYPE_VKB_KEY, NULL);
key->code = code;
int n_level = xkb_keymap_num_levels_for_key(self->vkb_keymap, code, 0);
if (n_level > 0)
{
n_level = n_level > 3 ? 3 : n_level;
for (int level = 0; level < n_level; level++)
{
const xkb_keysym_t *syms = NULL;
int n_sym = xkb_keymap_key_get_syms_by_level(self->vkb_keymap, code, 0, level, &syms);
if (n_sym <= 0 || syms[0] == key->syms[0] || syms[0] == key->syms[1])
{
continue;
}
key->syms[level] = syms[0];
key->key_caps[level] = diya_virtual_keyboard_get_keycap(&syms[0]);
}
}
return key;
}

View File

@ -0,0 +1,25 @@
#ifndef DIYA_VIRTUAL_KEYBOARD_H
#define DIYA_VIRTUAL_KEYBOARD_H
#include "shell.h"
typedef enum
{
VKB_KEY_STATE_RELEASED = 0 /*WL_KEYBOARD_KEY_STATE_RELEASED*/,
VKB_KEY_STATE_PRESSED = 1 /*WL_KEYBOARD_KEY_STATE_PRESSED*/,
} diya_vkb_state_t;
#define DIYA_TYPE_VKB_KEY (diya_vkb_key_get_type ())
G_DECLARE_FINAL_TYPE (DiyaVkbKey, diya_vkb_key, DIYA, VKB_KEY, DiyaObject)
const gchar* diya_vkb_key_get_keycap(DiyaVkbKey* key, uint32_t shift_level);
uint32_t diya_vkb_key_get_code(DiyaVkbKey* key);
uint32_t diya_vkb_key_is_alphabet(DiyaVkbKey* key);
DiyaVirtualKeyboard* diya_virtual_keyboard_new(DiyaShell* shell, const gchar* keymap_file);
void diya_virtual_keyboard_register(struct wl_registry *registry, uint32_t name, DiyaShell *shell);
void diya_virtual_keyboard_send_key(DiyaVirtualKeyboard* vkb, uint32_t key, diya_vkb_state_t state);
DiyaVkbKey* diya_virtual_keyboard_get_key(DiyaVirtualKeyboard* vkb, uint32_t key);
#endif