diff --git a/README.md b/README.md index 2beb667c..8ccb13ba 100644 --- a/README.md +++ b/README.md @@ -30,29 +30,42 @@ Building ### Dependencies -See `.gitlab-ci.yml`. +See `.gitlab-ci.yml` or run `apt-get build-dep .` ### Build from git repo -``` +```bash $ git clone https://source.puri.sm/Librem5/squeekboard.git $ cd squeekboard -$ mkdir ../build -$ meson ../build/ -$ cd ../build -$ ninja test -$ ninja install +$ mkdir _build +$ meson _build/ +$ cd _build +$ ninja ``` +To run tests use `ninja test`. To install squeekboard run `ninja install`. + Running ------- -``` +```bash $ phoc # if no compatible Wayland compositor is running yet $ cd ../build/ $ src/squeekboard ``` +Squeekboard honors the gnome "screen-keyboard-enabled" setting. Either enable this through gnome-settings under accessibility or run: + +```bash +$ gsettings set org.gnome.desktop.a11y.applications screen-keyboard-enabled true +``` + +To make the keyboard show you can use either an application that does so automatically, like a text editor or `python3 ./tests/entry.py`, or you can manually trigger it with: + +```bash +busctl call --user sm.puri.OSK0 /sm/puri/OSK0 sm.puri.OSK0 SetVisible b true +``` + Developing ---------- diff --git a/data/keyboards/be.yaml b/data/keyboards/be.yaml new file mode 100644 index 00000000..ab43116f --- /dev/null +++ b/data/keyboards/be.yaml @@ -0,0 +1,89 @@ +--- +outlines: + default: { width: 35.33, height: 52 } + altline: { width: 52.67, height: 52 } + wide: { width: 59, height: 52 } + spaceline: { width: 140, height: 52 } + special: { width: 44, height: 52 } + +views: + base: + - "a z e r t y u i o p" + - "q s d f g h j k l m" + - "Shift_L w x c v b n . BackSpace" + - "show_numbers preferences space show_eschars Return" + upper: + - "A Z E R T Y U I O P" + - "Q S D F G H J K L M" + - "Shift_L W X C V B N , BackSpace" + - "show_numbers preferences space show_eschars Return" + numbers: + - "1 2 3 4 5 6 7 8 9 0" + - "@ # € % & - _ + ( )" + - "show_symbols , \" ' colon ; ! ? BackSpace" + - "show_letters preferences space show_eschars Return" + symbols: + - "~ ` | · √ π τ ÷ × ¶" + - "© ® £ $ ¥ ^ ° * { }" + - "show_numbers_from_symbols \\ / < > = [ ] BackSpace" + - "show_letters preferences space show_eschars Return" + eschars: + - "à â ç é è ê î ô ù û" + - "À Â Ç É È Ê Î Ô Ù Û" + - "show_numbers_from_symbols æ œ ä ë ï ö ü BackSpace" + - "show_letters preferences space show_eschars Return" + +buttons: + Shift_L: + action: + locking: + lock_view: "upper" + unlock_view: "base" + outline: "altline" + icon: "key-shift" + BackSpace: + outline: "altline" + icon: "edit-clear-symbolic" + action: erase + preferences: + action: "show_prefs" + outline: "special" + icon: "keyboard-mode-symbolic" + show_numbers: + action: + set_view: "numbers" + outline: "wide" + label: "123" + show_numbers_from_symbols: + action: + set_view: "numbers" + outline: "altline" + label: "123" + show_letters: + action: + set_view: "base" + outline: "wide" + label: "abc" + show_symbols: + action: + set_view: "symbols" + outline: "altline" + label: "*/=" + show_eschars: + action: + locking: + lock_view: "eschars" + unlock_view: "base" + outline: "altline" + label: "âÂ" + space: + outline: "spaceline" + text: " " + Return: + outline: "wide" + icon: "key-enter" + keysym: "Return" + colon: + text: ":" + "\"": + keysym: "quotedbl" diff --git a/doc/hacking.md b/doc/hacking.md index 551b701b..d8c37811 100644 --- a/doc/hacking.md +++ b/doc/hacking.md @@ -13,16 +13,16 @@ The overarching principle of *squeekboard* is to empower users. Software is primarily meant to solve problems of its users. Often in the quest to make software better, a hard distinction is made between the developer, who becomes the creator, and the user, who takes the role of the consumer, without direct influence on the software they use. This project aims to give users the power to make the software work for them by blurring the lines between users and developers. -Nonwithstanding its current state, *squeekboard* must be structured in a way that provides users a gradual way to gain more experience and power to adjust it. It must be easy, in order of importance: +Notwithstanding its current state, *squeekboard* must be structured in a way that provides users a gradual way to gain more experience and power to adjust it. It must be easy, in order of importance: - to use the software, - to modify its resources, -- to change its behaviour, +- to change its behavior, - to contribute upstream. To give an idea of what it means in practice, those are some examples of what has been important for *squeekboard* so far: -- being quick and useable, +- being quick and usable, - allowing local overrides of resources and config, - storing resources and config as editable, standard files, - having complete, up to date documentation of interfaces, @@ -33,7 +33,7 @@ To give an idea of what it means in practice, those are some examples of what ha - having code that is [simple and obvious](https://www.python.org/dev/peps/pep-0020/), - having an easy process of testing and accepting contributions. -You may notice that they are ordered roughly from "user-focused" to "maintainer-focused". While good properties are desired, sometimes they conflict, and maintainers should give additional weight to those benefitting the user compared to those benefitting regular contributors. +You may notice that they are ordered roughly from "user-focused" to "maintainer-focused". While good properties are desired, sometimes they conflict, and maintainers should give additional weight to those benefiting the user compared to those benefiting regular contributors. Sending patches --------------- @@ -43,7 +43,7 @@ By submitting a change to this project, you agree to license it under the [GPL l Development environment ----------------------- -*Squeekboard* is regularly built and tested on [the develpment environment](https://developer.puri.sm/Librem5/Development_Environment.html). +*Squeekboard* is regularly built and tested on [the development environment](https://developer.puri.sm/Librem5/Development_Environment.html). Recent Fedora releases are likely to be tested as well. @@ -162,7 +162,7 @@ Maintenance Squeekboard uses Rust & Cargo for some of its dependencies. -Use the `cargo.sh` script for maintaining the Cargo part of the build. The script takes the usual Cargo commands, after the first 2 positionsl arguments: source directory, and output artifact. So, `cargo test` becomes: +Use the `cargo.sh` script for maintaining the Cargo part of the build. The script takes the usual Cargo commands, after the first 2 positional arguments: source directory, and output artifact. So, `cargo test` becomes: ``` cd build_dir diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index 9b839b10..3a477668 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -360,6 +360,10 @@ eek_gtk_keyboard_init (EekGtkKeyboard *self) priv->event = lfb_event_new ("button-pressed"); else g_warning ("Failed to init libfeedback: %s", err->message); + + GtkIconTheme *theme = gtk_icon_theme_get_default (); + + gtk_icon_theme_add_resource_path (theme, "/sm/puri/squeekboard/icons"); } static void diff --git a/eek/eek-keyboard.c b/eek/eek-keyboard.c index 11cc8afa..9e60f587 100644 --- a/eek/eek-keyboard.c +++ b/eek/eek-keyboard.c @@ -51,8 +51,9 @@ struct KeyMap eek_key_map_from_str(char *keymap_str) { g_error("Bad keymap:\n%s", keymap_str); xkb_context_unref(context); - keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1); - size_t keymap_len = strlen(keymap_str) + 1; + + char *xkb_keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1); + size_t keymap_len = strlen(xkb_keymap_str) + 1; g_autofree char *path = strdup("/eek_keymap-XXXXXX"); char *r = &path[strlen(path) - 6]; @@ -76,9 +77,9 @@ struct KeyMap eek_key_map_from_str(char *keymap_str) { if ((void*)ptr == (void*)-1) { g_error("Failed to set up mmap"); } - strncpy(ptr, keymap_str, keymap_len); + strncpy(ptr, xkb_keymap_str, keymap_len); munmap(ptr, keymap_len); - free(keymap_str); + free(xkb_keymap_str); xkb_keymap_unref(keymap); struct KeyMap km = { .fd = keymap_fd, diff --git a/eek/eek-renderer.c b/eek/eek-renderer.c index 8e62c560..143c553e 100644 --- a/eek/eek-renderer.c +++ b/eek/eek-renderer.c @@ -265,10 +265,6 @@ renderer_init (EekRenderer *self) self->allocation_height = 0.0; self->scale_factor = 1; - GtkIconTheme *theme = gtk_icon_theme_get_default (); - - gtk_icon_theme_add_resource_path (theme, "/sm/puri/squeekboard/icons"); - self->css_provider = squeek_load_style(); } diff --git a/src/data.rs b/src/data.rs index 3157849f..010257ee 100644 --- a/src/data.rs +++ b/src/data.rs @@ -743,8 +743,7 @@ fn extract_symbol_names<'a>(actions: &'a [(&str, action::Action)]) #[cfg(test)] mod tests { use super::*; - - use std::error::Error as ErrorTrait; + use ::logging::ProblemPanic; const THIS_FILE: &str = file!(); @@ -792,7 +791,8 @@ mod tests { Err(e) => { let mut handled = false; if let Error::Yaml(ye) = &e { - handled = ye.description() == "missing field `views`"; + handled = ye.to_string() + .starts_with("missing field `views`"); }; if !handled { println!("Unexpected error {:?}", e); @@ -810,7 +810,7 @@ mod tests { Err(e) => { let mut handled = false; if let Error::Yaml(ye) = &e { - handled = ye.description() + handled = ye.to_string() .starts_with("unknown field `bad_field`"); }; if !handled { diff --git a/src/locale_config.rs b/src/locale_config.rs index 0595f2b7..959dfde1 100644 --- a/src/locale_config.rs +++ b/src/locale_config.rs @@ -31,22 +31,16 @@ pub enum Error { impl ::std::fmt::Display for Error { fn fmt(&self, out: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - use ::std::error::Error; - out.write_str(self.description()) - } -} - -impl ::std::error::Error for Error { - fn description(&self) -> &str { - match self { + out.write_str(match self { &Error::NotWellFormed => "Language tag is not well-formed.", // this is exception: here we do want exhaustive match so we don't publish version with // missing descriptions by mistake. &Error::__NonExhaustive => panic!("Placeholder error must not be instantiated!"), - } + }) } } + /// Convenience Result alias. type Result = ::std::result::Result; diff --git a/src/resources.rs b/src/resources.rs index 67a2af00..ed446e55 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -17,6 +17,7 @@ const KEYBOARDS: &[(*const str, *const str)] = &[ ("us_wide", include_str!("../data/keyboards/us_wide.yaml")), ("br", include_str!("../data/keyboards/br.yaml")), ("de", include_str!("../data/keyboards/de.yaml")), + ("be", include_str!("../data/keyboards/be.yaml")), ("de_wide", include_str!("../data/keyboards/de_wide.yaml")), ("dk", include_str!("../data/keyboards/dk.yaml")), ("es", include_str!("../data/keyboards/es.yaml")), diff --git a/src/server-context-service.c b/src/server-context-service.c index ded432ef..515caf6e 100644 --- a/src/server-context-service.c +++ b/src/server-context-service.c @@ -31,6 +31,7 @@ enum { PROP_0, PROP_VISIBLE, + PROP_ENABLED, PROP_LAST }; @@ -44,6 +45,7 @@ struct _ServerContextService { struct ui_manager *manager; // unowned gboolean visible; + gboolean enabled; PhoshLayerSurface *window; GtkWidget *widget; // nullable guint hiding; @@ -208,6 +210,9 @@ on_hide (ServerContextService *self) static void server_context_service_real_show_keyboard (ServerContextService *self) { + if (!self->enabled) + return; + if (self->hiding) { g_source_remove (self->hiding); self->hiding = 0; @@ -263,7 +268,9 @@ server_context_service_set_property (GObject *object, case PROP_VISIBLE: self->visible = g_value_get_boolean (value); break; - + case PROP_ENABLED: + server_context_service_set_enabled (self, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -319,11 +326,43 @@ server_context_service_class_init (ServerContextServiceClass *klass) g_object_class_install_property (gobject_class, PROP_VISIBLE, pspec); + + /** + * ServerContextServie:keyboard: + * + * Does the user want the keyboard to show up automatically? + */ + pspec = + g_param_spec_boolean ("enabled", + "Enabled", + "Whether the keyboard is enabled", + TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (gobject_class, + PROP_ENABLED, + pspec); } static void server_context_service_init (ServerContextService *self) { - (void)self; + const char *schema_name = "org.gnome.desktop.a11y.applications"; + GSettingsSchemaSource *ssrc = g_settings_schema_source_get_default(); + g_autoptr(GSettingsSchema) schema = NULL; + + self->enabled = TRUE; + if (!ssrc) { + g_warning("No gsettings schemas installed."); + return; + } + schema = g_settings_schema_source_lookup(ssrc, schema_name, TRUE); + if (schema) { + g_autoptr(GSettings) settings = g_settings_new (schema_name); + g_settings_bind (settings, "screen-keyboard-enabled", + self, "enabled", G_SETTINGS_BIND_GET); + } else { + g_warning("Gsettings schema %s is not installed on the system. " + "Enabling by default.", schema_name); + } } ServerContextService * @@ -336,3 +375,18 @@ server_context_service_new (EekboardContextService *self, struct submission *sub ui->manager = uiman; return ui; } + +void +server_context_service_set_enabled (ServerContextService *self, gboolean enabled) +{ + g_return_if_fail (SERVER_IS_CONTEXT_SERVICE (self)); + + if (enabled == self->enabled) + return; + + self->enabled = enabled; + if (self->enabled) + server_context_service_show_keyboard (self); + else + server_context_service_hide_keyboard (self); +} diff --git a/src/server-context-service.h b/src/server-context-service.h index bafe71c3..a091d0f9 100644 --- a/src/server-context-service.h +++ b/src/server-context-service.h @@ -33,6 +33,7 @@ ServerContextService *server_context_service_new(EekboardContextService *self, s enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *); void server_context_service_show_keyboard (ServerContextService *self); void server_context_service_hide_keyboard (ServerContextService *self); +void server_context_service_set_enabled (ServerContextService *self, gboolean enabled); G_END_DECLS #endif /* SERVER_CONTEXT_SERVICE_H */ diff --git a/tests/meson.build b/tests/meson.build index 93ecefcc..f8950b64 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -50,6 +50,7 @@ endforeach foreach layout : [ 'us', 'us_wide', 'br', + 'be', 'de', 'de_wide', 'dk', 'es',