Skip to content

Commit

Permalink
add more keyboard functionalities
Browse files Browse the repository at this point in the history
  • Loading branch information
takotori committed Jun 6, 2024
1 parent 2546ec6 commit 52a1fca
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 37 deletions.
Binary file modified figures/highlightedKeyboardLayouts.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added figures/keyboard-gnome-irish.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added figures/keyboard-reset-irish.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion files/bibliography.yml
Original file line number Diff line number Diff line change
Expand Up @@ -348,4 +348,8 @@ flatpak-web:
gio:
type: web
title: "GIO"
url: https://crates.io/crates/gio
url: https://crates.io/crates/gio
gtk-css:
type: web
title: "GTK CSS properties"
url: https://docs.gtk.org/gtk4/css-properties.html
175 changes: 139 additions & 36 deletions sections/plugin_implementation/keyboard.typ
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,12 @@ input {
)<hyprconf-input-config>],
)

ReSet has to know where the input config is located which has to be provided by the user.
This path can be provided in the local config folder of a user in a file called Reset.toml.
This file contains ReSet relevant configuration. The user has to provide the path to the input
config there like @reset-keyboard-config-hyprland or else ReSet wouldn't know where to write
the changes to. If the file does not exist, a new one will be created.
ReSet has to know where the input config is located which has to be provided by
the user. This path can be provided in the local config folder of a user in a
file called Reset.toml. This file contains ReSet relevant configuration. The
user has to provide the path to the input config there like
@reset-keyboard-config-hyprland or else ReSet wouldn't know where to write the
changes to. If the file does not exist, a new one will be created.

#let code = "
[Keyboard]
Expand Down Expand Up @@ -133,11 +134,11 @@ Command::new(\"dconf\")
Therefore dconf_rs was replaced by gio. The advantages have already been discussed
in @GNOME. Gio provides very convenient bindings to the GSettings API. In
@gnome-gio-get-input-config the layouts are fetched and its type is checked. If the
layout_variant isn't an array of two strings an empty array will be returned. Otherwise
a generic get function is called with type Vec<(String, String)>> to parse it into
desired structure. This solution is a lot more elegant than the Regex because it is more
human readable and better performant wise as regex processing can be slower due to its
pattern matching which involves operations like backtracking.
layout_variant isn't an array of two strings an empty array will be returned.
Otherwise a generic get function is called with type Vec<(String, String)>> to parse
it into desired structure. This solution is a lot more elegant than the Regex because
it is more human readable and better performant wise as regex processing can be slower
due to its pattern matching which involves operations like backtracking.

#let code = "
let input_sources = gtk::gio::Settings::new(\"org.gnome.desktop.input-sources\");
Expand All @@ -157,7 +158,8 @@ let layouts = layout_variant.get::<Vec<(String, String)>>().unwrap();
)<gnome-gio-get-input-config>],
)

In @gnome-gio-set-input-config the code for writing the new keyboard layouts can be seen.
In @gnome-gio-set-input-config the code for writing the new keyboard layouts can be
seen.

#let code = "
let variant = Variant::from(all_layouts);
Expand All @@ -173,11 +175,12 @@ input_sources.set(\"sources\", variant).expect(\"failed to write layouts\");
)

#subsubsubsection("KDE Implementation")
To read the keyboard layouts and variants in KDE, kreadconfig6 has to be used. Unfortunately
there is no library that provides bindings so reading and writing using rust commands was
necessary. In @kde-get-input-config the command with all its argument can be seen. Writing
to the kxkbrc file works exactly the same as writing with the only difference of adding
the new keyboard layout string as an additional argument and using kwriteconfig6.
To read the keyboard layouts and variants in KDE, kreadconfig6 has to be used.
Unfortunately there is no library that provides bindings so reading and writing
using rust commands was necessary. In @kde-get-input-config the command with all
its argument can be seen. Writing to the kxkbrc file works exactly the same as
writing with the only difference of adding the new keyboard layout string as an
additional argument and using kwriteconfig6.

#let code = "
let output = Command::new(\"kreadconfig6\")
Expand Down Expand Up @@ -205,7 +208,8 @@ let kb_variant = parse_setting(output);

#align(
left, [#figure(
sourcecode(raw(code, lang: "rs")), kind: "code", supplement: "Listing", caption: [Read KDE keyboard layouts],
sourcecode(raw(code, lang: "rs")), kind: "code", supplement: "Listing",
caption: [Read KDE keyboard layouts],
)<kde-get-input-config>],
)

Expand All @@ -220,41 +224,140 @@ is not deprecated.
A quality-of-life feature to makes adding keyboard layouts easier is the
addition of nested listing. There are many keyboard variants for the same
layout, for example, German (US), German (Dvorak) etc. which can grouped
together into single entry in the list marked with an arrow symbol because not
all languages have variants.
together into single entry in the list marked with an arrow symbol because
not all languages have variants. An example on how this looks can be seen
in @nested-listing. \


