diff --git a/resources/gresource-login.xml b/resources/gresource-login.xml index eafd9a0..3df818d 100644 --- a/resources/gresource-login.xml +++ b/resources/gresource-login.xml @@ -1,7 +1,7 @@ - resources/login-shell.css + resources/login-shell.css resources/virtual-keyboard.css resources/default.keymap diff --git a/resources/gresource-session.xml b/resources/gresource-session.xml index 845bda4..4c70a9b 100644 --- a/resources/gresource-session.xml +++ b/resources/gresource-session.xml @@ -1,6 +1,7 @@ + resources/session-shell.css resources/default.keymap \ No newline at end of file diff --git a/resources/login-shell.css b/resources/login-shell.css index 7f92299..476560c 100644 --- a/resources/login-shell.css +++ b/resources/login-shell.css @@ -1,16 +1,21 @@ @import url("resource:///dev/iohub/diya/shell/virtual-keyboard.css"); -/* -* { - font-family:DejaVuSans; -} -*/ -.diya-login-header { +#diya_login_shell +{ +} + +#diya_login_shell label.diya-login-header { font-size: 16px; font-weight: bold; } -.diya-login-status { +#diya_login_shell label.diya-login-status { font-size: 12px; color: red; +} + +#diya_login_shell button.diya-btn-show-vkb +{ + color: gray; + min-width: 0px; } \ No newline at end of file diff --git a/resources/session-shell.css b/resources/session-shell.css new file mode 100644 index 0000000..36cf45c --- /dev/null +++ b/resources/session-shell.css @@ -0,0 +1,11 @@ +@import url("resource:///dev/iohub/diya/shell/virtual-keyboard.css"); + +#diya_shell_launcher +{ + background-color: orange; +} +#diya_shell_background +{ + background-image:url("file:///etc/xdg/labwc/wpp.jpg"); + background-size: cover; +} \ No newline at end of file diff --git a/resources/virtual-keyboard.css b/resources/virtual-keyboard.css index dcf8b96..1d800bb 100644 --- a/resources/virtual-keyboard.css +++ b/resources/virtual-keyboard.css @@ -1,18 +1,25 @@ -.diya-vkb +diya-vkb { background-color: transparent; - border: 1px solid orangered; + /* border: 1px solid orangered; */ } -.diya-vkb-btn { +diya-vkb-button +{ background-color: white; border: 1px solid #CDC7C2; border-radius: 3px; min-width: 30px; - /*min-height: 30px;*/ + min-height: 30px; + box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.19); } -.diya-vkb-btn:hover +diya-vkb-button.active +{ + background-color: #E7E6E2; +} + +diya-vkb-button:hover { background-color: #E7E6E2; } @@ -22,18 +29,19 @@ }*/ -.diya-vkb-btn-level-1 { +diya-vkb-button label.shift-level-1 { color: black; padding-top: 2px; + font-size: 12px; } -.diya-vkb-btn-level-2 { +diya-vkb-button label.shift-level-2 { color: gray; font-size: 9px; padding-left: 3px; } -.diya-vkb-btn-level-3 { +diya-vkb-button label.shift-level-3 { color: gray; font-size: 9px; padding-right: 3px; diff --git a/src/background.c b/src/background.c index f1f75d6..d68e3f9 100644 --- a/src/background.c +++ b/src/background.c @@ -1,6 +1,6 @@ #include "background.h" #include -#define NAMESPACE "background" +#define NAMESPACE "diya_shell_background" static void on_background_destroy(GtkWindow *window, GApplication *_data) { diff --git a/src/launcher.c b/src/launcher.c index 6e52b1d..9bddabb 100644 --- a/src/launcher.c +++ b/src/launcher.c @@ -3,7 +3,7 @@ #include "session-lock.h" #include -#define NAMESPACE "launcher" +#define NAMESPACE "diya_shell_launcher" static void on_launcher_destroy(GtkWindow *window, GApplication *_data) { @@ -51,8 +51,8 @@ void diya_session_shell_launcher_init(DiyaSessionShell * shell) // anchor window to all edges gtk_layer_set_anchor (gtk_window, GTK_LAYER_SHELL_EDGE_LEFT, true); gtk_layer_set_anchor (gtk_window, GTK_LAYER_SHELL_EDGE_RIGHT, true); - gtk_layer_set_anchor (gtk_window, GTK_LAYER_SHELL_EDGE_TOP, true); - gtk_layer_set_anchor (gtk_window, GTK_LAYER_SHELL_EDGE_BOTTOM, false); + gtk_layer_set_anchor (gtk_window, GTK_LAYER_SHELL_EDGE_TOP, false); + gtk_layer_set_anchor (gtk_window, GTK_LAYER_SHELL_EDGE_BOTTOM, true); // set margin on window for (int i = 0; i < GTK_LAYER_SHELL_EDGE_ENTRY_NUMBER; i++) diff --git a/src/login-shell.c b/src/login-shell.c index 944c8d6..ec9aee5 100644 --- a/src/login-shell.c +++ b/src/login-shell.c @@ -8,6 +8,7 @@ #define DBUS_SERVER_NAME "dev.iohub.diya.SessionManager" #define DBUS_SERVER_PATH "/dev/iohub/diya/SessionManager" #define DBUS_SERVER_ERROR_NAME "dev.iohub.diya.SessionManager.Error" +#define NAMESPACE "diya_login_shell" struct _DiyaLoginShell { @@ -17,7 +18,7 @@ struct _DiyaLoginShell GtkWidget *password; GtkWidget *status; guint bus_watch_id; - // GtkWindow *window; + GtkWidget *vkb_widget; GList *windows; }; @@ -165,87 +166,92 @@ static void do_login(GtkButton *button, DiyaLoginShell *self) // g_application_quit(G_APPLICATION(self->app)); } -static void open_vkb(GtkButton *button, DiyaLoginShell *self) +static void show_vkb(GtkToggleButton *button, DiyaLoginShell *self) { - (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); - g_usleep(10000); - diya_virtual_keyboard_send_key(vkb, 30, VKB_KEY_STATE_RELEASED); - g_usleep(10000); + gtk_widget_set_visible(GTK_WIDGET(self->vkb_widget), gtk_toggle_button_get_active(button)); } 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)))); gtk_session_lock_instance_assign_window_to_monitor(self->lock, window, monitor); + gtk_widget_set_name(GTK_WIDGET(window), NAMESPACE); + + GtkWidget *grid = gtk_grid_new(); + gtk_window_set_child(window, grid); + gtk_grid_set_row_homogeneous(GTK_GRID(grid), false); GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_widget_set_halign(box, GTK_ALIGN_CENTER); gtk_widget_set_valign(box, GTK_ALIGN_CENTER); gtk_box_set_spacing(GTK_BOX(box), 10); + gtk_widget_set_hexpand(box, true); + gtk_widget_set_vexpand(box, true); + GtkWidget *label; label = gtk_label_new("Please login"); gtk_box_append(GTK_BOX(box), label); gtk_widget_add_css_class(label, "diya-login-header"); - GtkWidget *user_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_widget_set_valign(user_box, GTK_ALIGN_CENTER); - gtk_widget_set_halign(user_box, GTK_ALIGN_END); - gtk_box_set_spacing(GTK_BOX(user_box), 10); - + GtkWidget *child_grid = gtk_grid_new(); + gtk_grid_set_row_spacing(GTK_GRID(child_grid),10); + gtk_grid_set_column_spacing(GTK_GRID(child_grid),10); label = gtk_label_new("Username"); - gtk_box_append(GTK_BOX(user_box), label); + gtk_grid_attach(GTK_GRID(child_grid), label, 0, 0, 1, 1); self->username = gtk_entry_new(); - gtk_box_append(GTK_BOX(user_box), GTK_WIDGET(self->username)); - - gtk_box_append(GTK_BOX(box), user_box); - - GtkWidget *password_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_widget_set_valign(password_box, GTK_ALIGN_CENTER); - gtk_widget_set_halign(password_box, GTK_ALIGN_END); - gtk_box_set_spacing(GTK_BOX(password_box), 10); + gtk_grid_attach(GTK_GRID(child_grid), self->username, 1, 0, 1, 1); label = gtk_label_new("Password"); - gtk_box_append(GTK_BOX(password_box), label); + gtk_grid_attach(GTK_GRID(child_grid), label, 0, 1, 1, 1); self->password = gtk_password_entry_new(); - gtk_box_append(GTK_BOX(password_box), GTK_WIDGET(self->password)); + gtk_grid_attach(GTK_GRID(child_grid), self->password, 1, 1, 1, 1); - gtk_box_append(GTK_BOX(box), password_box); + gtk_box_append(GTK_BOX(box), child_grid); g_signal_connect(self->username, "activate", G_CALLBACK(do_login), self); g_signal_connect(self->password, "activate", G_CALLBACK(do_login), self); + child_grid = gtk_grid_new(); + gtk_grid_set_column_spacing(GTK_GRID(child_grid),2); + 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_box_append(GTK_BOX(box), button); - - // Not displayed, but allows testing that creating popups doesn't crash GTK + gtk_widget_set_can_focus(GTK_WIDGET(button), false); + gtk_grid_attach(GTK_GRID(child_grid), button, 0, 0, 1, 1); + // Not displayed, but allows testing that creating popups doesn't crash GTK gtk_widget_set_tooltip_text(button, "Login"); + gtk_widget_set_hexpand(button, true); + + button = gtk_toggle_button_new_with_label("⌨"); + gtk_widget_add_css_class(button, "diya-btn-show-vkb"); + gtk_grid_attach(GTK_GRID(child_grid), button, 1, 0, 1, 1); + gtk_box_append(GTK_BOX(box), child_grid); + gtk_widget_set_tooltip_text(button, "Show virtual keyboard"); + g_signal_connect (button, "toggled",G_CALLBACK (show_vkb),self); + gtk_widget_set_can_focus(GTK_WIDGET(button), false); self->status = gtk_label_new(NULL); gtk_box_append(GTK_BOX(box), self->status); gtk_widget_add_css_class(self->status, "diya-login-status"); - button = gtk_button_new_with_label("Show virtual keyboard"); - g_signal_connect(button, "clicked", G_CALLBACK(open_vkb), self); - gtk_widget_set_can_focus(GTK_WIDGET(button), false); - gtk_box_append(GTK_BOX(box), button); + gtk_grid_attach(GTK_GRID(grid), box, 0, 0, 1, 1); - 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)); + box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_valign(box, GTK_ALIGN_CENTER); + gtk_widget_set_halign(box, GTK_ALIGN_CENTER); + gtk_box_set_spacing(GTK_BOX(box), 10); - gtk_window_set_child(GTK_WINDOW(window), box); + self->vkb_widget = diya_virtual_keyboard_widget_new(diya_shell_get_virtual_keyboard(DIYA_SHELL(self), "fr")); + gtk_box_append(GTK_BOX(box), self->vkb_widget); + gtk_widget_set_visible(self->vkb_widget, false); + + gtk_grid_attach(GTK_GRID(grid), box, 0, 1, 1, 1); + gtk_widget_set_hexpand(box, true); + gtk_widget_set_vexpand(box, false); gtk_window_present(window); @@ -287,26 +293,6 @@ static void diya_login_shell_startup(DiyaShell *shell) g_object_unref(self); return; } - GError *err = NULL; - GBytes *bytes = g_resources_lookup_data("/dev/iohub/diya/shell/login-shell.css", 0, &err); - if (err != NULL) - { - g_critical("Unable to load CSS resource: %s", err->message); - g_error_free(err); - // continue without stylesheet - } - else - { - const char *data = g_bytes_get_data(bytes, NULL); - g_debug("CSS resource loaded:\n %s", data); - GtkCssProvider *provider = gtk_css_provider_new(); - gtk_css_provider_load_from_string(provider, data); - gtk_style_context_add_provider_for_display( - gdk_display_get_default(), - GTK_STYLE_PROVIDER(provider), - 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++) { diff --git a/src/login.c b/src/login.c index a9e3c9e..9739e64 100644 --- a/src/login.c +++ b/src/login.c @@ -3,33 +3,9 @@ #include "login-shell.h" -static gchar **g_shell_argv; - -static gboolean restart(gpointer d) -{ - (void)d; - gint i, fdlimit; - - fdlimit = (int)sysconf(_SC_OPEN_MAX); - g_debug("reload: closing fd's %d to %d", STDERR_FILENO + 1, fdlimit); - for (i = STDERR_FILENO + 1; i < fdlimit; i++) - { - fcntl(i, F_SETFD, FD_CLOEXEC); - } - g_debug("reload: exec: %s", g_shell_argv[0]); - execvp(g_shell_argv[0], g_shell_argv); - exit(1); - return FALSE; -} int main(int argc, char *argv[]) { - g_shell_argv = g_malloc0(sizeof(gchar *) * (argc + 1)); - for (int i = 0; i < argc; i++) - { - g_shell_argv[i] = argv[i]; - } - g_unix_signal_add(SIGHUP, (GSourceFunc)restart, NULL); DiyaLoginShell* shell = DIYA_LOGIN_SHELL(g_object_new(DIYA_TYPE_LOGIN_SHELL, "name", "dev.iohub.diya.login-shell", NULL)); return diya_shell_run(DIYA_SHELL(shell), argc, argv); } diff --git a/src/session-shell.c b/src/session-shell.c index 79d60cb..3149582 100644 --- a/src/session-shell.c +++ b/src/session-shell.c @@ -99,22 +99,12 @@ static void diya_session_shell_startup(DiyaShell* shell) { diya_session_shell_launcher_init(DIYA_SESSION_SHELL(shell)); diya_session_shell_init_background(DIYA_SESSION_SHELL(shell)); - - GtkCssProvider *provider = gtk_css_provider_new(); - const char *css = "#launcher {background-color: red;} #background {background-image:url(\"file:///etc/xdg/labwc/wpp.jpg\");background-size: cover;}"; - gtk_css_provider_load_from_string(provider, css); - gtk_style_context_add_provider_for_display( - gdk_display_get_default(), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_USER); - // g_signal_connect (win, "destroy", G_CALLBACK (before_destroy), provider); - g_object_unref(provider); - // CSS support - // set color for it - // g_timeout_add (100,(GSourceFunc )shell_timer,NULL); } static void diya_session_shell_active(DiyaShell* shell) { - diya_session_shell_lock(DIYA_SESSION_SHELL(shell)); + (void) shell; + // diya_session_shell_lock(DIYA_SESSION_SHELL(shell)); } static void diya_session_shell_class_init(DiyaSessionShellClass *class) diff --git a/src/session.c b/src/session.c index bee5f7e..67d143c 100644 --- a/src/session.c +++ b/src/session.c @@ -2,26 +2,6 @@ #include #include "session-shell.h" - -static gchar **g_shell_argv; - -static gboolean restart(gpointer d) -{ - (void)d; - gint i, fdlimit; - - fdlimit = (int)sysconf(_SC_OPEN_MAX); - g_debug("reload: closing fd's %d to %d", STDERR_FILENO + 1, fdlimit); - for (i = STDERR_FILENO + 1; i < fdlimit; i++) - { - fcntl(i, F_SETFD, FD_CLOEXEC); - } - g_debug("reload: exec: %s", g_shell_argv[0]); - execvp(g_shell_argv[0], g_shell_argv); - exit(1); - return FALSE; -} - static void session_locked(DiyaSessionShell* shell, void* data) { (void)data; @@ -38,12 +18,6 @@ static void session_unlocked(DiyaSessionShell* shell, void* data) int main(int argc, char *argv[]) { - g_shell_argv = g_malloc0(sizeof(gchar *) * (argc + 1)); - for (int i = 0; i < argc; i++) - { - g_shell_argv[i] = argv[i]; - } - g_unix_signal_add(SIGHUP, (GSourceFunc)restart, NULL); DiyaSessionShell *shell = DIYA_SESSION_SHELL(g_object_new(DIYA_TYPE_SESSION_SHELL, "name","dev.iohub.diya.session-shell", NULL)); g_signal_connect(shell, "session-locked", G_CALLBACK(session_locked), NULL); g_signal_connect(shell, "session-unlocked", G_CALLBACK(session_unlocked), NULL); diff --git a/src/shell.c b/src/shell.c index aa9416c..468b14d 100644 --- a/src/shell.c +++ b/src/shell.c @@ -19,8 +19,9 @@ typedef struct _DiyaShellPrivate DiyaObject parent; DiyaWayland * wayland; GtkApplication* app; - DiyaVirtualKeyboard* vkb; gchar* name; + GHashTable* vkbs; + GtkCssProvider* css_provider; } DiyaShellPrivate; G_DEFINE_TYPE_WITH_PRIVATE(DiyaShell, diya_shell, DIYA_TYPE_OBJECT); @@ -41,10 +42,11 @@ static void diya_shell_dispose(GObject* object) g_free(priv->name); priv->name = NULL; } - if(priv->vkb) + if(priv->css_provider) { - g_object_unref(priv->vkb); + g_object_unref(priv->css_provider); } + g_hash_table_destroy(priv->vkbs); G_OBJECT_CLASS(diya_shell_parent_class)->dispose(object); if (priv->app) { @@ -52,6 +54,62 @@ static void diya_shell_dispose(GObject* object) } } +static void diya_shell_reload(DiyaShell* shell) +{ + GError *err = NULL; + GBytes *bytes = NULL; + gchar* css_string = NULL; + DiyaShellPrivate* priv = diya_shell_get_instance_private(shell); + gchar* css_file = g_strconcat(g_get_user_config_dir(),"/diya/themes/",priv->name,".css", NULL); + g_debug("diya_shell_reload: Looking for css file: %s", css_file); + g_file_get_contents(css_file,&css_string, NULL, &err); + free(css_file); + if (err != NULL) + { + g_warning("diya_shell_reload: Unable to load CSS from file: %s", err->message); + g_error_free(err); + err = NULL; + g_debug("diya_shell_reload: Fallback to default theme"); + css_file = g_strconcat("/dev/iohub/diya/shell/",priv->name,".css", NULL); + bytes = g_resources_lookup_data(css_file, 0, &err); + free(css_file); + if (err != NULL) + { + g_critical("diya_shell_reload: Unable to load CSS from resource: %s", err->message); + g_error_free(err); + css_string = NULL; + } + else + { + css_string = (gchar*)g_bytes_get_data(bytes, NULL); + } + } + if(css_string) + { + if(priv->css_provider) + { + gtk_style_context_remove_provider_for_display(gdk_display_get_default(), GTK_STYLE_PROVIDER(priv->css_provider)); + priv->css_provider = NULL; + } + + g_debug("diya_shell_reload: Applying stylesheet:\n %s", css_string); + priv->css_provider = gtk_css_provider_new(); + gtk_css_provider_load_from_string(priv->css_provider, css_string); + gtk_style_context_add_provider_for_display( + gdk_display_get_default(), + GTK_STYLE_PROVIDER(priv->css_provider), + GTK_STYLE_PROVIDER_PRIORITY_USER); + if(!bytes) + { + free(css_string); + } + } + if(bytes) + { + g_bytes_unref(bytes); + } +} + static void on_gtk_app_startup(GtkApplication *app, void *data) { (void)app; @@ -59,6 +117,7 @@ static void on_gtk_app_startup(GtkApplication *app, void *data) DiyaShellPrivate* priv = diya_shell_get_instance_private(shell); priv->wayland =diya_wayland_new(DIYA_SHELL(shell)); DiyaShellClass* class = DIYA_SHELL_GET_CLASS(shell); + diya_shell_reload(shell); if(class->startup_handle) { class->startup_handle(shell); @@ -88,6 +147,19 @@ static gboolean diya_shell_sigint_handle(gpointer data) return true; } + +static gboolean diya_shell_sighub_handle(DiyaShell* self) +{ + // reload css file + diya_shell_reload(self); + DiyaShellClass* class = DIYA_SHELL_GET_CLASS(self); + if(class->reload_handle) + { + class->reload_handle(self); + } + return true; +} + static void init_gtk_application(DiyaShell* self) { DiyaShellPrivate* priv = diya_shell_get_instance_private(self); @@ -99,7 +171,7 @@ static void init_gtk_application(DiyaShell* self) g_signal_connect(priv->app, "startup", G_CALLBACK(on_gtk_app_startup), (void *)self); g_signal_connect(priv->app, "activate", G_CALLBACK(on_gtk_app_active), (void *)self); g_unix_signal_add(SIGINT,(GSourceFunc)diya_shell_sigint_handle,(void*)self); - // g_signal_connect(priv->app, "shutdown", G_CALLBACK(shutdown), (void*)shell); + g_unix_signal_add(SIGHUP, (GSourceFunc)diya_shell_sighub_handle, (void*)self); } static void diya_shell_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) @@ -151,7 +223,8 @@ static void diya_shell_init(DiyaShell *self) priv->wayland = NULL; priv->app = NULL; priv->name = NULL; - priv->vkb = NULL; + priv->vkbs = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_object_unref); + priv->css_provider = NULL; } DiyaWayland * diya_shell_get_wayland(DiyaShell* shell) @@ -194,6 +267,7 @@ static void diya_shell_class_init(DiyaShellClass *class) class->monitor_changed_handle = NULL; class->startup_handle = NULL; class->active_handle = NULL; + class->reload_handle = NULL; shell_properties[PROP_SHELL_WAYLAND] = g_param_spec_pointer("wayland", NULL, "Shell wayland", G_PARAM_READABLE); // shell_properties[PROP_SHELL_NAME] = g_param_spec_string("name", NULL, "Shell name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); @@ -202,21 +276,54 @@ 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); assert(GTK_IS_APPLICATION(priv->app)); - int status = g_application_run(G_APPLICATION(priv->app),argc,argv); - g_object_unref(priv->app); + GtkApplication* app = priv->app; + int status = g_application_run(G_APPLICATION(app),argc,argv); + g_object_unref(app); return status; +} + +DiyaVirtualKeyboard* diya_shell_get_virtual_keyboard(DiyaShell* shell, const gchar* name) +{ + DiyaVirtualKeyboard* vkb = NULL; + DiyaShellPrivate* priv = diya_shell_get_instance_private(shell); + if(name) + { + if(g_hash_table_contains(priv->vkbs, name)) + { + g_debug("diya_shell_get_virtual_keyboard: Getting keyboard %s from cache", name); + vkb = g_hash_table_lookup(priv->vkbs, name); + } + else + { + gchar* keymap_file = g_strconcat(g_get_user_config_dir(),"/diya/xkb/", name,".keymap", NULL); + g_debug("diya_shell_get_virtual_keyboard: Looking for keymap file: %s", keymap_file); + if(g_file_test(keymap_file, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK)) + { + vkb = diya_virtual_keyboard_new(shell, keymap_file); + if(vkb) + { + g_debug("diya_shell_get_virtual_keyboard: add new keyboard %s to cache", name); + g_hash_table_insert(priv->vkbs, (gpointer)name, vkb); + } + } + free(keymap_file); + } + } + + if(!vkb) + { + g_debug("Fallback to default virtual key board"); + if(!g_hash_table_contains(priv->vkbs, "default")) + { + g_debug("Add new keyboard instance to cache"); + g_hash_table_insert(priv->vkbs,"default", diya_virtual_keyboard_new(shell, NULL)); + } + vkb = g_hash_table_lookup(priv->vkbs, "default"); + } + + return vkb; } \ No newline at end of file diff --git a/src/shell.h b/src/shell.h index c6830bb..8ef40cc 100644 --- a/src/shell.h +++ b/src/shell.h @@ -26,13 +26,13 @@ struct _DiyaShellClass void (*monitor_changed_handle)(GListModel* /*list*/,guint /*position*/, guint /*removed*/,guint /*added*/, gpointer); void (*startup_handle)(DiyaShell*); void (*active_handle)(DiyaShell*); + void (*reload_handle)(DiyaShell*); }; 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); +DiyaVirtualKeyboard* diya_shell_get_virtual_keyboard(DiyaShell* shell, const gchar* name); int diya_shell_run(DiyaShell* shell, int argc, char **argv); #endif \ No newline at end of file diff --git a/src/vkb/virtual-keyboard-widgets.c b/src/vkb/virtual-keyboard-widgets.c index b044401..8068372 100644 --- a/src/vkb/virtual-keyboard-widgets.c +++ b/src/vkb/virtual-keyboard-widgets.c @@ -8,7 +8,8 @@ struct _DiyaVkbButton { GtkWidget super; GtkWidget *labels[3]; - DiyaVkbKey *key; + DiyaVkbKey *key; /*owned by the virtual keyboard*/ + gulong mod_sig_id; }; G_DEFINE_FINAL_TYPE(DiyaVkbButton, diya_vkb_button, GTK_TYPE_WIDGET); @@ -21,15 +22,21 @@ static void diya_vkb_button_dispose(GObject *object) { 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_event(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) +{ + (void) n_press; + (void) x; + (void) y; + const gchar* evt_name = (gchar*) data; + GtkEventController *controller = GTK_EVENT_CONTROLLER(gesture); + DiyaVkbButton *self = DIYA_VKB_BUTTON(gtk_event_controller_get_widget(controller)); + g_signal_emit_by_name(self, evt_name); +} + static void diya_vkb_button_init(DiyaVkbButton *self) { gchar class_name[32]; /*diya-vkb-btn-level-%d */ @@ -38,13 +45,12 @@ static void diya_vkb_button_init(DiyaVkbButton *self) 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); + g_snprintf(class_name, sizeof(class_name), "shift-level-%d", i + 1); gtk_widget_add_css_class(self->labels[i], class_name); gtk_widget_set_hexpand(self->labels[i], true); @@ -73,32 +79,53 @@ static void diya_vkb_button_init(DiyaVkbButton *self) break; } } + // event handle + GtkGesture *controller = gtk_gesture_click_new(); + g_signal_connect(controller, "pressed", G_CALLBACK(diya_vkb_button_event), "pressed"); + g_signal_connect(controller, "released", G_CALLBACK(diya_vkb_button_event), "released"); + gtk_widget_add_controller(GTK_WIDGET(self), GTK_EVENT_CONTROLLER(controller)); } 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_css_name(GTK_WIDGET_CLASS(class), "diya-vkb-button"); gtk_widget_class_set_layout_manager_type(GTK_WIDGET_CLASS(class), GTK_TYPE_GRID_LAYOUT); } +void diya_vkb_button_set_key(DiyaVkbButton* btn, DiyaVkbKey *key) +{ + btn->key = key; + for (uint32_t i = 0; i < 3; i++) + { + if(key) + { + 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); + } + } + else + { + gtk_label_set_text(GTK_LABEL(btn->labels[i]), NULL); + } + } +} + 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++) + if(key) { - 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); - } + diya_vkb_button_set_key(btn, key); } + btn->mod_sig_id = 0; return btn; } @@ -115,7 +142,7 @@ 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, + 50, 94, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 111, 66, 9, 206, 64, 65, 0, 108, 113, 116, 114}; struct _DiyaVirtualKeyboardWidget @@ -129,7 +156,7 @@ struct _DiyaVirtualKeyboardWidget * row 4: 54 - 62 */ GList *buttons; - DiyaVirtualKeyboard *vkb; + DiyaVirtualKeyboard *vkb; /*owned by the widget itself*/ }; G_DEFINE_FINAL_TYPE(DiyaVirtualKeyboardWidget, diya_virtual_keyboard_widget, GTK_TYPE_WIDGET); @@ -149,15 +176,18 @@ static void diya_virtual_keyboard_widget_dispose(GObject *object) } } } + /* if(self->vkb) + { + g_object_unref(self->vkb); + } */ // 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); + // 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); @@ -171,17 +201,100 @@ static void diya_virtual_keyboard_widget_class_init(DiyaVirtualKeyboardWidgetCla { GObjectClass *gobject_class = G_OBJECT_CLASS(class); gobject_class->dispose = diya_virtual_keyboard_widget_dispose; - + gtk_widget_class_set_css_name(GTK_WIDGET_CLASS(class), "diya-vkb"); gtk_widget_class_set_layout_manager_type(GTK_WIDGET_CLASS(class), GTK_TYPE_GRID_LAYOUT); + g_signal_new("pressed", + DIYA_TYPE_VKB_BUTTON, + G_SIGNAL_DETAILED | + G_SIGNAL_ACTION | + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0, + NULL); + g_signal_new("released", + DIYA_TYPE_VKB_BUTTON, + G_SIGNAL_DETAILED | + G_SIGNAL_ACTION | + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0, + NULL); } -DiyaVirtualKeyboardWidget *diya_virtual_keyboard_widget_new(DiyaVirtualKeyboard *kb) +static void diya_vkb_widget_on_key_pressed(DiyaVkbButton* button, DiyaVirtualKeyboardWidget* self) +{ + gtk_widget_add_css_class(GTK_WIDGET(button), "active"); + diya_virtual_keyboard_send_key(self->vkb, button->key,VKB_KEY_STATE_PRESSED); +} + +static void diya_vkb_widget_on_key_released(DiyaVkbButton* button, DiyaVirtualKeyboardWidget* self) +{ + if(!diya_vkb_key_is_modifier(button->key)) + { + gtk_widget_remove_css_class(GTK_WIDGET(button), "active"); + } + diya_virtual_keyboard_send_key(self->vkb, button->key,VKB_KEY_STATE_RELEASED); +} + +static void on_kb_modifier_changed(DiyaVirtualKeyboard* kb, DiyaVkbButton* button) +{ + if(!diya_virtual_keyboard_key_modifier_is_active(kb, button->key)) + { + gtk_widget_remove_css_class(GTK_WIDGET(button), "active"); + } +} + +void diya_virtual_keyboard_widget_set_keyboard(DiyaVirtualKeyboardWidget* self, DiyaVirtualKeyboard* keyboard) +{ + self->vkb = keyboard; + int index = 0; + if (self->buttons) + { + GList *it = NULL; + for (it = self->buttons; it; it = it->next) + { + if (it->data) + { + DiyaVkbButton* button = it->data; + DiyaVkbKey *key = NULL; + if(button->mod_sig_id > 0) + { + g_signal_handler_disconnect(self->vkb,button->mod_sig_id); + button->mod_sig_id = 0; + } + if(keyboard) + { + key = diya_virtual_keyboard_get_key(self->vkb, g_vkb_layout[index]); + g_debug("set button key: %s", diya_object_to_string(key)); + if(diya_vkb_key_is_modifier(key)) + { + button->mod_sig_id = g_signal_connect(self->vkb, "modifier-changed", G_CALLBACK(on_kb_modifier_changed), button); + } + } + diya_vkb_button_set_key(button, key); + index++; + } + } + } +} + +GtkWidget *diya_virtual_keyboard_widget_new(DiyaVirtualKeyboard* keyboard) { 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; + self->vkb = keyboard; + if(self->vkb == NULL) + { + return NULL; + } for (int i = 0; i < VKB_N_CELLS; i++) { gboolean skip = false; @@ -199,7 +312,7 @@ DiyaVirtualKeyboardWidget *diya_virtual_keyboard_widget_new(DiyaVirtualKeyboard 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); + skip = (col > 0 && col < 3) || (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); @@ -212,15 +325,16 @@ DiyaVirtualKeyboardWidget *diya_virtual_keyboard_widget_new(DiyaVirtualKeyboard { 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)); + + GtkWidget *button = GTK_WIDGET(diya_vkb_button_new(NULL)); 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)); + g_signal_connect(button, "pressed", G_CALLBACK(diya_vkb_widget_on_key_pressed),self); + g_signal_connect(button, "released", G_CALLBACK(diya_vkb_widget_on_key_released),self); + gtk_grid_layout_child_set_row(grid_child, row); gtk_grid_layout_child_set_column(grid_child, col); @@ -229,6 +343,7 @@ DiyaVirtualKeyboardWidget *diya_virtual_keyboard_widget_new(DiyaVirtualKeyboard case 26: case 29: case 58: + case 87: case 116: gtk_grid_layout_child_set_column_span(grid_child, 3); break; @@ -236,8 +351,8 @@ DiyaVirtualKeyboardWidget *diya_virtual_keyboard_widget_new(DiyaVirtualKeyboard 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); + /* 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); @@ -249,5 +364,9 @@ DiyaVirtualKeyboardWidget *diya_virtual_keyboard_widget_new(DiyaVirtualKeyboard break; } } - return self; + if(keyboard) + { + diya_virtual_keyboard_widget_set_keyboard(self, keyboard); + } + return GTK_WIDGET(self); } diff --git a/src/vkb/virtual-keyboard-widgets.h b/src/vkb/virtual-keyboard-widgets.h index 805704c..e2e0b0b 100644 --- a/src/vkb/virtual-keyboard-widgets.h +++ b/src/vkb/virtual-keyboard-widgets.h @@ -7,12 +7,14 @@ #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(); +GtkWidget* diya_virtual_keyboard_widget_new(DiyaVirtualKeyboard* keyboard); +void diya_virtual_keyboard_widget_set_keyboard(DiyaVirtualKeyboardWidget* widget, DiyaVirtualKeyboard* keyboard); #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); +void diya_vkb_button_set_key(DiyaVkbButton* btn, DiyaVkbKey *key); #endif \ No newline at end of file diff --git a/src/vkb/virtual-keyboard.c b/src/vkb/virtual-keyboard.c index 06b97bf..0a6e70d 100644 --- a/src/vkb/virtual-keyboard.c +++ b/src/vkb/virtual-keyboard.c @@ -13,6 +13,18 @@ #include "virtual-keyboard.h" #include "wayland.h" +typedef enum +{ + DIYA_VKB_KEY_MOD_NONE = 0, + DIYA_VKB_KEY_MOD_SHIFT = 1, + DIYA_VKB_KEY_MOD_CAPS_LOCK = 2, + DIYA_VKB_KEY_MOD_CTRL = 4, + DIYA_VKB_KEY_MOD_ALT = 8, + DIYA_VKB_KEY_MOD_SUPER = 64, + DIYA_VKB_KEY_MOD_ALT_GR = 128, +} diya_vkb_key_modifier_t; + + struct _DiyaVkbKey { DiyaObject parent; @@ -20,6 +32,7 @@ struct _DiyaVkbKey gchar *key_caps[3]; uint32_t syms[3]; gchar *info; + diya_vkb_key_modifier_t mode; }; G_DEFINE_FINAL_TYPE(DiyaVkbKey, diya_vkb_key, DIYA_TYPE_OBJECT) @@ -49,6 +62,7 @@ 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->mode = DIYA_VKB_KEY_MOD_NONE; self->info = NULL; } @@ -80,6 +94,19 @@ static void diya_vkb_key_class_init(DiyaVkbKeyClass *class) // 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; + + g_signal_new("modifier-changed", + DIYA_TYPE_VIRTUAL_KEYBOARD, + G_SIGNAL_DETAILED | + G_SIGNAL_ACTION | + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0, + NULL); } const gchar *diya_vkb_key_get_keycap(DiyaVkbKey *key, uint32_t shift_level) @@ -91,16 +118,21 @@ const gchar *diya_vkb_key_get_keycap(DiyaVkbKey *key, uint32_t shift_level) return key->key_caps[shift_level]; } -uint32_t diya_vkb_key_get_code(DiyaVkbKey *key) + + +/*uint32_t diya_vkb_key_get_code(DiyaVkbKey *key) { - return key->code; + return key->code - 8; +}*/ + +gboolean diya_vkb_key_is_alphabet(DiyaVkbKey* self) +{ + return (self->syms[0] >= XKB_KEY_a && self->code <= XKB_KEY_Z); } -uint32_t diya_vkb_key_is_alphabet(DiyaVkbKey* self) +gboolean diya_vkb_key_is_modifier(DiyaVkbKey* self) { - return (self->code >= 24 && self->code <= 33) || - (self->code >= 38 && self->code <= 46) || - (self->code >= 52 && self->code <= 58); + return self->mode != DIYA_VKB_KEY_MOD_NONE; } /** @@ -116,6 +148,8 @@ struct _DiyaVirtualKeyboard struct zwp_virtual_keyboard_v1 *keyboard; struct xkb_context *vkb_ctx; struct xkb_keymap *vkb_keymap; + GHashTable * keys; + guint32 key_mods; }; G_DEFINE_FINAL_TYPE(DiyaVirtualKeyboard, diya_virtual_keyboard, DIYA_TYPE_SHELL_OBJECT); @@ -123,18 +157,22 @@ G_DEFINE_FINAL_TYPE(DiyaVirtualKeyboard, diya_virtual_keyboard, DIYA_TYPE_SHELL_ 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_debug("diya_virtual_keyboard_dispose: %s", diya_object_to_string(object)); + g_hash_table_destroy(self->keys); if (self->vkb_keymap) { xkb_keymap_unref(self->vkb_keymap); + self->vkb_keymap = NULL; } if (self->vkb_ctx) { xkb_context_unref(self->vkb_ctx); + self->vkb_ctx = NULL; + } + if (self->keyboard) + { + zwp_virtual_keyboard_v1_destroy(self->keyboard); + self->keyboard = NULL; } G_OBJECT_CLASS(diya_virtual_keyboard_parent_class)->dispose(object); } @@ -144,12 +182,18 @@ static void diya_virtual_keyboard_init(DiyaVirtualKeyboard *self) self->keyboard = NULL; self->vkb_ctx = NULL; self->vkb_keymap = NULL; + self->keys = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref); + self->key_mods = 0; } static const gchar *diya_virtual_keyboard_to_string(DiyaObject *object) { - (void)object; - return "Diya virtual keyboard instance"; + DiyaVirtualKeyboard* self = DIYA_VIRTUAL_KEYBOARD(object); + if(self->vkb_keymap) + { + return xkb_keymap_layout_get_name(self->vkb_keymap,0); + } + return NULL; } static void diya_virtual_keyboard_class_init(DiyaVirtualKeyboardClass *class) @@ -291,8 +335,8 @@ DiyaVirtualKeyboard *diya_virtual_keyboard_new(DiyaShell *shell, const gchar *ke 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); + xkb_context_unref(vkb_ctx); return NULL; } @@ -300,8 +344,9 @@ DiyaVirtualKeyboard *diya_virtual_keyboard_new(DiyaShell *shell, const gchar *ke if (fd == -1) { g_critical("diya_virtual_keyboard_new: create temp file"); - xkb_context_unref(vkb_ctx); xkb_keymap_unref(vkb_keymap); + xkb_context_unref(vkb_ctx); + free(content); return NULL; } @@ -309,9 +354,10 @@ DiyaVirtualKeyboard *diya_virtual_keyboard_new(DiyaShell *shell, const gchar *ke 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); + xkb_context_unref(vkb_ctx); close(fd); + free(content); return NULL; } // g_debug("Using keymap configuration: \n%s", content); @@ -335,18 +381,58 @@ void diya_virtual_keyboard_register(struct wl_registry *registry, uint32_t name, 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) +void diya_virtual_keyboard_send_key(DiyaVirtualKeyboard *self, DiyaVkbKey* key, diya_vkb_state_t state) { + guint32 old_mods = self->key_mods; 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); + zwp_virtual_keyboard_v1_key(self->keyboard, current_time_ms, key->code - 8, (uint32_t)state); + switch (state) + { + case VKB_KEY_STATE_PRESSED: + switch (key->mode) + { + case DIYA_VKB_KEY_MOD_NONE: + break; + case DIYA_VKB_KEY_MOD_CAPS_LOCK: + self->key_mods = (self->key_mods & DIYA_VKB_KEY_MOD_CAPS_LOCK) ^ key->mode; + zwp_virtual_keyboard_v1_modifiers(self->keyboard,0,0,self->key_mods,0); + break; + default: + self->key_mods ^= key->mode; + zwp_virtual_keyboard_v1_modifiers(self->keyboard,0,self->key_mods,0,0); + break; + } + break; + + case VKB_KEY_STATE_RELEASED: + switch (key->mode) + { + case DIYA_VKB_KEY_MOD_NONE: + if(self->key_mods) + { + self->key_mods = self->key_mods & DIYA_VKB_KEY_MOD_CAPS_LOCK; + zwp_virtual_keyboard_v1_modifiers(self->keyboard,0,0,self->key_mods,0); + } + break; + default: + break; + } + break; + } + if(old_mods != self->key_mods) + { + g_signal_emit_by_name(self,"modifier-changed", NULL); + } } -gchar *diya_virtual_keyboard_get_keycap(const xkb_keysym_t *sym) +void diya_virtual_keyboard_init_level(DiyaVkbKey* key, const xkb_keysym_t sym, int level) { char buf[32]; - switch (*sym) + key->syms[level] = sym; + diya_vkb_key_modifier_t mod = DIYA_VKB_KEY_MOD_NONE; + switch (sym) { case XKB_KEY_Escape: g_snprintf(buf, sizeof(buf), "%s", "Esc"); @@ -362,19 +448,24 @@ gchar *diya_virtual_keyboard_get_keycap(const xkb_keysym_t *sym) break; case XKB_KEY_Control_L: g_snprintf(buf, sizeof(buf), "%s", "Ctrl"); + mod = DIYA_VKB_KEY_MOD_CTRL; break; case XKB_KEY_Shift_L: g_snprintf(buf, sizeof(buf), "%s", "⇧"); + mod = DIYA_VKB_KEY_MOD_SHIFT; break; case XKB_KEY_Caps_Lock: g_snprintf(buf, sizeof(buf), "%s", "⇪"); + mod = DIYA_VKB_KEY_MOD_CAPS_LOCK; break; case XKB_KEY_Alt_L: g_snprintf(buf, sizeof(buf), "%s", "⎇"); + mod = DIYA_VKB_KEY_MOD_ALT; break; case XKB_KEY_Alt_R: case XKB_KEY_ISO_Level3_Shift: g_snprintf(buf, sizeof(buf), "%s", "⇮"); + mod = DIYA_VKB_KEY_MOD_ALT_GR; break; case XKB_KEY_space: g_snprintf(buf, sizeof(buf), "%s", "⎵"); @@ -398,7 +489,13 @@ gchar *diya_virtual_keyboard_get_keycap(const xkb_keysym_t *sym) g_snprintf(buf, sizeof(buf), "%s", "⌘"); break; case XKB_KEY_Super_L: - g_snprintf(buf, sizeof(buf), "%s", "●"); + g_snprintf(buf, sizeof(buf), "%s", "●"); + if(level != 0) + { + key->syms[0] = sym; + key->syms[level] = 0; + } + mod = DIYA_VKB_KEY_MOD_SUPER; break; case XKB_KEY_dead_circumflex: g_snprintf(buf, sizeof(buf), "%s", "^"); @@ -407,34 +504,58 @@ gchar *diya_virtual_keyboard_get_keycap(const xkb_keysym_t *sym) g_snprintf(buf, sizeof(buf), "%s", "¨"); break; default: - if (xkb_keysym_to_utf8(*sym, buf, sizeof(buf)) == 0) + if (xkb_keysym_to_utf8(sym, buf, sizeof(buf)) == 0) { - return NULL; + return; } break; } - return g_strdup(buf); + if(level == 0) + { + key->mode = mod; + } + if(sym == XKB_KEY_Super_L && level != 0) + { + if(key->key_caps[0]) + { + free(key->key_caps[0]); + } + key->key_caps[0] = g_strdup(buf); + } + else + { + key->key_caps[level] = 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) + if(!g_hash_table_contains(self->keys, GUINT_TO_POINTER(code))) { - n_level = n_level > 3 ? 3 : n_level; - for (int level = 0; level < n_level; level++) + 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) { - 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]) + n_level = n_level > 3 ? 3 : n_level; + for (int level = 0; level < n_level; level++) { - continue; + 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; + } + diya_virtual_keyboard_init_level(key, syms[0],level); } - key->syms[level] = syms[0]; - key->key_caps[level] = diya_virtual_keyboard_get_keycap(&syms[0]); } + g_hash_table_insert(self->keys, GUINT_TO_POINTER(code), key); } - return key; + + return g_hash_table_lookup(self->keys, GUINT_TO_POINTER(code)); +} + +gboolean diya_virtual_keyboard_key_modifier_is_active(DiyaVirtualKeyboard* vkb, DiyaVkbKey* key) +{ + return (key->mode & vkb->key_mods) > 0; } \ No newline at end of file diff --git a/src/vkb/virtual-keyboard.h b/src/vkb/virtual-keyboard.h index 52878a9..c3e8b12 100644 --- a/src/vkb/virtual-keyboard.h +++ b/src/vkb/virtual-keyboard.h @@ -12,14 +12,14 @@ typedef enum #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); - +gboolean diya_vkb_key_is_alphabet(DiyaVkbKey* key); +gboolean diya_vkb_key_is_modifier(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); +void diya_virtual_keyboard_send_key(DiyaVirtualKeyboard* vkb, DiyaVkbKey* key, diya_vkb_state_t state); DiyaVkbKey* diya_virtual_keyboard_get_key(DiyaVirtualKeyboard* vkb, uint32_t key); +gboolean diya_virtual_keyboard_key_modifier_is_active(DiyaVirtualKeyboard* vkb, DiyaVkbKey* key); #endif \ No newline at end of file