#align(
center, [#figure(
img("keyboardAddLayout.png", width: 75%, extension: "figures"), caption: [Keyboard layouts with variants],
img("keyboardAddLayout.png", width: 75%, extension: "figures"),
caption: [Keyboard layouts with variants],
)<nested-listing>],
)

In Gnome control setting, every keyboard layout with its variations are
shown in an alphabetically sorted list. The problem with this approach is
that there are variants for layouts that have a very different name where
it's not obvious to which layout it belongs to as seen in an example in
@comparison-reset-gnome-irish.

#align(
center, [#figure([
#columns(2, [
#img("keyboard-reset-irish.png", width: 100%, extension: "figures")
#colbreak()
#img("keyboard-gnome-irish.png", width: 100%, extension: "figures")
])
], caption: [Irish keyboard layouts comparison (ReSet left, Gnome right)])<comparison-reset-gnome-irish>],
)

This feature reduces the list by a significant amount and helps the user to
narrow down the desired language first before looking more detailed for the
specific variant. Clicking on such an entry removes all other keyboard layouts
and only shows the variants for that language.
and only shows the variants for that language as seen in @keyboard-layout-variants.

#align(
center, [#figure(
img("keyboardAddLayoutVariants.png", width: 80%, extension: "figures"), caption: [Keyboard layouts with variants],
img("keyboardAddLayoutVariants.png", width: 80%, extension: "figures"),
caption: [Keyboard layouts with variants],
)<keyboard-layout-variants>],
)

To achieve this, a layout that has variants needs to have some code that removes
all other layouts and only show its variants and a button to show all layouts
again. This is shown in the on click event listener in @keyboard-show-variants.
The back button removes every element in the list and inserts all layouts back
to the list.

#let code = "
layout_row.connect_activate(clone!(@strong keyboard_layouts, @weak list, @strong back_row => move |_| {
// add variants to list
for keyboard_layout in keyboard_layouts.clone() {
let layout_row = create_layout_row(keyboard_layout.description.clone());
list.append(&layout_row);
}
list.prepend(&back_row);
let mut last_row = list.last_child();
let mut skip = keyboard_layouts.len();
// remove all but first
while last_row != None {
// if we're at top of list, prevent selecting the back button and break
if list.first_child() == last_row {
list.grab_focus();
break;
}
// skip rows because it's a variant we want to show
if skip > 0 {
last_row = last_row.unwrap().prev_sibling();
skip -= 1;
continue;
}
// remove row from list
let temp = last_row.clone().unwrap().prev_sibling();
list.remove(&last_row.unwrap());
last_row = temp;
}
}));
";

#align(
left, [#figure(
sourcecode(raw(code, lang: "rs")), kind: "code", supplement: "Listing",
caption: [Code to only show variants of selected layout],
)<keyboard-show-variants>],
)

#subsubsubsection("Highlight active layouts")
To show users that limitation visually, the first few rows are highlighted,
while the rest have system colors. This number is set depending on the desktop
environment because some don't use XKB and therefore could allow more than four
keyboard layouts. To further clarify it a subtitle for this setting group that
explains the highlight is added. \

#align(
center, [#figure(
img("highlightedKeyboardLayouts.png", width: 75%, extension: "figures"),
caption: [First few keyboard layouts are colored differently],
)<highlighted-keyboard-layouts>],
)

Because there are users that use many different themes, it is not possible to
hardcode a single color because it might not fit with other themes. A GTK
theme is defined in a css file that contains a list of key-value like pairs
of name and a color as can be seen in @gtk-theme-definition. These can be
accessed from ReSet with an \@css-name like @keyboard-css-highlight. Because
using the color definition as is is bound to clash with other UI elements with
the same coloring, color expressions can be used to slightly change a color
without having to hardcode it. @gtk-css

#subsubsubsection("Testing")
// todo
#let code = "
@define-color accent_color #a9b1d6;
@define-color accent_bg_color #a9b1d6;
@define-color accent_fg_color rgba(0, 0, 0, 0.87);
@define-color destructive_color #F28B82;
/* many more colors */
";

#align(
left, [#figure(
sourcecode(raw(code, lang: "css")), kind: "code", supplement: "Listing",
caption: [Excerpt from GTK default dark theme],
)<gtk-theme-definition>],
)

// moved from existing plugin fucntionality
// todo somehow integrate this somewhere
//To show users that limitation visually, the first few rows are highlighted,
//while the rest have system colors. This number is set depending on the desktop
//environment because some don't use XKB and therefore could allow more than four
//keyboard layouts.
#let code = "
row.activeLanguage {
background-color: darker(darker(darker(@window_fg_color)));
}
";

// #align(
// center, [#figure(
// img("highlightedKeyboardLayouts.png", width: 75%, extension: "figures"),
// caption: [First four keyboard layouts are colored differently],
// )<highlighted-keyboard-layouts>],
//)
#align(
left, [#figure(
sourcecode(raw(code, lang: "css")), kind: "code", supplement: "Listing",
caption: [Setting the highlight color],
)<keyboard-css-highlight>],
)

0 comments on commit 52a1fca

Please sign in to comment.