Compare commits

..

3 Commits

97 changed files with 1212 additions and 6783 deletions

View File

@ -136,10 +136,7 @@ test:
- build_meson
script:
- apt-get -y build-dep .
- apt-get -y install clang-tidy
- ninja -C _build test
- cd _build
- clang-tidy --checks=-clang-diagnostic-missing-braces,readability-braces-around-statements, --warnings-as-errors=readability-braces-around-statements -extra-arg=-Wno-unknown-warning-option ../src/*.c ../eek/*.c ../eekboard/*.c
check_release:
<<: *tags

430
Cargo.lock generated
View File

@ -4,481 +4,483 @@
name = "atk"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b7499272acf036bb5820c6e346bbfb5acc5dceb104bc2c4fd7e6e33dfcde6a"
dependencies = [
"atk-sys",
"bitflags",
"glib",
"glib-sys",
"gobject-sys",
"libc",
"atk-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atk-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e552c1776737a4c80110d06b36d099f47c727335f9aaa5d942a72b6863a8ec6f"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"pkg-config",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "cairo-rs"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e05db47de3b0f09a222fa4bba2eab957d920d4243962a86b2d77ab401e4a359c"
dependencies = [
"bitflags",
"cairo-sys-rs",
"glib",
"glib-sys",
"gobject-sys",
"libc",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-sys-rs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cairo-sys-rs"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff65ba02cac715be836f63429ab00a767d48336efc5497c5637afb53b4f14d63"
dependencies = [
"glib-sys",
"libc",
"pkg-config",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cc"
version = "1.0.67"
version = "1.0.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
[[package]]
name = "clap"
version = "2.33.3"
version = "2.33.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"bitflags",
"textwrap",
"unicode-width",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dtoa"
version = "0.4.8"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
[[package]]
name = "fragile"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f8140122fa0d5dcb9fc8627cfce2b37cc1500f752636d46ea28bc26785c2f9"
[[package]]
name = "gdk"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6243e995f41f3a61a31847e54cc719edce93dd9140c89dca3b9919be1cfe22d5"
dependencies = [
"bitflags",
"cairo-rs",
"cairo-sys-rs",
"gdk-pixbuf",
"gdk-sys",
"gio",
"gio-sys",
"glib",
"glib-sys",
"gobject-sys",
"libc",
"pango",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-sys-rs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gio 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pango 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gdk-pixbuf"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9726408ee1bbada83094326a99b9c68fea275f9dbb515de242a69e72051f4fcc"
dependencies = [
"gdk-pixbuf-sys",
"gio",
"gio-sys",
"glib",
"glib-sys",
"gobject-sys",
"libc",
"gdk-pixbuf-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gio 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gdk-pixbuf-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8991b060a9e9161bafd09bf4a202e6fd404f5b4dd1a08d53a1e84256fb34ab0"
dependencies = [
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"pkg-config",
"gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gdk-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6adf679e91d1bff0c06860287f80403e7db54c2d2424dce0a470023b56c88fbb"
dependencies = [
"cairo-sys-rs",
"gdk-pixbuf-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"pango-sys",
"pkg-config",
"cairo-sys-rs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pango-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gio"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6261b5d34c30c2d59f879e643704cf54cb44731f3a2038000b68790c03e360e3"
dependencies = [
"bitflags",
"fragile",
"gio-sys",
"glib",
"glib-sys",
"gobject-sys",
"lazy_static",
"libc",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fragile 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gio-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fad225242b9eae7ec8a063bb86974aca56885014672375e5775dc0ea3533911"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"pkg-config",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "glib"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be27232841baa43e0fd5ae003f7941925735b2f733a336dc75f07b9eff415e7b"
dependencies = [
"bitflags",
"glib-sys",
"gobject-sys",
"lazy_static",
"libc",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "glib-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95856f3802f446c05feffa5e24859fe6a183a7cb849c8449afc35c86b1e316e2"
dependencies = [
"libc",
"pkg-config",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gobject-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31d1a804f62034eccf370006ccaef3708a71c31d561fee88564abe71177553d9"
dependencies = [
"glib-sys",
"libc",
"pkg-config",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gtk"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "709f1074259d4685b96133f92b75c7f35b504715b0fcdc96ec95de2607296a60"
dependencies = [
"atk",
"bitflags",
"cairo-rs",
"cairo-sys-rs",
"cc",
"gdk",
"gdk-pixbuf",
"gdk-pixbuf-sys",
"gdk-sys",
"gio",
"gio-sys",
"glib",
"glib-sys",
"gobject-sys",
"gtk-sys",
"lazy_static",
"libc",
"pango",
"pango-sys",
"atk 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-sys-rs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gio 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gtk-sys 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pango 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pango-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gtk-sys"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53def660c7b48b00b510c81ef2d2fbd3c570f1527081d8d7947f471513e1a4c1"
dependencies = [
"atk-sys",
"cairo-sys-rs",
"gdk-pixbuf-sys",
"gdk-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"pango-sys",
"pkg-config",
"atk-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-sys-rs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pango-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.94"
version = "0.2.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
[[package]]
name = "linked-hash-map"
version = "0.5.4"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "maplit"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "memmap"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
dependencies = [
"libc",
"winapi",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pango"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "393fa071b144f8ffb83ede273758983cf414ca3c0b1d2a5a9ce325b3ba3dd786"
dependencies = [
"bitflags",
"glib",
"glib-sys",
"gobject-sys",
"lazy_static",
"libc",
"pango-sys",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pango-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pango-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b93d84907b3cf0819bff8f13598ba72843bee579d5ebc2502e4b0367b4be7d"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"pkg-config",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pkg-config"
version = "0.3.19"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
[[package]]
name = "proc-macro2"
version = "1.0.26"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
dependencies = [
"unicode-xid",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "1.0.9"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
"proc-macro2",
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
dependencies = [
"regex-syntax",
"regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rs"
version = "0.1.0"
dependencies = [
"bitflags",
"cairo-rs",
"cairo-sys-rs",
"clap",
"gdk",
"gio",
"glib",
"glib-sys",
"gtk",
"gtk-sys",
"maplit",
"regex",
"serde",
"serde_yaml",
"xkbcommon",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-sys-rs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gtk 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gtk-sys 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_yaml 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)",
"xkbcommon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde"
version = "1.0.126"
version = "1.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
dependencies = [
"serde_derive",
"serde_derive 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.126"
version = "1.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
dependencies = [
"proc-macro2",
"quote",
"syn",
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_yaml"
version = "0.8.17"
version = "0.8.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23"
dependencies = [
"dtoa",
"linked-hash-map",
"serde",
"yaml-rust",
"dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)",
"yaml-rust 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "1.0.72"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-width"
version = "0.1.8"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "unicode-xid"
version = "0.2.2"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "winapi"
version = "0.3.9"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "xkbcommon"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fda0ea5f7ddabd51deeeda7799bee06274112f577da7dd3d954b8eda731b2fce"
dependencies = [
"libc",
"memmap",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "yaml-rust"
version = "0.4.5"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
"linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
"checksum atk 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "86b7499272acf036bb5820c6e346bbfb5acc5dceb104bc2c4fd7e6e33dfcde6a"
"checksum atk-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e552c1776737a4c80110d06b36d099f47c727335f9aaa5d942a72b6863a8ec6f"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum cairo-rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e05db47de3b0f09a222fa4bba2eab957d920d4243962a86b2d77ab401e4a359c"
"checksum cairo-sys-rs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff65ba02cac715be836f63429ab00a767d48336efc5497c5637afb53b4f14d63"
"checksum cc 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)" = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311"
"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
"checksum dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3"
"checksum fragile 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f8140122fa0d5dcb9fc8627cfce2b37cc1500f752636d46ea28bc26785c2f9"
"checksum gdk 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6243e995f41f3a61a31847e54cc719edce93dd9140c89dca3b9919be1cfe22d5"
"checksum gdk-pixbuf 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9726408ee1bbada83094326a99b9c68fea275f9dbb515de242a69e72051f4fcc"
"checksum gdk-pixbuf-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d8991b060a9e9161bafd09bf4a202e6fd404f5b4dd1a08d53a1e84256fb34ab0"
"checksum gdk-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6adf679e91d1bff0c06860287f80403e7db54c2d2424dce0a470023b56c88fbb"
"checksum gio 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6261b5d34c30c2d59f879e643704cf54cb44731f3a2038000b68790c03e360e3"
"checksum gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4fad225242b9eae7ec8a063bb86974aca56885014672375e5775dc0ea3533911"
"checksum glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "be27232841baa43e0fd5ae003f7941925735b2f733a336dc75f07b9eff415e7b"
"checksum glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "95856f3802f446c05feffa5e24859fe6a183a7cb849c8449afc35c86b1e316e2"
"checksum gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31d1a804f62034eccf370006ccaef3708a71c31d561fee88564abe71177553d9"
"checksum gtk 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "709f1074259d4685b96133f92b75c7f35b504715b0fcdc96ec95de2607296a60"
"checksum gtk-sys 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53def660c7b48b00b510c81ef2d2fbd3c570f1527081d8d7947f471513e1a4c1"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
"checksum linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
"checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
"checksum pango 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "393fa071b144f8ffb83ede273758983cf414ca3c0b1d2a5a9ce325b3ba3dd786"
"checksum pango-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86b93d84907b3cf0819bff8f13598ba72843bee579d5ebc2502e4b0367b4be7d"
"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
"checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
"checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
"checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
"checksum serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)" = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d"
"checksum serde_derive 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)" = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250"
"checksum serde_yaml 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3e2dd40a7cdc18ca80db804b7f461a39bb721160a85c9a1fa30134bf3c02a5"
"checksum syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum xkbcommon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fda0ea5f7ddabd51deeeda7799bee06274112f577da7dd3d954b8eda731b2fce"
"checksum yaml-rust 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"

View File

@ -19,7 +19,6 @@ path = "@path@/examples/test_layout.rs"
[features]
gio_v0_5 = []
gtk_v0_5 = []
rustc_less_1_36 = []
# Dependencies which don't change based on build flags
[dependencies.cairo-sys-rs]

View File

@ -1,49 +0,0 @@
#!/usr/bin/env python3
"""This script manages Cargo builds
while keeping the artifact directory within the build tree
instead of the source tree.
"""
from pathlib import Path
import shlex
import subprocess
import sys
source_dir = Path(__file__).absolute().parent
args = sys.argv[1:]
binary_dir = "debug"
if '--release' in args:
binary_dir = "release"
# The file produced by Cargo will have a special name
try:
i = args.index('--rename')
except ValueError:
filename = None
else:
args.pop(i)
filename = args.pop(i)
# The target destination of the produced file is a positional argument
out_path = [arg for arg in args if not arg.startswith('--')]
if out_path:
out_path = out_path[0]
i = args.index(out_path)
args.pop(i)
subprocess.run(['sh', "{}/cargo.sh".format(source_dir.as_posix()), 'build']
+ args,
check=True)
if out_path:
out_path = Path(out_path).absolute()
out_basename = out_path.name
filename = filename or out_basename
subprocess.run(['cp', '-a',
'./{}/{}'.format(binary_dir, filename),
out_path],
check=True)

34
cargo_build.sh Executable file
View File

@ -0,0 +1,34 @@
#!/bin/sh
# This script manages Cargo builds
# while keeping the artifact directory within the build tree
# instead of the source tree
set -e
SCRIPT_PATH="$(realpath "$0")"
SOURCE_DIR="$(dirname "$SCRIPT_PATH")"
RELEASE=""
BINARY_DIR="debug"
if [ "${1}" = "--release" ]; then
shift
BINARY_DIR="release"
RELEASE="--release"
fi
if [ "${1}" = "--rename" ]; then
shift
FILENAME="${1}"
shift
fi
OUT_PATH="$(realpath "${1}")"
shift
OUT_BASENAME="$(basename "${OUT_PATH}")"
FILENAME="${FILENAME:-"${OUT_BASENAME}"}"
sh "$SOURCE_DIR"/cargo.sh build $RELEASE "$@"
if [ -n "${OUT_PATH}" ]; then
cp -a ./"${BINARY_DIR}"/"${FILENAME}" "${OUT_PATH}"
fi

View File

@ -1,70 +0,0 @@
# Maintained by: Khaled Eldoheiri <khalid@kdehairy.com>
---
outlines:
default: { width: 32.66, height: 52 }
altline: { width: 48.99, height: 52 }
wide: { width: 62, height: 52 }
spaceline: { width: 195.96, height: 52 }
special: { width: 35.66, height: 52 }
views:
base:
- "ذ ض ص ث ق ف غ ع خ ح ج"
- "ش س ي ب ل ا ت ن م ك ط"
- "Shift_L ء ؤ ر ة و ز ظ د BackSpace"
- "show_numbers preferences space . Return"
extra:
- "ذ ض ص ث ق لإ إ ع خ ح ج"
- "ش س ى ب لأ أ ت ن م ك ط"
- "Shift_L ئ لآ لا ه آ ز ظ د BackSpace"
- "show_numbers preferences space . Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols ، \" ' : ؛ ! ؟ BackSpace"
- "show_letters preferences space . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers \\ / < > = [ ] BackSpace"
- "show_letters preferences space . Return"
buttons:
Shift_L:
action:
locking:
lock_view: "extra"
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: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "altline"
label: "ض"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
space:
outline: "spaceline"
label: " "
text: " "
Return:
outline: "altline"
icon: "key-enter"
keysym: "Return"

View File

@ -1,70 +0,0 @@
# Maintained by: Khaled Eldoheiri <khalid@kdehairy.com>
---
outlines:
default: { width: 49, height: 42 }
altline: { width: 73.5, height: 42 }
wide: { width: 108, height: 42 }
spaceline: { width: 324, height: 42 }
special: { width: 49, height: 42 }
views:
base:
- "ذ ض ص ث ق ف غ ع خ ح ج"
- "ش س ي ب ل ا ت ن م ك ط"
- "Shift_L ء ؤ ر ة و ز ظ د BackSpace"
- "show_numbers preferences space . Return"
extra:
- "ذ ض ص ث ق لإ إ ع خ ح ج"
- "ش س ى ب لأ أ ت ن م ك ط"
- "Shift_L ئ لآ لا ه آ ز ظ د BackSpace"
- "show_numbers preferences space . Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols ، \" ' : ؛ ! ؟ BackSpace"
- "show_letters preferences space . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers \\ / < > = [ ] BackSpace"
- "show_letters preferences space . Return"
buttons:
Shift_L:
action:
locking:
lock_view: "extra"
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: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "altline"
label: "ض"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
space:
outline: "spaceline"
label: " "
text: " "
Return:
outline: "altline"
icon: "key-enter"
keysym: "Return"

View File

@ -1,78 +0,0 @@
---
outlines:
default: { width: 32.72, height: 52 }
altline: { width: 47, height: 52 }
wide: { width: 49.09, height: 52 }
spaceline: { width: 185, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "я в е р т ъ у и о п ю"
- "а с д ф г х й к л ш щ"
- "Shift_L з ь ц ж б н м ч BackSpace"
- "show_numbers preferences space . Return"
upper:
- В Е Р Т Ъ У И О П Ю"
- "А С Д Ф Г Х Й К Л Ш Щ"
- "Shift_L З Ь Ц Ж Б Н М Ч BackSpace"
- "show_numbers preferences space , Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space 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: "*/="
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"
"\"":
keysym: "quotedbl"

View File

@ -1,78 +0,0 @@
---
outlines:
default: { width: 32.72, height: 52 }
altline: { width: 47, height: 52 }
wide: { width: 49.09, height: 52 }
spaceline: { width: 185, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "у е и ш щ к с д з ц б"
- "ь я а о ж г т н в м ч"
- "Shift_L ю й ъ ф х п р л BackSpace"
- "show_numbers preferences space . Return"
upper:
- "У Е И Ш Щ К С Д З Ц Б"
- "Ь Я А О Ж Г Т Н В М Ч"
- "Shift_L Ю Й Ъ Ф Х П Р Л BackSpace"
- "show_numbers preferences space , Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? ѝ BackSpace"
- "show_letters preferences space Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space 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: "*/="
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"
"\"":
keysym: "quotedbl"

View File

@ -1,91 +0,0 @@
# Maintained by: Jordi Bossy <jordi@bossy.space>. No Copyright, enjoy!
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 48, height: 52 }
wide: { width: 59, height: 52 }
spaceline: { width: 70, height: 52 }
special: { width: 28, height: 52 }
views:
base:
- "q w e r t z u i o p"
- "a s d f g h j k l ?"
- "Shift_L y x c v b n m BackSpace"
- "show_numbers show_eschars preferences ' space , . Return"
upper:
- "Q W E R T Z U I O P"
- "A S D F G H J K L !"
- "Shift_L Y X C V B N M BackSpace"
- "show_numbers show_eschars preferences \" space , . Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ * + - = ( ) ~ < >"
- "show_symbols # & / \\ √ ; : BackSpace"
- "show_letters show_eschars preferences _ space , . Return"
symbols:
- "€ $ £ ¥ % | § µ [ ]"
- "© ® § ` ^ { } · ¡ ¿"
- "show_numbers « » ÷ × “ ” „ BackSpace"
- "show_letters show_eschars preferences - space , . Return"
eschars:
- "à â ç é è ê î ô ù û"
- "À Â Ç É È Ê Î Ô Ù Û"
- "show_numbers æ œ ä ë ï ö ü BackSpace"
- "show_letters_from_accents preferences ñ Ñ space ° ß 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: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "altline"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_eschars:
action:
locking:
lock_view: "eschars"
unlock_view: "base"
outline: "altline"
label: "âÂ"
show_letters_from_accents:
action:
locking:
lock_view: "eschars"
unlock_view: "base"
outline: "altline"
label: "âÂ"
space:
outline: "spaceline"
label: " "
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
"\"":
keysym: "quotedbl"

View File

@ -1,106 +0,0 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 52.67, height: 52 }
spaceline: { width: 106, height: 52 }
special: { width: 35.33, height: 52 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers preferences show_accents space , . Return"
upper:
- "Q W E R T Y U I O P"
- "A S D F G H J K L"
- "Shift_L Z X C V B N M BackSpace"
- "show_numbers preferences show_upper_accents space ! ? Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences show_accents space , . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences show_accents space , . Return"
accents:
- "ä ě é ř ť ý ů í ó ö"
- "á š ď ë ŕ ú ü ô ľ"
- "accents_Shift_L ž ß č ç ñ ň ĺ BackSpace"
- "show_letters preferences show_accents space , . Return"
upper_accents:
- "Ä Ě É Ř Ť Ý Ů Í Ó Ö"
- "Á Š Ď Ë Ŕ Ú Ü Ô Ľ"
- "accents_Shift_L Ž ẞ Č Ç Ñ Ň Ĺ BackSpace"
- "show_letters preferences show_upper_accents space , . Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
accents_Shift_L:
action:
locking:
lock_view: "upper_accents"
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_accents:
action:
locking:
lock_view: "accents"
unlock_view: "base"
outline: "special"
label: "á"
show_upper_accents:
action:
locking:
lock_view: "upper_accents"
unlock_view: "base"
outline: "special"
label: "Á"
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -1,106 +0,0 @@
---
outlines:
default: { width: 54, height: 42 }
altline: { width: 81, height: 42 }
wide: { width: 81, height: 42 }
spaceline: { width: 162, height: 42 }
special: { width: 54, height: 42 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers preferences show_accents space , . Return"
upper:
- "Q W E R T Y U I O P"
- "A S D F G H J K L"
- "Shift_L Z X C V B N M BackSpace"
- "show_numbers preferences show_upper_accents space ! ? Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences show_accents space , . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences show_accents space , . Return"
accents:
- "ä ě é ř ť ý ů í ó ö"
- "á š ď ë ŕ ú ü ô ľ"
- "accents_Shift_L ž ß č ç ñ ň ĺ BackSpace"
- "show_letters preferences show_accents space , . Return"
upper_accents:
- "Ä Ě É Ř Ť Ý Ů Í Ó Ö"
- "Á Š Ď Ë Ŕ Ú Ü Ô Ľ"
- "accents_Shift_L Ž ẞ Č Ç Ñ Ň Ĺ BackSpace"
- "show_letters preferences show_upper_accents space , . Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
accents_Shift_L:
action:
locking:
lock_view: "upper_accents"
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_accents:
action:
locking:
lock_view: "accents"
unlock_view: "base"
outline: "special"
label: "á"
show_upper_accents:
action:
locking:
lock_view: "upper_accents"
unlock_view: "base"
outline: "special"
label: "Á"
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -1,106 +0,0 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 52.67, height: 52 }
spaceline: { width: 106, height: 52 }
special: { width: 35.33, height: 52 }
views:
base:
- "q w e r t z u i o p"
- "a s d f g h j k l"
- "Shift_L y x c v b n m BackSpace"
- "show_numbers preferences show_accents space , . Return"
upper:
- "Q W E R T Z U I O P"
- "A S D F G H J K L"
- "Shift_L Y X C V B N M BackSpace"
- "show_numbers preferences show_upper_accents space ! ? Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences show_accents space , . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences show_accents space , . Return"
accents:
- "ä ě é ř ť ž ů í ó ö"
- "á š ď ë ŕ ú ü ô ľ"
- "accents_Shift_L ý ß č ç ñ ň ĺ BackSpace"
- "show_letters preferences show_accents space , . Return"
upper_accents:
- "Ä Ě É Ř Ť Ž Ů Í Ó Ö"
- "Á Š Ď Ë Ŕ Ú Ü Ô Ľ"
- "accents_Shift_L Ý ẞ Č Ç Ñ Ň Ĺ BackSpace"
- "show_letters preferences show_upper_accents space , . Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
accents_Shift_L:
action:
locking:
lock_view: "upper_accents"
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_accents:
action:
locking:
lock_view: "accents"
unlock_view: "base"
outline: "special"
label: "á"
show_upper_accents:
action:
locking:
lock_view: "upper_accents"
unlock_view: "base"
outline: "special"
label: "Á"
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -1,106 +0,0 @@
---
outlines:
default: { width: 54, height: 42 }
altline: { width: 81, height: 42 }
wide: { width: 81, height: 42 }
spaceline: { width: 162, height: 42 }
special: { width: 54, height: 42 }
views:
base:
- "q w e r t z u i o p"
- "a s d f g h j k l"
- "Shift_L y x c v b n m BackSpace"
- "show_numbers preferences show_accents space , . Return"
upper:
- "Q W E R T Z U I O P"
- "A S D F G H J K L"
- "Shift_L Y X C V B N M BackSpace"
- "show_numbers preferences show_upper_accents space ! ? Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences show_accents space , . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences show_accents space , . Return"
accents:
- "ä ě é ř ť ž ů í ó ö"
- "á š ď ë ŕ ú ü ô ľ"
- "accents_Shift_L ý ß č ç ñ ň ĺ BackSpace"
- "show_letters preferences show_accents space , . Return"
upper_accents:
- "Ä Ě É Ř Ť Ž Ů Í Ó Ö"
- "Á Š Ď Ë Ŕ Ú Ü Ô Ľ"
- "accents_Shift_L Ý ẞ Č Ç Ñ Ň Ĺ BackSpace"
- "show_letters preferences show_upper_accents space , . Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
accents_Shift_L:
action:
locking:
lock_view: "upper_accents"
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_accents:
action:
locking:
lock_view: "accents"
unlock_view: "base"
outline: "special"
label: "á"
show_upper_accents:
action:
locking:
lock_view: "upper_accents"
unlock_view: "base"
outline: "special"
label: "Á"
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -21,7 +21,7 @@ views:
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols ; \" ' : = < > BackSpace"
- "show_symbols , \" ' : = < > BackSpace"
- "show_letters show_eschars preferences space , . Return"
symbols:
- "~ ` ´ | · √ µ ÷ × ¶"

View File

@ -21,7 +21,7 @@ views:
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # % & - _ + ( ) ß"
- "show_symbols ; \" ' : = < > BackSpace"
- "show_symbols , \" ' : = < > BackSpace"
- "show_letters preferences space , . Return"
symbols:
- "~ ` ´ · © ® ÷ × ¶"

View File

@ -1,81 +0,0 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 62, height: 52 }
spaceline: { width: 99.67, height: 52 }
special: { width: 35.33, height: 52 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers show_eschars preferences space , . Return"
upper:
- "Q W E R T Y U I O P"
- "A S D F G H J K L"
- "Shift_L Z X C V B N M BackSpace"
- "show_numbers show_eschars preferences space ! ? Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' : ; ! ? BackSpace"
- "show_letters preferences space . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space . Return"
eschars:
- "ĉ ĝ ĥ ĵ ŝ ŭ ?"
- "Ĉ Ĝ Ĥ Ĵ Ŝ Ŭ !"
- "show_numbers ' - 🐊 💚 🌐 . BackSpace"
- "show_letters show_eschars preferences space „ “ 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: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "altline"
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"
label: " "
text: " "
Return:
outline: "altline"
icon: "key-enter"
keysym: "Return"

View File

@ -1,87 +0,0 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 62, height: 52 }
spaceline: { width: 99.67, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l ç"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers show_eschars preferences space ? period Return"
upper:
- "Q W E R T Y U I O P"
- "A S D F G H J K L Ç"
- "Shift_L Z X C V B N M BackSpace"
- "show_numbers show_eschars preferences space ¿ period Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon ; ! = BackSpace"
- "show_letters show_eschars preferences space ? period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers \\ / < > = [ ] BackSpace"
- "show_letters show_eschars preferences space ? period Return"
eschars:
- "á é í ó ú Á É Í Ó Ú"
- "à è ì ò ù À È Ì Ò Ù"
- "show_numbers ü ç ï Ü Ç Ï ¡ BackSpace"
- "show_letters show_eschars preferences space « » 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: "default"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "altline"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_eschars:
action:
locking:
lock_view: "eschars"
unlock_view: "base"
outline: "altline"
label: "àÀ"
period:
outline: "default"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "altline"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -1,71 +0,0 @@
---
outlines:
default: { width: 40, height: 60 }
altline: { width: 56, height: 60 }
wide: { width: 62, height: 60 }
spaceline: { width: 142, height: 60 }
special: { width: 44, height: 60 }
views:
base:
- "' - ק ר א ט ו ן ם פ"
- "ש ד ג כ ע י ח ל ך ף"
- ס ב ה נ מ צ ת ץ BackSpace"
- "show_numbers comma preferences space period Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # ₪ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € $ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space period Return"
buttons:
BackSpace:
outline: "default"
icon: "edit-clear-symbolic"
action: erase
comma:
outline: "special"
text: ","
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: "*/="
period:
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -1,78 +0,0 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 62, height: 52 }
spaceline: { width: 142, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "ض ص ق ف غ ع ه خ ح ج"
- "ش س ی ب ل ا ت ن م ک"
- "Shift_L ظ ط ز ر ذ د و BackSpace"
- "show_numbers preferences space period Return"
upper:
- "پ { } [ ] ّ َ ِ ُ چ"
- "ؤ‌ ئ ي‌ إ أ آ ة‌ » « گ"
- "Shift_L ك ٓ ژ ء > < ؟ BackSpace"
- "show_numbers preferences space period Return"
numbers:
- "۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ ۰"
- "@ # ﷼ % & - _ + ( )"
- "show_symbols , \" ' colon ؛ ! ? BackSpace"
- "show_letters preferences space period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space period 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: "*/="
period:
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -1,78 +0,0 @@
---
outlines:
default: { width: 54, height: 42 }
altline: { width: 81, height: 42 }
wide: { width: 108, height: 42 }
spaceline: { width: 216, height: 42 }
special: { width: 54, height: 42 }
views:
base:
- "ض ص ق ف غ ع ه خ ح ج"
- "ش س ی ب ل ا ت ن م ک"
- "Shift_L ظ ط ز ر ذ د و BackSpace"
- "show_numbers preferences space period Return"
upper:
- "پ { } [ ] ّ َ ِ ُ چ"
- "ؤ‌ ئ ي‌ إ أ آ ة‌ » « گ"
- "Shift_L ك ٓ ژ ء > < ؟ BackSpace"
- "show_numbers preferences space period Return"
numbers:
- "۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ ۰"
- "@ # ﷼ % & - _ + ( )"
- "show_symbols , \" ' colon ؛ ! ? BackSpace"
- "show_letters preferences space period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space period 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: "*/="
".":
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -1,89 +0,0 @@
# Friulian layout created by Fabio Tomat
# 14 october 2020
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 62, height: 52 }
spaceline: { width: 99.67, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers show_eschars preferences space , . Return"
upper:
- "Q W E R T Y U I O P"
- "A S D F G H J K L"
- "Shift_L Z X C V B N M BackSpace"
- "show_numbers show_eschars preferences space “ ” Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' : ; ! = BackSpace"
- "show_letters show_eschars preferences space ? . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers \\ / < > = [ ] BackSpace"
- "show_letters show_eschars preferences space ? . Return"
eschars:
- "â ê î ô û Â Ê Î Ô Û"
- "à è ì ò ù À È Ì Ò Ù"
- "show_numbers ç Ç ᶜ ᵐ ⁿ ᵉ ᵗ BackSpace"
- "show_letters show_eschars preferences space ᶠ . 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: "altline"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "altline"
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"
label: " "
text: " "
Return:
outline: "altline"
icon: "key-enter"
keysym: "Return"

View File

@ -22,7 +22,7 @@ views:
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' : ; ! ? BackSpace"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters show_eschars preferences space ? . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
@ -84,4 +84,7 @@ buttons:
outline: "altline"
icon: "key-enter"
keysym: "Return"
colon:
label: ":"
"\"":
keysym: "quotedbl"

View File

@ -438,7 +438,7 @@ buttons:
unlock_view: "カタカナ"
outline: "altline"
label: "。"
# Buttons for Latin characters
# Buttons for Latin charachters
RSYM1:
action:
locking:

View File

@ -438,7 +438,7 @@ buttons:
unlock_view: "カタカナ"
outline: "altline"
label: "。"
# Buttons for Latin characters
# Buttons for Latin charachters
RSYM1:
action:
locking:

View File

@ -2,9 +2,9 @@
outlines:
default: { width: 32, height: 52 }
altline: { width: 48.39024, height: 52 }
wide: { width: 64, height: 52 }
spaceline: { width: 142, height: 52 }
special: { width: 44, height: 52 }
wide: { width: 62, height: 52 }
outline7: { width: 88.97561, height: 52 }
spaceline: { width: 150.5853, height: 52 }
views:
base:
@ -25,7 +25,7 @@ views:
symbols:
- "~ ` | U00B7 squareroot Greek_pi Greek_tau division multiply paragraph"
- "copyright U00AE U00A3 EuroSign U00A5 asciicircum degree * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_numbers \\ / < > = [ ] BackSpace"
- "show_letters preferences space . Return"
buttons:
@ -42,22 +42,17 @@ buttons:
action: erase
preferences:
action: "show_prefs"
outline: "special"
outline: "altline"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: altline
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
outline: "altline"
label: "ABC"
show_symbols:
action:
@ -65,7 +60,7 @@ buttons:
outline: "altline"
label: "*/="
".":
outline: "special"
outline: altline
space:
outline: spaceline
text: " "

View File

@ -52,8 +52,6 @@ buttons:
locking:
lock_view: "upper_accents"
unlock_view: "accents"
looks_locked_from:
- "upper"
outline: "altline"
icon: "key-shift"
BackSpace:
@ -96,8 +94,6 @@ buttons:
locking:
lock_view: "upper_accents"
unlock_view: "upper"
looks_locked_from:
- "accents"
outline: "altline"
label: "ĄĘ"
period:

View File

@ -147,6 +147,9 @@ buttons:
Pause:
outline: "action"
keysym: "Pause"
Menu:
outline: "action"
keysym: "Menu"
Break:
outline: "action"
keysym: "Break"
@ -198,3 +201,4 @@ buttons:
modifier: "Alt"
outline: "small"
label: "Alt"

View File

@ -1,220 +0,0 @@
---
outlines:
action: { width: 59, height: 46 }
small: { width: 50, height: 22 }
default: { width: 35.33, height: 46 }
altline: { width: 48, height: 46 }
wide: { width: 50, height: 46 }
spaceline: { width: 110, height: 46 }
special: { width: 44, height: 46 }
views:
base:
- "Ctrl Alt Tabsmall ↑ ↓ ← →"
- "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 period BackSpace"
- "show_numbers preferences space show_eschars show_actions Return"
upper:
- "Ctrl Alt Tabsmall PgUp PgDn Home End"
- "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 show_actions Return"
numbers:
- "Ctrl Alt Tabsmall ↑ ↓ ← →"
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space show_eschars show_actions Return"
symbols:
- "Ctrl Alt Tabsmall ↑ ↓ ← →"
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space show_eschars show_actions Return"
eschars:
- "Ctrl Alt Tabsmall ↑ ↓ ← →"
- "à â ç é è ê î ô ù û"
- "À Â Ç É È Ê Î Ô Ù Û"
- "show_numbers_from_symbols æ œ ä ë ï ö ü BackSpace"
- "show_letters preferences space show_eschars show_actions Return"
actions:
- "Ctrl Alt PgUp PgDn Home End"
- "F1 F2 F3 F4 F5 F6"
- "F7 F8 F9 F10 F11 F12"
- "Esc Tab Pause Insert Up Del"
- "show_letters Menu Break Left Down Right"
buttons:
F1:
outline: "action"
keysym: "F1"
F2:
outline: "action"
keysym: "F2"
F3:
outline: "action"
keysym: "F3"
F4:
outline: "action"
keysym: "F4"
F5:
outline: "action"
keysym: "F5"
F6:
outline: "action"
keysym: "F6"
F7:
outline: "action"
keysym: "F7"
F8:
outline: "action"
keysym: "F8"
F9:
outline: "action"
keysym: "F9"
F10:
outline: "action"
keysym: "F10"
F11:
outline: "action"
keysym: "F11"
F12:
outline: "action"
keysym: "F12"
Esc:
outline: "action"
keysym: "Escape"
Tab:
outline: "action"
keysym: "Tab"
Tabsmall:
outline: "small"
keysym: "Tab"
label: "Tab"
Del:
outline: "action"
keysym: "Delete"
Insert:
outline: "action"
keysym: "Insert"
Menu:
outline: "action"
keysym: "Menu"
Pause:
outline: "action"
keysym: "Pause"
Break:
outline: "action"
keysym: "Break"
Home:
outline: "small"
keysym: "Home"
End:
outline: "small"
keysym: "End"
PgUp:
outline: "small"
keysym: "Page_Up"
PgDn:
outline: "small"
keysym: "Page_Down"
"↑":
outline: "small"
keysym: "Up"
"↓":
outline: "small"
keysym: "Down"
"←":
outline: "small"
keysym: "Left"
"→":
outline: "small"
keysym: "Right"
Up:
label: "↑"
outline: "action"
keysym: "Up"
Left:
label: "←"
outline: "action"
keysym: "Left"
Down:
label: "↓"
outline: "action"
keysym: "Down"
Right:
label: "→"
outline: "action"
keysym: "Right"
Ctrl:
modifier: "Control"
outline: "small"
label: "Ctrl"
Alt:
modifier: "Alt"
outline: "small"
label: "Alt"
period:
outline: "special"
text: "."
show_actions:
action:
set_view: "actions"
outline: "special"
label: ">_"
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"

View File

@ -1,223 +0,0 @@
---
outlines:
action: { width: 90, height: 37 }
small: { width: 67.4, height: 22 }
default: { width: 54, height: 37 }
altline: { width: 81, height: 37 }
wide: { width: 100, height: 37 }
spaceline: { width: 110, height: 37 }
special: { width: 54, height: 37 }
views:
base:
- "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
- "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 period BackSpace"
- "show_numbers preferences space show_eschars show_actions Return"
upper:
- "EscSmall TabSmall Ctrl Alt PgUp PgDn Home End"
- "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 show_actions Return"
numbers:
- "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space show_eschars show_actions Return"
symbols:
- "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space show_eschars show_actions Return"
eschars:
- "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
- "à â ç é è ê î ô ù û"
- "À Â Ç É È Ê Î Ô Ù Û"
- "show_numbers_from_symbols æ œ ä ë ï ö ü BackSpace"
- "show_letters preferences space show_eschars show_actions Return"
actions:
- "EscSmall TabSmall Ctrl Alt PgUp PgDn Home End"
- "F1 F2 F3 F4 F5 F6"
- "F7 F8 F9 F10 F11 F12"
- "Esc Tab Pause Insert Up Del"
- "show_letters Menu Break Left Down Right"
buttons:
F1:
outline: "action"
keysym: "F1"
F2:
outline: "action"
keysym: "F2"
F3:
outline: "action"
keysym: "F3"
F4:
outline: "action"
keysym: "F4"
F5:
outline: "action"
keysym: "F5"
F6:
outline: "action"
keysym: "F6"
F7:
outline: "action"
keysym: "F7"
F8:
outline: "action"
keysym: "F8"
F9:
outline: "action"
keysym: "F9"
F10:
outline: "action"
keysym: "F10"
F11:
outline: "action"
keysym: "F11"
F12:
outline: "action"
keysym: "F12"
Esc:
outline: "action"
keysym: "Escape"
EscSmall:
outline: "small"
keysym: "Escape"
label: "Esc"
Tab:
outline: "action"
keysym: "Tab"
TabSmall:
outline: "small"
keysym: "Tab"
label: "Tab"
Del:
outline: "action"
keysym: "Delete"
Insert:
outline: "action"
keysym: "Insert"
Menu:
outline: "action"
keysym: "Menu"
Pause:
outline: "action"
keysym: "Pause"
Break:
outline: "action"
keysym: "Break"
Home:
outline: "small"
keysym: "Home"
End:
outline: "small"
keysym: "End"
PgUp:
outline: "small"
keysym: "Page_Up"
PgDn:
outline: "small"
keysym: "Page_Down"
"↑":
outline: "small"
keysym: "Up"
"↓":
outline: "small"
keysym: "Down"
"←":
outline: "small"
keysym: "Left"
"→":
outline: "small"
keysym: "Right"
Up:
label: "↑"
outline: "action"
keysym: "Up"
Left:
label: "←"
outline: "action"
keysym: "Left"
Down:
label: "↓"
outline: "action"
keysym: "Down"
Right:
label: "→"
outline: "action"
keysym: "Right"
Ctrl:
modifier: "Control"
outline: "small"
label: "Ctrl"
Alt:
modifier: "Alt"
outline: "small"
label: "Alt"
period:
outline: "special"
text: "."
show_actions:
action:
set_view: "actions"
outline: "special"
label: ">_"
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"

View File

@ -155,6 +155,9 @@ buttons:
Pause:
outline: "action"
keysym: "Pause"
Menu:
outline: "action"
keysym: "Menu"
Break:
outline: "action"
keysym: "Break"
@ -205,4 +208,4 @@ buttons:
Alt:
modifier: "Alt"
outline: "small"
label: "Alt"
label: "Alt"

View File

@ -1,80 +0,0 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 62, height: 52 }
spaceline: { width: 142, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "ๅ / _ ภ ถ ุ ึ ค ต จ ข ช"
- "ๆ ไ ำ พ ะ ั ี ร น ย บ ล"
- "ฟ ห ก ด เ ้ ่ า ส ว ง ฃ"
- "Shift_L ผ ป แ อ ิ ื ท ม ใ ฝ BackSpace"
- "show_numbers preferences space period Return"
upper:
- "+ ๑ ๒ ๓ ๔ ู ฿ ๕ ๖ ๗ ๘ ๙"
- " \" ฎ ฑ ธ ํ ๊ ณ ฯ ญ ฐ ,"
- "ฤ ฆ ฏ โ ฌ ็ ๋ ษ ศ ซ . ฅ"
- "Shift_L ( ) ฉ ฮ ฺ ์ ? ฒ ฬ ฦ BackSpace"
- "show_numbers preferences space period Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space period 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: "กขค"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
period:
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -1,84 +0,0 @@
---
outlines:
default: { width: 75, height: 56 }
altline: { width: 75, height: 56 }
wide: { width: 135, height: 56 }
spaceline: { width: 450, height: 56 }
spacelinesymbol: { width: 300, height: 56 }
special: { width: 90, height: 56 }
views:
base:
- "ๅ / _ ภ ถ ุ ึ ค ต จ ข ช"
- "ๆ ไ ำ พ ะ ั ี ร น ย บ ล"
- "ฟ ห ก ด เ ้ ่ า ส ว ง ฃ"
- "Shift_L ผ ป แ อ ิ ื ท ม ใ ฝ BackSpace"
- "show_numbers preferences space period Return"
upper:
- "+ ๑ ๒ ๓ ๔ ู ฿ ๕ ๖ ๗ ๘ ๙"
- " \" ฎ ฑ ธ ํ ๊ ณ ฯ ญ ฐ ,"
- "ฤ ฆ ฏ โ ฌ ็ ๋ ษ ศ ซ . ฅ"
- "Shift_L ( ) ฉ ฮ ฺ ์ ? ฒ ฬ ฦ BackSpace"
- "show_numbers preferences space period Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences spacesymbol period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences spacesymbol period 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: "กขค"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
period:
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
spacesymbol:
outline: "spacelinesymbol"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -1,78 +0,0 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 62, height: 52 }
spaceline: { width: 142, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "q w f p g j l u y"
- "a r s t d h n e i o"
- "Shift_L z x c v b k m BackSpace"
- "show_numbers preferences space period Return"
upper:
- "Q W F P G J L U Y"
- "A R S T D H N E I O"
- "Shift_L Z X C V B K M BackSpace"
- "show_numbers preferences space period Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space period 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: "*/="
period:
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -1,78 +0,0 @@
---
outlines:
default: { width: 54, height: 42 }
altline: { width: 81, height: 42 }
wide: { width: 108, height: 42 }
spaceline: { width: 216, height: 42 }
special: { width: 54, height: 42 }
views:
base:
- "q w f p g j l u y"
- "a r s t d h n e i o"
- "Shift_L z x c v b k m BackSpace"
- "show_numbers preferences space . Return"
upper:
- "Q W F P G J L U Y"
- "A R S T D H N E I O"
- "Shift_L Z X C V B K M BackSpace"
- "show_numbers preferences space . Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space . 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: "*/="
".":
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -1,89 +0,0 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 62, height: 52 }
spaceline: { width: 142, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "Shift_L p y f g c r l BackSpace"
- "a o e u i d h t n s"
- ", q j k x b m w v z"
- "show_numbers preferences space period Return"
upper:
- "Shift_L P Y F G C R L BackSpace"
- "A O E U I D H T N S"
- ", Q J K X B M W V Z"
- "show_numbers preferences space period Return"
numbers:
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "* # $ / & - _ + ( )"
- "1 2 3 4 5 6 7 8 9 0"
- "show_letters preferences space period Return"
symbols:
- "show_numbers_from_symbols \\ % < > = [ ] BackSpace"
- "© ® £ € ¥ ^ ° @ { }"
- "~ ` | · √ π τ ÷ × ¶"
- "show_letters preferences space period 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: "*/="
period:
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"
# The US QWERTY layout has fewer letters on the third row, and so has
# the shift & backspace keys placed there. In contrast, the US DVORAK
# layout has fewer letters on the first row, which makes it a good
# choice for the shift & backspace keys. That leads to what may be,
# for many people, an unexpected layout in numbers mode: the numerals
# are on the third row (not the first) so that the backspace key
# remains in a consistent location regardless of mode, without
# sacrificing key width. (Once could argue that in numbers mode, the
# numerals should be closer to the enter key.) As with any keyboard
# layout, familiarity comes with repeated use.

View File

@ -1,89 +0,0 @@
---
outlines:
default: { width: 54, height: 42 }
altline: { width: 81, height: 42 }
wide: { width: 108, height: 42 }
spaceline: { width: 216, height: 42 }
special: { width: 54, height: 42 }
views:
base:
- "Shift_L p y f g c r l BackSpace"
- "a o e u i d h t n s"
- ", q j k x b m w v z"
- "show_numbers preferences space period Return"
upper:
- "Shift_L P Y F G C R L BackSpace"
- "A O E U I D H T N S"
- ", Q J K X B M W V Z"
- "show_numbers preferences space period Return"
numbers:
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "* # $ / & - _ + ( )"
- "1 2 3 4 5 6 7 8 9 0"
- "show_letters preferences space period Return"
symbols:
- "show_numbers_from_symbols \\ % < > = [ ] BackSpace"
- "© ® £ € ¥ ^ ° @ { }"
- "~ ` | · √ π τ ÷ × ¶"
- "show_letters preferences space period 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: "*/="
period:
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"
# The US QWERTY layout has fewer letters on the third row, and so has
# the shift & backspace keys placed there. In contrast, the US DVORAK
# layout has fewer letters on the first row, which makes it a good
# choice for the shift & backspace keys. That leads to what may be,
# for many people, an unexpected layout in numbers mode: the numerals
# are on the third row (not the first) so that the backspace key
# remains in a consistent location regardless of mode, without
# sacrificing key width. (Once could argue that in numbers mode, the
# numerals should be closer to the enter key.) As with any keyboard
# layout, familiarity comes with repeated use.

View File

@ -1,22 +0,0 @@
ara Арабски
be Белгийски
bg Български
br Бразилски
cz Чешки
de Немски
dk Датски
es Испански
emoji Емоджи
fi Фински
fr Френски
gr Гръцки
it Италиански
jp Японски
no Норвежки
pl Полски
ru Руски
se Шведски
th Тайски
ua Украински
terminal Терминал
us Английски (САЩ)

View File

@ -1,21 +0,0 @@
be Belgická
cz Česká
cz+qwerty Česká (QWERTY)
de Německá
dk Dánská
emoji Emoji
es Španělská
fi Finská
fr Francouzská
gr Řecká
it Italská
jp Japonská
jp+kana Japonská (Kana)
no Norská
pl Polská
ru Ruská
se Švédská
terminal Terminál
th Thajská
ua Ukrajinská
us Anglická (USA)

View File

@ -1,2 +0,0 @@
emoji ایموجی
terminal ترمینال

View File

@ -1,18 +0,0 @@
be Belgjic
br Brasilian
de Todesc
dk Danês
es Spagnûl
fi Finlandês
fr Francês
it+fur Furlan
gr Grêc
it Talian
jp+kana Gjaponês (Kana)
no Norvegjês
pl Polac
ru Rus
se Svedês
terminal Terminâl
ua Ucrain
us American (USA)

View File

@ -1,19 +0,0 @@
be בלגית
br פורטוגזית (ברזיל)
cz צ'כית
de גרמנית
dk דנית
es ספרדית
emoji אימוג'י
fi פינית
fr צרפתית
gr יוונית
il עברית
it איטלקית
no נורווגית
pl פולנית
ru רוסית
se שוודית
terminal טרמינל
ua אוקראינית
us אנגלית (ארה"ב)

View File

@ -31,14 +31,9 @@ sq_button.wide {
border-color: #3e3a44;
}
sq_button.latched {
background: #ffffff;
color: #2b292f;
}
sq_button.locked {
background: #ffffff;
color: #1c71d8;
color: #2b292f;
}
sq_button.action {

View File

@ -34,14 +34,9 @@ sq_button.wide {
border-color: @borders; /* #3e3a44; */
}
sq_button.latched {
background: @theme_fg_color; /*#ffffff;*/
color: @theme_bg_color; /*#2b292f;*/
}
sq_button.locked {
background: @theme_fg_color; /*#ffffff;*/
color: mix(@theme_selected_bg_color, @theme_bg_color, 0.4); /*#2b292f;*/
color: @theme_bg_color; /*#2b292f;*/
}
sq_button.action {

239
debian/changelog vendored
View File

@ -1,242 +1,3 @@
squeekboard (1.14.0pureos0~amber0) amber-phone; urgency=medium
[ Dorota Czaplejewicz ]
* data: Split into loading and parsing
* layout: Remove unused code
* build: Fix unnecessary shell quotes
* popover: Allow spanning outside panel area
* cargo: Update dependencies before release
[ undef ]
* Fix typos jp keyboard comments
[ anteater ]
* use the correct GtkStyleProviderPriority to indicate that the styles are provided by the application
* remove some unnecessary unsafe code
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Sat, 15 May 2021 12:45:20 +0000
squeekboard (1.13.0pureos0~amber0) amber-phone; urgency=medium
[ Dorota Czaplejewicz ]
* layout: Latch keys when clicked twice
* layout: Add stateless view switching
* layout: Plug in stateless view switching
* layout: Remove the little abomination of view change promise
* view: Ąto-unlatching when multiple latching buttons pressed
* renderer: Bring button drawing closer to Rust
* ffi: Eliminate squeek_button and squeek_row
* imservice: Increment serials on receiving done, not sending commit
* input-method: Fix commit/done mixup in protocol text
* CI: fix xheck_tag to be compatible with Amber
* italian: Fix colon
* popover: Fix prematurely deallocated CString
* Rust: Remove unnecessary no_mangle statements to silence warnings
* renderer: Reduce reliance on knowing the transform
* renderer: Split mutable geometry and place it directly in GtkKeyboard
* Revert "moved data/langs/he_IL.txt -> data/langs/he-IL.txt to better conform with existing translations."
* layout: Make it possible to opt out of latching per-key
* renderer: Mark latched buttons differently than locked
* appearance: Colour latched/locked according to design
* docs: Describe view switching
* language-terminal: Place keyboards in a sub-path
* layout selection: Fix emoji and number
* rust: Fix compiler warnings
* layout: Take into account text purpose again
* layouts: Make selection testable
* layouts: Stop assuming that layout name always changes on switch
* Cargo: Version bump
[ J.D. Laub ]
* Add US Dvorak layout (and Colemak wide)
* Add US Dvorak layout (and Colemak wide)
[ Jordi Masip ]
* Catalan keyboard layout
[ Myth ]
* Added hebrew keyboard layout
[ David96 ]
* Add Mod4 (Windows) key
[ Panawat Wong-klaew ]
* Add wide Thai keyboard layout
[ Guido Günther ]
* server-main: Add quit()
* server-main: Properly register to gnome-session (Closes: #274)
[ Kozova1 ]
* Added Hebrew translations for most layouts.
* moved data/langs/he_IL.txt -> data/langs/he-IL.txt to better conform with existing translations.
* Fixed Hebrew layout.
* moved data/langs/he_IL.txt -> data/langs/he-IL.txt to better conform with existing translations.
[ M33 ]
* Revert "Update tests/meson.build"
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Mon, 12 Apr 2021 10:40:32 +0000
squeekboard (1.12.0pureos0~amber0) amber-phone; urgency=medium
[ Dorota Czaplejewicz ]
* docs: Correct Cargo update instructions
* visibility: Centralize keyboard panel visibility policy and handling
* build: Fix release
* tests: Prefer the env var for finding test layouts
* tests: Explicitly pass source directory to tests
* debian: Build reproducibly
* tests: Allow legacy mode to have much longer tests.
* build: Enable unused warnings in C
* build: Enable wformat to remove warnings about missing wformat
* build: Fail on any C warnings when strict
* data: Made data flow in fallback clearer
* data: Flattened layout fallback function
* layouts: Use base as fallback for alternative layouts
* layouts: Simplify the main flow of source list
* tests: Add some description to the list of tested layouts
* layout_names: Unmess the list of builtin layouts
* dbus: Reset hints if text input missing
* visibility: Stop calling GTK functions from the visibility manager
[ Wannaphong Phatthiyaphaibun ]
* Add thai keyboard
* Update resources.rs
* Update meson.build
* escape " on thai keyboard
[ clonex10100 ]
* Added US Colemak Keyboard Layout
[ Henry-Nicolas Tourneur ]
* d/rules: fix an FTBFS on mips64el with GOT > 64kb
* d/rules: export RUSTFLAGS only on architecture that needs it
* d/rules: export RUSTFLAGS only on architecture that needs it
[ Jiří Stránský ]
* Add Czech keyboard layouts
[ Stefan Grotz ]
* Esperanto keyboard
[ Vladimir ]
* Bulgarian language keyboard layout
[ Vladimir Stoilov ]
* bulgarian add translation and to needed lists
* Fix bulgarian layout size
[ Andreas Rönnquist ]
* no: Use wide button switching between numbers, symbols and base
[ jranaraki ]
* Farsi/Persian keyboard layout
* Farsi/Persian keyboard layout
* Added requirements to resources.rs and meson.build
* Updated the layout to provide more convenient and faster typing experience
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Sun, 10 Jan 2021 09:43:42 +0000
squeekboard (1.11.1) amber-phone; urgency=medium
[ Mark Müller ]
* keyboard: Fix semicolon in German layout
* keyboard: Move semicolon in German layout to numbers view replacing redundant comma key
[ Dorota Czaplejewicz ]
* imservice: Set up UI according to current needs when it shows up
* UI: Keep visibility factors in a central place
* cargo: Update deps
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Sat, 21 Nov 2020 11:08:06 +0000
squeekboard (1.11.0) amber-phone; urgency=medium
[ Dorota Czaplejewicz ]
* UI: Delay hiding only when leaving a text field
* ui: Cancel hiding delay when activity requested again
* Update dependencies
[ Fabio Tomat ]
* Update fur-IT.txt fix typo for Spanish
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Sat, 14 Nov 2020 06:46:28 +0000
squeekboard (1.10.0) amber-phone; urgency=medium
[ Dorota Czaplejewicz ]
* virtual_keyboard: Fix desynced modifiers state
* rust: Fix deprecation warnings
* docs: Tutorial syntax cleanups
* docs: Reorganize tutorial
* build: Error on repeating declarations
* keymap: Generate from symbol map, not layout
* data: Restore testability of action->keysym conversion
* syntax: Let older rustc understand symbolmap's lifetime
* debian: Insert a "breaks" for librem5-base < 24
* keymap: Keep keymap fd management in one place
* vkeyboard: Use a generic slice instead of a vector
* tests: Check for missing return in builtin layouts except emoji
* keymap: Concentrate special handling of BackSpace, which is implicit in Erase action
* keymaps: Use multiple key maps, each within the limit of what Xorg can accept.
* build: Avoid MaybeUninit on older Debian
* tests: Fix bad field access
* cargo: Update dependencies
[ Guido Günther ]
* eekboard-context-service: Return early if schema is unavailable
* treewide: Use new style function definitions
* build: Enable '-Wold-style-definition' '-Wstrict-prototypes'
* build: Enable '-Wunused-function'
* eekboard-context-service: Drop EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE
* keyboard: Fix warning
* layout: Fix warning
* gitlab-ci: Enable --Werror
* eek-keyboard: Don't ignore return value
* build: Enable -Winit-self
* build: Enable -Wformat-security
* build: Enable -Wmaybe-uninitialized
* treewide: Drop redundant declarations
* build: Enable -Wredundant-declarations
* ServerContextService: Drop GObject boilerplate
* build: Enable '-Wformat-nonliteral'
* eekboad-context-service: Drop signal class handler
* eekboard-context-service: Drop docstrings for inexistent functions
* eekboard-context-service: Drop the GObject boilerplate
* eekboard-context-service: Drop private struct
* server-context-service: Consistenty name self argument 'self'
* server-context-service: swap signal arguments
* server-context-service: Don't show keyboard when disabled (Closes: #222)
[ Nazarii Kretovych ]
* Add Ukrainian keyboard layout.
[ Benjamin Schaaf ]
* Fix spelling mistakes in doc/hacking.md
* Expand the development documentation in the readme
* Expand key press detection to the edges of the view's bounding box
* Sort layouts by type before sorting by name
* Fix leak in level_keyboard_new
* Fix leak endlessly adding a resource path to the default theme
* Add settings option to popover
[ Al ]
* proposal for belgian layout (copy of fr)
* alphabetical order for src/resources.rs tests/meson.build
[ Arnaud Ferraris ]
* eek-gtk-keyboard: use virtual resolution to check arrangement kind
* server-context-service: optimize height calculation
* keyboards: add wide French layout
* keyboards: add wide Belgian layout
* keyboards: add wide terminal layout
[ Fabio Tomat ]
* Revert "Add friulian keyboard"
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Mon, 19 Oct 2020 14:07:01 +0000
squeekboard (1.9.3) amber-phone; urgency=medium
[ Björn Tantau ]

View File

@ -5,7 +5,6 @@ Feed it the first changelog line, and then all available tags.
"""
import re, sys
version = re.findall("\\((.*)\\)", input())[0]
tag = 'v' + re.findall("([0-9]+\\.[0-9]+\\.[0-9]+).*", version)[0]
tag = "v" + re.findall("\\((.*)\\)", input())[0]
if tag not in map(str.strip, sys.stdin.readlines()):
raise Exception("Changelog's current version doesn't have a tag. Push the tag!")

1
debian/control vendored
View File

@ -26,7 +26,6 @@ Build-Depends:
librust-xkbcommon-0.4+wayland-dev (>= 0.4),
libwayland-dev (>= 1.16),
lsb-release,
python3,
rustc,
wayland-protocols (>= 1.14),
Standards-Version: 4.1.3

21
debian/rules vendored
View File

@ -2,27 +2,6 @@
export CARGO_HOME = $(CURDIR)/debian/cargo
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
# the below avoids an FTBFS on mips64el with a GOT > 64kb
DEB_HOST_ARCH := $(shell dpkg-architecture -qDEB_HOST_ARCH)
ifeq ($(DEB_HOST_ARCH),mips64el)
export RUSTFLAGS = -Ctarget-feature=+xgot
endif
# the below avoids an FTBFS on mips64el with a GOT > 64kb
DEB_HOST_ARCH := $(shell dpkg-architecture -qDEB_HOST_ARCH)
ifeq ($(DEB_HOST_ARCH),mips64el)
xgot = -Ctarget-feature=+xgot
else
xgot =
endif
# Don't use paths that may change between builds.
# No need to care about $HOME
# because Cargo will not place any source in ~/.cargo.
# The build directory is a subdirectory of the source directory,
# so it doesn't need to be explicitly taken care of.
export RUSTFLAGS = --remap-path-prefix=$(CURDIR)=/remap-pwd $(xgot)
distrel := $(shell lsb_release --codename --short)
ifneq (,$(filter $(distrel),buster amber))

View File

@ -113,7 +113,7 @@ User interface modules should:
Code submitted should roughly match the style of surrounding code. Things that will *not* be accepted are ones that often lead to errors:
- skipping brackets `{}` after every `if()`, `else`, and similar ([SCI CERT C: EXP19-C](https://wiki.sei.cmu.edu/confluence/display/c/EXP19-C.+Use+braces+for+the+body+of+an+if%2C+for%2C+or+while+statement))
- skipping brackets `{}` after every `if()`, `else`, and similar
Bad example:
@ -179,10 +179,7 @@ Dependencies must be specified in `Cargo.toml` with 2 numbers: "major.minor". Si
```
cd build_dir
ninja ./Cargo.toml
ninja build src/Cargo.toml
sh /source_path/cargo.sh update
ninja test
cp ./Cargo.lock /source_path/
```
Since version 1.9.3, `Cargo.lock` is not actually used by the build system, due to `Cargo.toml` being generated at every build.

View File

@ -6,7 +6,6 @@ Contents
* [Tutorial](tutorial.md)
* [Contributing](hacking.md)
* [Switching views](views.md)
Introduction
------------
@ -22,8 +21,6 @@ Layouts are created using a text-based format, based on YAML.
TODO: Provide a description of the format.
Squeekboard layouts are separated into *views* and use a *room metaphor* to [switch views](views.md).
Contributions
-------------

View File

@ -1,594 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="177.92439mm"
height="88.144363mm"
viewBox="0 0 177.92439 88.144364"
version="1.1"
id="svg8"
sodipodi:docname="latching.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<defs
id="defs2">
<marker
style="overflow:visible"
id="Arrow1Lend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Mend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Mend"
inkscape:isstock="true">
<path
transform="matrix(-0.4,0,0,-0.4,-4,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1098" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Sstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart"
inkscape:isstock="true">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1119" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Mstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart"
inkscape:isstock="true">
<path
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1113" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-5" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect848" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect848-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-9" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect848-8" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect916" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-4" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect951" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect986" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect1061" />
<marker
style="overflow:visible"
id="Arrow1Lend-5"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#00ad12;fill-opacity:1;fill-rule:evenodd;stroke:#00ad12;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-7" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect1549" />
<marker
style="overflow:visible"
id="Arrow1Lend-8"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#101010;fill-opacity:1;fill-rule:evenodd;stroke:#101010;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-8" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-3" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect1845" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-38" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect1960" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-3-9" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect2304" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-3-4" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect2304-7" />
<marker
style="overflow:visible"
id="Arrow1Lend-2"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:#6c6c6c;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-89" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Lend-2-6"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#00ad12;fill-opacity:1;fill-rule:evenodd;stroke:#00ad12;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-89-8" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-21" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect2574" />
<marker
style="overflow:visible"
id="Arrow1Lend-2-6-1"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#00ad12;fill-opacity:1;fill-rule:evenodd;stroke:#00ad12;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-89-8-0" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Lend-2-6-6"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#00ad12;fill-opacity:1;fill-rule:evenodd;stroke:#00ad12;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-89-8-2" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10-1-8" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect3021" />
<marker
style="overflow:visible"
id="Arrow1Lend-8-3"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#101010;fill-opacity:1;fill-rule:evenodd;stroke:#101010;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-8-5" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.3358025"
inkscape:cx="212.63846"
inkscape:cy="105.21093"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
fit-margin-top="4"
fit-margin-left="4"
fit-margin-right="4"
fit-margin-bottom="4"
lock-margins="true"
inkscape:window-width="1298"
inkscape:window-height="708"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-72.097892,-53.326191)">
<path
style="fill:none;fill-rule:evenodd;stroke:#101010;stroke-width:0.264999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-8-3)"
d="m 134.9616,86.141869 c 17.5759,-11.622767 35.93283,0 35.93283,0"
id="path1087-1-6" />
<g
id="g2948">
<circle
style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1065-6"
cx="129.67093"
cy="92.793152"
r="7.8844509" />
<text
xml:space="preserve"
id="text833-0"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(46.071199,-1.2662626)"><tspan
x="80.886719"
y="96.225952"><tspan>A</tspan></tspan></text>
</g>
<rect
style="color:#000000;overflow:visible;fill:#f8f8f8;fill-opacity:1;stroke:#000000;stroke-width:0.555679;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect2066"
width="1.4562259"
height="10.90563"
x="81.767418"
y="75.519585"
ry="0.9693895" />
<g
id="g905"
transform="translate(0,-0.85044703)">
<circle
style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1065"
cx="83.154755"
cy="93.6436"
r="7.8844509" />
<text
xml:space="preserve"
id="text833"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none">a</tspan></tspan></text>
</g>
<g
id="g905-3-7"
transform="translate(92.82116,-0.85044861)">
<circle
style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1065-6-7"
cx="83.557831"
cy="93.6436"
r="7.8844509" />
<text
xml:space="preserve"
id="text833-0-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10-1);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan>Ą</tspan></tspan></text>
</g>
<g
id="g905-1"
transform="translate(68.838914,-17.67039)">
<rect
style="color:#000000;overflow:visible;fill:#e2e2e2;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-8"
width="10.583333"
height="13.79613"
x="78.878532"
y="85.920006"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-7"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.2686286,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan> ̨̂ ̈</tspan></tspan></text>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#101010;stroke-width:0.264999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-8)"
d="m 88.446425,85.89509 c 17.575895,-11.622767 35.932835,0 35.932835,0"
id="path1087-1" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="99.186691"
y="66.221436"
id="text1035-89"><tspan
sodipodi:role="line"
id="tspan1033-6"
x="99.186691"
y="66.221436"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">locking</tspan></text>
<g
id="g905-1-4"
transform="translate(22.423434,-17.67039)">
<rect
style="color:#000000;overflow:visible;fill:#e2e2e2;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-8-3"
width="10.583333"
height="13.79613"
x="78.878532"
y="85.920006"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-7-3"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2-3);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan></tspan></tspan></text>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.5, 0.5;stroke-dashoffset:0;stroke-opacity:1"
d="m 83.251484,76.550079 c -0.31498,0 -0.944941,-0.314981 -0.944941,0 0,0.31498 0.770221,0.262079 0.944941,0 0.212555,-0.318834 0.08197,-0.862973 -0.188988,-1.133929 -0.132651,-0.13265 -1.931144,0.354037 -2.078869,0.944941 -0.108038,0.432149 0.877467,-0.188989 1.322916,-0.188989 0.339244,0 0.626121,0.262042 0.944941,0.377977 0.374434,0.136158 0.777569,0.199796 1.133928,0.377976 0.113894,0.05695 -0.0037,0.439732 0.944941,0.755952 0.544156,0.181385 1.78847,0.275251 2.267857,0.377976 0.448438,0.09609 0.881944,0.251984 1.322917,0.377977 0.063,0.188988 0.388199,0.566964 0.188988,0.566964 -0.195153,0 -0.745291,-0.93961 0,-0.566964 0.281726,0.140863 0.485859,0.404908 0.755952,0.566964 1.460327,0.876196 3.039871,1.714659 4.346726,2.834821 0.966187,0.828161 1.495207,2.006597 2.645833,2.645834 2.876101,1.597834 5.000414,0.287454 7.370534,1.133929 0.4783,0.170821 0.85136,0.567325 1.32292,0.755952 1.8557,0.74228 0.94424,0.230907 2.26785,0.377976 1.47287,0.16365 2.67387,1.06159 4.15774,0.566965 1.22233,-0.407443 3.2674,-1.377519 4.15774,-2.267858 0.39842,-0.398422 0.42845,-1.053404 0.75595,-1.511905 0.50136,-0.70189 1.27041,-1.107171 1.7009,-1.889881 2.28615,-4.156632 0.41931,-1.931216 3.2128,-4.724702 0.18898,-0.188988 0.33491,-0.434362 0.56696,-0.566964 0.864,-0.493714 5.11938,-0.281812 6.04762,-0.188989 0.34449,0.03445 3.71968,0.978261 3.96875,1.133929 0.35339,0.220868 1.41179,1.650838 1.88988,1.889881 0.80324,0.40162 2.22057,0.354332 3.02381,0.755952 1.24832,0.624162 -0.45041,0.669376 -0.18899,1.322917 0.1193,0.298244 0.64418,0.0762 0.94494,0.188988 0.28702,0.107634 1.48279,1.113549 1.5119,1.133929 2.56034,1.792236 -0.96522,-0.855663 2.26786,1.133928 1.61516,0.993946 2.82802,2.547938 4.53572,3.401785 2.03418,1.017093 4.38487,-0.122885 6.42559,-0.377975 1.6791,-0.209886 3.23813,0.06137 4.91369,-0.566965 0.50424,-0.18909 1.82709,-1.701063 2.26786,-2.078869 0.45926,-0.393653 1.0853,-0.707329 1.5119,-1.133928 0.81561,-0.815609 1.44764,-1.826091 2.45685,-2.456845 0.28768,-0.179799 0.65726,-0.198178 0.94494,-0.377977 0.28791,-0.179945 0.60349,-0.774216 0.94494,-0.94494 0.23232,-0.116159 0.51479,-0.09252 0.75595,-0.188988 0.21089,-0.08436 0.33983,-0.377976 0.56697,-0.377976 0.14086,0 0.23711,0.188988 0.37797,0.188988 0.0891,0 0.126,-0.125992 0.18899,-0.188988 0.18899,-0.063 0.36976,-0.217161 0.56696,-0.188988 0.77174,0.110248 1.92711,0.94494 3.02381,0.94494 0.16785,0 0.94189,-0.862638 1.13393,-0.94494 0.19546,-0.08377 1.57981,-0.364523 1.7009,-0.377977 0.72233,-0.08026 2.11645,0.340388 2.64583,-0.188988"
id="path2010" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;line-height:125%;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="73.802078"
y="72.354546"
id="text2091"><tspan
sodipodi:role="line"
id="tspan2089"
x="73.802078"
y="72.354546"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">SAVED</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;line-height:125%;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="164.55956"
y="72.354546"
id="text2091-8"><tspan
sodipodi:role="line"
id="tspan2089-8"
x="164.55956"
y="72.354546"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">CURRENT</tspan><tspan
sodipodi:role="line"
x="164.55956"
y="79.410095"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
id="tspan3432" /></text>
<g
id="g2259"
transform="matrix(1.0856157,0,0,0.94777147,-19.677062,6.4360598)">
<path
id="rect2111-9"
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 179.53502,72.72924 h 5.84717 l -1.37074,1.931346 h -3.04292 z"
sodipodi:nodetypes="ccccc" />
<path
id="rect2111-9-0"
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 179.4049,80.846668 h 5.84717 l -1.23711,-1.931347 h -3.17655 z"
sodipodi:nodetypes="ccccc" />
<g
id="g2247"
transform="translate(-0.04032786,-0.04319387)">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,75.343053 2.96688,-0.19452"
id="path2145"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,76.112065 2.96688,-0.19452"
id="path2145-3"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,76.881078 2.96688,-0.19452"
id="path2145-0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,77.65009 2.96688,-0.19452"
id="path2145-2"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,78.419102 2.96688,-0.19452"
id="path2145-4"
sodipodi:nodetypes="cc" />
</g>
</g>
<g
id="g905-0"
transform="translate(157.32586,-0.83970203)" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="145.70187"
y="66.221436"
id="text1035-89-2"><tspan
sodipodi:role="line"
id="tspan1033-6-9"
x="145.70187"
y="66.221436"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">locking</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@ -1,631 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="169.9455mm"
height="98.072433mm"
viewBox="0 0 169.94549 98.072434"
version="1.1"
id="svg8"
sodipodi:docname="latching_return.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<defs
id="defs2">
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10-1" />
<marker
style="overflow:visible"
id="Arrow1Lend-5"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-7" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-38" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-3-9" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-3-4" />
<marker
style="overflow:visible"
id="Arrow1Lend-2-6"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-89-8" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-21" />
<marker
style="overflow:visible"
id="Arrow1Lend-2-6-1"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-89-8-0" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Lend-2-6-6"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-89-8-2" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10-1-8" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-12" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10-7" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.94455498"
inkscape:cx="314.8465"
inkscape:cy="213.42055"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
fit-margin-top="4"
fit-margin-left="4"
fit-margin-right="4"
fit-margin-bottom="4"
lock-margins="true"
inkscape:window-width="1298"
inkscape:window-height="708"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
showguides="false" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-70.551731,-46.47634)">
<g
id="g3858"
transform="translate(1.354821,1.4005714)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="204.75821"
y="130.07979"
id="text2293-4"><tspan
sodipodi:role="line"
id="tspan2291-1"
x="204.75821"
y="130.07979"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="194.54915"
y="128.70164"
id="text2293-0-5-8"><tspan
sodipodi:role="line"
id="tspan2291-6-7-5"
x="194.54915"
y="128.70164"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">cuts</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529167;stroke-dashoffset:0;stroke-opacity:1"
d="m 210.34971,123.9389 c 0.0233,0.14006 0.07,0.27818 0.07,0.42017 0,0.0738 -0.07,0.13627 -0.07,0.21009 0,0.11902 0.0582,0.23171 0.07,0.35014 0.049,0.49035 0.0857,0.98109 0.14006,1.4706 0.018,0.1624 -0.0269,0.32902 0,0.4902 0.0435,0.26077 0.11166,0.3369 0,0.56023 -0.0209,0.0418 0.033,0.10705 0,0.14006 -0.0369,0.0369 -0.10315,0.0331 -0.14006,0.07"
id="path3816-9" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529167;stroke-dashoffset:0;stroke-opacity:1"
d="m 209.9819,128.43627 c -0.12445,0.48957 -0.1295,0.98859 -0.0743,1.48553 0.0118,0.10583 0.01,0.21643 0.0248,0.32186 -0.002,0.0627 0.0396,0.11405 0.0495,0.17332 0.0144,0.0866 -0.0193,0.077 0,0.17331 0.0124,0.0621 0.20619,0.18971 0.24759,0.22283"
id="path3820-7" />
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Lend-2-6-1)"
d="m 180.7405,85.345284 c 21.77006,-11.52723 44.50758,0 44.50758,0"
id="path1087-3-0-8" />
<rect
style="color:#000000;overflow:visible;fill:#f8f8f8;fill-opacity:1;stroke:#000000;stroke-width:0.555679;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect2066"
width="1.4562259"
height="10.90563"
x="81.767418"
y="75.519585"
ry="0.9693895" />
<g
id="g905-3-7"
transform="translate(92.629263,-0.8504468)">
<text
xml:space="preserve"
id="text833-0-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10-1);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan>Ą</tspan></tspan></text>
<rect
style="color:#000000;overflow:visible;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-4-9"
width="10.583333"
height="13.79613"
x="78.266167"
y="86.745537"
ry="1.937705" />
</g>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:0.4em;font-family:monospace;-inkscape-font-specification:monospace;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="174.86499"
y="130.79413"
id="text1035-8"><tspan
sodipodi:role="line"
x="174.86499"
y="130.79413"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
id="tspan2277">locking</tspan><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
sodipodi:role="line"
x="174.86499"
y="135.11462"
id="tspan1606" /></text>
<g
id="g905-1-6"
transform="translate(90.668095,26.90725)">
<rect
style="color:#000000;overflow:visible;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-8-0"
width="10.583333"
height="13.79613"
x="78.878532"
y="85.920006"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-7-4"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2-38);fill:#f8f8f8;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.2686286,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan
style="fill:#f8f8f8;fill-opacity:1"> ̨̂ ̈</tspan></tspan></text>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.5, 0.5;stroke-dashoffset:0;stroke-opacity:1"
d="m 83.251484,76.550079 c -0.31498,0 -0.944941,-0.314981 -0.944941,0 0,0.31498 0.770221,0.262079 0.944941,0 0.212555,-0.318834 0.08197,-0.862973 -0.188988,-1.133929 -0.132651,-0.13265 -1.931144,0.354037 -2.078869,0.944941 -0.108038,0.432149 0.877467,-0.188989 1.322916,-0.188989 0.339244,0 0.626121,0.262042 0.944941,0.377977 0.374434,0.136158 0.777569,0.199796 1.133928,0.377976 0.113894,0.05695 -0.0037,0.439732 0.944941,0.755952 0.544156,0.181385 1.78847,0.275251 2.267857,0.377976 0.448438,0.09609 0.881944,0.251984 1.322917,0.377977 0.063,0.188988 0.388199,0.566964 0.188988,0.566964 -0.195153,0 -0.745291,-0.93961 0,-0.566964 0.281726,0.140863 0.485859,0.404908 0.755952,0.566964 1.460327,0.876196 3.039871,1.714659 4.346726,2.834821 0.966187,0.828161 1.495207,2.006597 2.645833,2.645834 2.876101,1.597834 5.000414,0.287454 7.370534,1.133929 0.4783,0.170821 0.85136,0.567325 1.32292,0.755952 1.8557,0.74228 0.94424,0.230907 2.26785,0.377976 1.47287,0.16365 2.67387,1.06159 4.15774,0.566965 1.22233,-0.407443 3.2674,-1.377519 4.15774,-2.267858 0.39842,-0.398422 0.42845,-1.053404 0.75595,-1.511905 0.50136,-0.70189 1.27041,-1.107171 1.7009,-1.889881 2.28615,-4.156632 0.41931,-1.931216 3.2128,-4.724702 0.18898,-0.188988 0.33491,-0.434362 0.56696,-0.566964 0.864,-0.493714 5.11938,-0.281812 6.04762,-0.188989 0.34449,0.03445 3.71968,0.978261 3.96875,1.133929 0.35339,0.220868 1.41179,1.650838 1.88988,1.889881 0.80324,0.40162 2.22057,0.354332 3.02381,0.755952 1.24832,0.624162 -0.45041,0.669376 -0.18899,1.322917 0.1193,0.298244 0.64418,0.0762 0.94494,0.188988 0.28702,0.107634 1.48279,1.113549 1.5119,1.133929 2.56034,1.792236 -0.96522,-0.855663 2.26786,1.133928 1.61516,0.993946 2.82802,2.547938 4.53572,3.401785 2.03418,1.017093 4.38487,-0.122885 6.42559,-0.377975 1.6791,-0.209886 3.23813,0.06137 4.91369,-0.566965 0.50424,-0.18909 1.82709,-1.701063 2.26786,-2.078869 0.45926,-0.393653 1.0853,-0.707329 1.5119,-1.133928 0.81561,-0.815609 1.44764,-1.826091 2.45685,-2.456845 0.28768,-0.179799 0.65726,-0.198178 0.94494,-0.377977 0.28791,-0.179945 0.60349,-0.774216 0.94494,-0.94494 0.23232,-0.116159 0.51479,-0.09252 0.75595,-0.188988 0.21089,-0.08436 0.33983,-0.377976 0.56697,-0.377976 0.14086,0 0.23711,0.188988 0.37797,0.188988 0.0891,0 0.126,-0.125992 0.18899,-0.188988 0.18899,-0.063 0.36976,-0.217161 0.56696,-0.188988 0.77174,0.110248 1.92711,0.94494 3.02381,0.94494 0.16785,0 0.94189,-0.862638 1.13393,-0.94494 0.19546,-0.08377 1.57981,-0.364523 1.7009,-0.377977 0.72233,-0.08026 2.11645,0.340388 2.64583,-0.188988"
id="path2010" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;line-height:125%;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="74.331245"
y="71.825378"
id="text2091"><tspan
sodipodi:role="line"
id="tspan2089"
x="74.331245"
y="71.825378"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">SAVED</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;line-height:125%;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="164.23172"
y="70.186089"
id="text2091-8"><tspan
sodipodi:role="line"
id="tspan2089-8"
x="164.23172"
y="70.186089"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">CURRENT</tspan><tspan
sodipodi:role="line"
x="164.23172"
y="77.241638"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
id="tspan3432" /></text>
<g
id="g2259"
transform="matrix(1.0856157,0,0,0.94777147,-20.206229,4.319393)">
<path
id="rect2111-9"
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 179.53502,72.72924 h 5.84717 l -1.37074,1.931346 h -3.04292 z"
sodipodi:nodetypes="ccccc" />
<path
id="rect2111-9-0"
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 179.4049,80.846668 h 5.84717 l -1.23711,-1.931347 h -3.17655 z"
sodipodi:nodetypes="ccccc" />
<g
id="g2247"
transform="translate(-0.04032786,-0.04319387)">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,75.343053 2.96688,-0.19452"
id="path2145"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,76.112065 2.96688,-0.19452"
id="path2145-3"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,76.881078 2.96688,-0.19452"
id="path2145-0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,77.65009 2.96688,-0.19452"
id="path2145-2"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,78.419102 2.96688,-0.19452"
id="path2145-4"
sodipodi:nodetypes="cc" />
</g>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Lend-5)"
d="m 173.01207,99.691217 c 0,0 -8.37295,13.367043 -0.26038,13.813423 9.36786,0.51544 7.89797,-9.16673 6.50059,-13.41252"
id="path2269"
sodipodi:nodetypes="csc" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="176.93353"
y="138.21815"
id="text2293"><tspan
sodipodi:role="line"
id="tspan2291"
x="176.93353"
y="138.21815"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"></tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Lend-2-6)"
d="m 181.46685,99.71436 c 21.61425,11.51564 44.18902,0 44.18902,0"
id="path1087-3-0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="195.7271"
y="122.96945"
id="text1035-89-7"><tspan
sodipodi:role="line"
id="tspan1033-6-5"
x="195.7271"
y="122.96945"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">set_view</tspan></text>
<g
id="g905-1-4-4"
transform="translate(120.23594,18.477932)">
<rect
style="color:#000000;overflow:visible;fill:#e2e2e2;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-8-3-8"
width="10.583333"
height="13.79613"
x="78.878532"
y="85.920006"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-7-3-1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2-3-4);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan></tspan></tspan></text>
</g>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:0.36em;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="196.99921"
y="61.359337"
id="text1035-89-4"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
sodipodi:role="line"
id="tspan3987"
x="196.99921"
y="61.359337">locking</tspan><tspan
sodipodi:role="line"
x="196.99921"
y="65.362335"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
id="tspan3985">pops: false</tspan></text>
<g
id="g905-1-4-9"
transform="translate(120.23594,-18.828317)">
<rect
style="color:#000000;overflow:visible;fill:#e2e2e2;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-8-3-2"
width="10.583333"
height="13.79613"
x="78.878532"
y="85.920006"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-7-3-2"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2-3-9);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan></tspan></tspan></text>
</g>
<g
id="g905-0"
transform="translate(147.8008,-0.83970203)">
<rect
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-5"
width="10.583333"
height="13.79613"
x="77.863091"
y="86.745537"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-21);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan>ą</tspan></tspan></text>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Lend-2-6-6)"
d="m 170.49256,99.691217 c -49.40563,31.667983 -82.046134,0 -82.046134,0"
id="path1087-3-0-5"
sodipodi:nodetypes="cc" />
<g
id="g905-3-7-6"
transform="translate(45.925334,26.134402)">
<rect
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-4-9-8"
width="10.583333"
height="13.79613"
x="78.266167"
y="86.745537"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-0-5-2"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10-1-8);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan>Ą</tspan></tspan></text>
</g>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:0.4em;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="129.60217"
y="131.30838"
id="text1035-8-4"><tspan
sodipodi:role="line"
x="129.60217"
y="131.30838"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
id="tspan2277-2">text</tspan><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
sodipodi:role="line"
x="129.60217"
y="135.62888"
id="tspan1606-4" /></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.58611px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="123.67847"
y="136.8163"
id="text2293-0"><tspan
sodipodi:role="line"
id="tspan2291-6"
x="123.67847"
y="136.8163"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.58611px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">returns</tspan></text>
<g
id="g905"
transform="translate(1.1299757e-7,-0.85044747)">
<circle
style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1065"
cx="83.154755"
cy="93.6436"
r="7.8844509" />
<text
xml:space="preserve"
id="text833"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-12);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none">a</tspan></tspan></text>
</g>
<g
id="g2948">
<circle
style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1065-6"
cx="129.67093"
cy="92.793152"
r="7.8844509" />
<text
xml:space="preserve"
id="text833-0"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10-7);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(46.071199,-1.2662626)"><tspan
x="80.886719"
y="96.225952"><tspan>A</tspan></tspan></text>
</g>
<g
id="g2259-3"
transform="matrix(0.61171471,0,0,0.53404326,8.8050741,94.418409)">
<path
id="rect2111-9-1"
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 179.53502,72.72924 h 5.84717 l -1.37074,1.931346 h -3.04292 z"
sodipodi:nodetypes="ccccc" />
<path
id="rect2111-9-0-7"
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 179.4049,80.846668 h 5.84717 l -1.23711,-1.931347 h -3.17655 z"
sodipodi:nodetypes="ccccc" />
<g
id="g2247-5"
transform="translate(-0.04032786,-0.04319387)">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,75.343053 2.96688,-0.19452"
id="path2145-9"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,76.112065 2.96688,-0.19452"
id="path2145-3-6"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,76.881078 2.96688,-0.19452"
id="path2145-0-2"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,77.65009 2.96688,-0.19452"
id="path2145-2-1"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,78.419102 2.96688,-0.19452"
id="path2145-4-7"
sodipodi:nodetypes="cc" />
</g>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.265;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.06, 0.53;stroke-dashoffset:0;stroke-opacity:1"
d="m 119.51485,135.86385 c -0.50656,0.62998 -2.26796,0.26701 -2.85105,0.85011 -0.52314,0.52314 2.02401,2.4426 3.96141,3.16913 2.94083,1.1028 4.79827,0.22 7.72476,-0.19807 0.3268,-0.0467 0.66473,0.0543 0.99035,0 1.72749,-0.28792 3.39512,-0.79539 5.14984,-0.99036 1.10207,-0.12245 0.49735,0.0622 1.58457,0.19807 0.91825,0.11479 1.8542,0.0832 2.77299,0.19807 0.86919,0.10865 1.70964,-0.19807 2.57492,-0.19807"
id="path3796" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="166.72447"
y="136.84001"
id="text2293-0-5"><tspan
sodipodi:role="line"
id="tspan2291-6-7"
x="166.72447"
y="136.84001"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">cuts</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529166;stroke-dashoffset:0;stroke-opacity:1"
d="m 182.52503,132.07727 c 0.0233,0.14006 0.07,0.27818 0.07,0.42017 0,0.0738 -0.07,0.13627 -0.07,0.21009 0,0.11902 0.0582,0.23171 0.07,0.35014 0.049,0.49035 0.0857,0.98109 0.14006,1.4706 0.018,0.1624 -0.0269,0.32902 0,0.4902 0.0435,0.26077 0.11166,0.3369 0,0.56023 -0.0209,0.0418 0.033,0.10705 0,0.14006 -0.0369,0.0369 -0.10315,0.0331 -0.14006,0.07"
id="path3816" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529166;stroke-dashoffset:0;stroke-opacity:1"
d="m 182.15722,136.57464 c -0.12445,0.48957 -0.1295,0.98859 -0.0743,1.48553 0.0118,0.10583 0.01,0.21643 0.0248,0.32186 -0.002,0.0627 0.0396,0.11405 0.0495,0.17332 0.0144,0.0866 -0.0193,0.077 0,0.17331 0.0124,0.0621 0.20619,0.18971 0.24759,0.22283"
id="path3820" />
<g
id="g3858-9"
transform="translate(1.354821,-73.436839)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="204.75821"
y="130.07979"
id="text2293-4-6"><tspan
sodipodi:role="line"
id="tspan2291-1-4"
x="204.75821"
y="130.07979"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="194.54915"
y="128.70164"
id="text2293-0-5-8-3"><tspan
sodipodi:role="line"
id="tspan2291-6-7-5-3"
x="194.54915"
y="128.70164"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">cuts</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529167;stroke-dashoffset:0;stroke-opacity:1"
d="m 210.34971,123.9389 c 0.0233,0.14006 0.07,0.27818 0.07,0.42017 0,0.0738 -0.07,0.13627 -0.07,0.21009 0,0.11902 0.0582,0.23171 0.07,0.35014 0.049,0.49035 0.0857,0.98109 0.14006,1.4706 0.018,0.1624 -0.0269,0.32902 0,0.4902 0.0435,0.26077 0.11166,0.3369 0,0.56023 -0.0209,0.0418 0.033,0.10705 0,0.14006 -0.0369,0.0369 -0.10315,0.0331 -0.14006,0.07"
id="path3816-9-3" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529167;stroke-dashoffset:0;stroke-opacity:1"
d="m 209.9819,128.43627 c -0.12445,0.48957 -0.1295,0.98859 -0.0743,1.48553 0.0118,0.10583 0.01,0.21643 0.0248,0.32186 -0.002,0.0627 0.0396,0.11405 0.0495,0.17332 0.0144,0.0866 -0.0193,0.077 0,0.17331 0.0124,0.0621 0.20619,0.18971 0.24759,0.22283"
id="path3820-7-8" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 39 KiB

View File

@ -1,386 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="70.905495mm"
height="78.260262mm"
viewBox="0 0 70.905494 78.260262"
version="1.1"
id="svg8"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
sodipodi:docname="switching.svg">
<defs
id="defs2">
<marker
style="overflow:visible"
id="Arrow1Lend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Mend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Mend"
inkscape:isstock="true">
<path
transform="matrix(-0.4,0,0,-0.4,-4,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1098" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Sstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart"
inkscape:isstock="true">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1119" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Mstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart"
inkscape:isstock="true">
<path
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1113" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-5" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect848" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect848-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-9" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect848-8" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect916" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-4" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect951" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect986" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect1061" />
<marker
style="overflow:visible"
id="Arrow1Lend-5"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-7" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect1549" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="136.49044"
inkscape:cy="110.83537"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
fit-margin-top="4"
fit-margin-left="4"
fit-margin-right="4"
fit-margin-bottom="4"
lock-margins="true"
inkscape:window-width="1298"
inkscape:window-height="708"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-70.899889,-58.974186)">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.265;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
d="m 88.446426,85.895089 c 17.575894,-11.622767 35.932844,0 35.932844,0"
id="path1087" />
<g
id="g905"
transform="translate(0,-0.85044703)">
<circle
style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1065"
cx="83.03434"
cy="93.834679"
r="7.8844509" />
<text
xml:space="preserve"
id="text833"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.16231537,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none">a</tspan></tspan></text>
</g>
<g
id="g905-3"
transform="translate(46.113101,-0.85044703)">
<circle
style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1065-3"
cx="83.557831"
cy="93.366959"
r="7.8844509" />
<text
xml:space="preserve"
id="text833-0"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan>A</tspan></tspan></text>
</g>
<g
id="g905-7"
transform="translate(-0.94494048,73.232887)">
<text
xml:space="preserve"
id="text833-6"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-4);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan>ą</tspan></tspan></text>
<rect
style="color:#000000;overflow:visible;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-3"
width="10.583333"
height="13.79613"
x="77.863091"
y="86.745537"
ry="1.937705" />
</g>
<g
id="g905-3-7"
transform="translate(49.136911,68.319196)">
<text
xml:space="preserve"
id="text833-0-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10-1);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan>Ą</tspan></tspan></text>
<rect
style="color:#000000;overflow:visible;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-4-9"
width="10.583333"
height="13.79613"
x="78.266167"
y="86.745537"
ry="1.937705" />
</g>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="90.548096"
y="65.654472"
id="text1035"><tspan
sodipodi:role="line"
id="tspan1033"
x="90.548096"
y="65.654472"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52778px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">set_view: upper</tspan></text>
<g
id="g905-1"
transform="translate(22.423437,-17.670388)">
<rect
style="color:#000000;overflow:visible;fill:#e2e2e2;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-8"
width="10.583333"
height="13.79613"
x="78.878532"
y="85.920006"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-7"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan></tspan></tspan></text>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-5)"
d="m 124.74085,99.691217 c -17.5759,11.622773 -35.932849,0 -35.932849,0"
id="path1087-4" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:0.4em;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="91.116165"
y="123.76147"
id="text1035-8"><tspan
sodipodi:role="line"
id="tspan1033-5"
x="91.116165"
y="123.76147"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">locking</tspan><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
sodipodi:role="line"
id="tspan1604"
x="91.116165"
y="128.08197">lock_view: upper</tspan><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
sodipodi:role="line"
x="91.116165"
y="132.40247"
id="tspan1606">unlock_view: lower</tspan></text>
<g
id="g905-1-9"
transform="translate(22.423437,17.64464)">
<rect
style="color:#000000;overflow:visible;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-8-7"
width="10.583333"
height="13.79613"
x="78.878532"
y="85.920006"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-7-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2-1);fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan
style="fill:#ffffff;fill-opacity:1"></tspan></tspan></text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,64 +0,0 @@
Switching views
=========
Squeekboard layout files are separated into *views*.
What are views?
-------------------
A view is the button arrangement which you see on Squeekboard's panel. The view always spans the entire panel area, so it's not possible to see two views at the same time, even if the layout contains multiple views.
Views are useful because they allow to have many more buttons than would fit on the panel at the same time. That works because views can be switched.
Views are different from layouts: they can be switched without affecting the active language, and without touching the globe button. Layouts cannot share views, so switching layouts *always* switches views.
Switching views
------------------
The model selected for switching views is less similar to "levels" known from physical keyboards, but closer to "rooms", which may resemble a game map.
Buttons don't have states. It's more of a model where each view is a room, and buttons are doors. Switching means moving to the next room, and buttons highlight according to which view/room they lead to or from.
There are two basic kinds of switching buttons: one way (`set_view`), and two way (`locking`). `locking` is the more sophisticated one. When placed inside `lock_view`, it is drawn highlighted, and goes to `unlock view`. When placed inside any other view, it behaves like `set_view`.
![Diagram showing two transitions: from lowercase via `set_view` to uppercase, and back via `locking`](switching.svg) This diagram shows which buttons can switch between two views. Views are shown as circles, and buttons as rounded rectangles.
The two buttons are separate, and visible only in the view *from which the switch starts*. Note that the `locking` button is shown highlighted. That's because it's in `upper` view, which matches its `lock_view`.
Latching
----------
`locking` buttons provide a second mode of operation: latching. It's useful when the target view is needed only for a single button press, like entering a single accent or a single capital letter in Latin scripts.
When a latching button is pressed, the keyboard remembers to come back to the current (source) view, and then the view is switched. If another `locking` button is pressed, the source view stays in memory. If a text button is pressed, the view from memory is shown again, and forgotten.
![Diagram showing the switches needed to travel across 3 views: a→A→Ą, while latching.](latching.svg) In this diagram, the dashed line connects the view the typist is seeing to the view remembered for unlatching.
There are two ways to erase the memory without going back to the remembered view. Pressing the button again will permanently switch to the current view, and `set_view` will permanently switch to its target.
In the room metaphor, it's as if tying a thread inside the room before going through the door to the next one. And another `locking` door while holding the thread. Once the Minotaur is slain (text button pressed), the hero follows the thread back to the starting room.
The typist hero cuts the thread in two circumstances: when staying longer in the current room (press button again), or when moving through a `set_view` door.
![Diagram showing possible ways to stop latching, by staying in Ą, by unlatching back to a, and by moving on to ą view.](latching_return.svg) This diagram shows the possible ways to stop latching. One is by pressing a text button, which takes back to the original view. Another is pressing a locking button which appears highlighted (note that it can be any button, what matters is its `lock_view`). Finally, switching to another view using a button that doesn't keep the latch on forgets latching.
The layout author should pay attention that `set_view`'s lack of latching does not come as a surprise to typists.
Differences from keyboard levels
---------------------------------------
Views are **not** like keyboard levels.
On a physical keyboard, the number of buttons can not change when switching levels. In Squeekboard, they can have any arrangement of buttons you could imagine.
When switching levels on a keyboard, for example by pressing Shift, the key press not only affects the meaning of other keys, but also tells the application that it's pressed down. In Squeekboard, pressing buttons to change layouts *does not* do anything but switch the layout. Pressing the switching button especially *does not* tell the application that it was pressed. (This is the reason Shift and AltGr modifiers are not implemented in Squeekboard.)
Why not use the "views" model?
-------------------------------------
Squeekboard's goal is to support as many scripts as possible, and the author of the initial design doesn't know a whole lot. There are two problems with using the levels metaphor:
Firstly, the levels model assumes that there is a "base" and an "active" level. This does not work well with scripts that have different but equivalent modes of writing. An example is the Kana layout with Katakana and Hiragana, which are both "base".
Both systems could have been combined, but the view switching designer doesn't have enough experience with different scripts to do that. Some scripts may have different non-hierarchical ways to switch character groups (Balinese?), which could make combining hierarchy with free-form switching even harder.
Secondly, when dealing with languages with a hierarchy, we end up with extra work to eliminate nonsensical combinations. With "symbols" and "uppercase" levels, what does it mean to have both engaged? Eliminating that means extra work. Either validating layouts, so that it's not possible to engage "uppercase" from "symbols", or duplicating, so that "uppercase+symbols" is the same as just "symbols". With "accents" in the mix, this could become a challenge to design well.

View File

@ -45,8 +45,6 @@
typedef struct _EekGtkKeyboardPrivate
{
EekRenderer *renderer; // owned, nullable
struct render_geometry render_geometry; // mutable
EekboardContextService *eekboard_context; // unowned reference
struct submission *submission; // unowned reference
@ -74,23 +72,12 @@ eek_gtk_keyboard_real_realize (GtkWidget *self)
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->realize (self);
}
static void set_allocation_size(EekGtkKeyboard *gtk_keyboard,
struct squeek_layout *layout, gdouble width, gdouble height)
{
// This is where size-dependent surfaces would be released
EekGtkKeyboardPrivate *priv =
eek_gtk_keyboard_get_instance_private (gtk_keyboard);
priv->render_geometry = eek_render_geometry_from_allocation_size(
layout, width, height);
}
static gboolean
eek_gtk_keyboard_real_draw (GtkWidget *self,
cairo_t *cr)
{
EekGtkKeyboard *keyboard = EEK_GTK_KEYBOARD (self);
EekGtkKeyboardPrivate *priv =
eek_gtk_keyboard_get_instance_private (keyboard);
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
GtkAllocation allocation;
gtk_widget_get_allocation (self, &allocation);
@ -105,14 +92,15 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
priv->keyboard,
pcontext);
set_allocation_size (keyboard, priv->keyboard->layout,
allocation.width, allocation.height);
eek_renderer_set_allocation_size (priv->renderer,
priv->keyboard->layout,
allocation.width,
allocation.height);
eek_renderer_set_scale_factor (priv->renderer,
gtk_widget_get_scale_factor (self));
}
eek_renderer_render_keyboard (priv->renderer, priv->render_geometry,
priv->submission, cr, priv->keyboard);
eek_renderer_render_keyboard (priv->renderer, priv->submission, cr, priv->keyboard);
return FALSE;
}
@ -129,9 +117,8 @@ static void
eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
GtkAllocation *allocation)
{
EekGtkKeyboard *keyboard = EEK_GTK_KEYBOARD (self);
EekGtkKeyboardPrivate *priv =
eek_gtk_keyboard_get_instance_private (keyboard);
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
// check if the change would switch types
enum squeek_arrangement_kind new_type = get_type(
(uint32_t)(allocation->width - allocation->x),
@ -142,10 +129,11 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
eekboard_context_service_use_layout(priv->eekboard_context, priv->layout, time);
}
if (priv->renderer) {
set_allocation_size (keyboard, priv->keyboard->layout,
allocation->width, allocation->height);
}
if (priv->renderer)
eek_renderer_set_allocation_size (priv->renderer,
priv->keyboard->layout,
allocation->width,
allocation->height);
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->
size_allocate (self, allocation);
@ -173,7 +161,7 @@ static void depress(EekGtkKeyboard *self,
}
squeek_layout_depress(priv->keyboard->layout,
priv->submission,
x, y, priv->render_geometry.widget_to_layout, time, self);
x, y, eek_renderer_get_transformation(priv->renderer), time, self);
}
static void drag(EekGtkKeyboard *self,
@ -185,7 +173,7 @@ static void drag(EekGtkKeyboard *self,
}
squeek_layout_drag(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout,
priv->submission,
x, y, priv->render_geometry.widget_to_layout, time,
x, y, eek_renderer_get_transformation(priv->renderer), time,
priv->eekboard_context, self);
}
@ -196,7 +184,8 @@ static void release(EekGtkKeyboard *self, guint32 time)
return;
}
squeek_layout_release(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout,
priv->submission, priv->render_geometry.widget_to_layout, time,
priv->submission,
eek_renderer_get_transformation(priv->renderer), time,
priv->eekboard_context, self);
}
@ -366,11 +355,10 @@ eek_gtk_keyboard_init (EekGtkKeyboard *self)
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
g_autoptr(GError) err = NULL;
if (lfb_init(SQUEEKBOARD_APP_ID, &err)) {
if (lfb_init(SQUEEKBOARD_APP_ID, &err))
priv->event = lfb_event_new ("button-pressed");
} else {
else
g_warning ("Failed to init libfeedback: %s", err->message);
}
GtkIconTheme *theme = gtk_icon_theme_get_default ();
@ -406,24 +394,6 @@ eek_gtk_keyboard_new (EekboardContextService *eekservice,
priv->submission = submission;
priv->layout = layout;
priv->renderer = NULL;
// This should really be done on initialization.
// Before the widget is allocated,
// we don't really know what geometry it takes.
// When it's off the screen, we also kinda don't.
struct render_geometry initial_geometry = {
// Set to 100 just to make sure if there's any attempt to use it,
// it actually gives plausible results instead of blowing up,
// e.g. on zero division.
.allocation_width = 100,
.allocation_height = 100,
.widget_to_layout = {
.origin_x = 0,
.origin_y = 0,
.scale = 1,
},
};
priv->render_geometry = initial_geometry;
g_signal_connect (eekservice,
"notify::keyboard",
G_CALLBACK(on_notify_keyboard),

View File

@ -28,7 +28,6 @@
#include <glib.h>
#include <gtk/gtk.h>
#include "eek/eek-renderer.h"
#include "eek/eek-types.h"
struct submission;

View File

@ -28,12 +28,19 @@
#include <sys/random.h> // TODO: this is Linux-specific
#include <xkbcommon/xkbcommon.h>
#include "eek-keyboard.h"
/// External linkage for Rust.
/// The corresponding deinit is implemented in vkeyboard::KeyMap::drop
struct keymap squeek_key_map_from_str(const char *keymap_str) {
static void eek_key_map_deinit(struct keymap *self) {
if (self->fd < 0) {
g_error("Deinit called multiple times on KeyMap");
} else {
close(self->fd);
}
self->fd = -1;
}
static struct keymap eek_key_map_from_str(const char *keymap_str) {
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!context) {
g_error("No context created");
@ -42,9 +49,8 @@ struct keymap squeek_key_map_from_str(const char *keymap_str) {
struct xkb_keymap *keymap = xkb_keymap_new_from_string(context, keymap_str,
XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!keymap) {
if (!keymap)
g_error("Bad keymap:\n%s", keymap_str);
}
xkb_context_unref(context);
@ -53,9 +59,8 @@ struct keymap squeek_key_map_from_str(const char *keymap_str) {
g_autofree char *path = strdup("/eek_keymap-XXXXXX");
char *r = &path[strlen(path) - 6];
if (getrandom(r, 6, GRND_NONBLOCK) < 0) {
if (getrandom(r, 6, GRND_NONBLOCK) < 0)
g_error("Failed to get random numbers: %s", strerror(errno));
}
for (unsigned i = 0; i < 6; i++) {
r[i] = (r[i] & 0b1111111) | 0b1000000; // A-z
r[i] = r[i] > 'z' ? '?' : r[i]; // The randomizer doesn't need to be good...
@ -86,6 +91,7 @@ struct keymap squeek_key_map_from_str(const char *keymap_str) {
}
void level_keyboard_free(LevelKeyboard *self) {
eek_key_map_deinit(&self->keymap);
squeek_layout_free(self->layout);
g_free(self);
}
@ -98,5 +104,7 @@ level_keyboard_new (struct squeek_layout *layout)
g_error("Failed to create a keyboard");
}
keyboard->layout = layout;
const gchar *keymap_str = squeek_layout_get_keymap(keyboard->layout);
keyboard->keymap = eek_key_map_from_str(keymap_str);
return keyboard;
}

View File

@ -41,7 +41,7 @@ struct keymap {
/// Keyboard state holder
struct _LevelKeyboard {
struct squeek_layout *layout; // owned
// FIXME: This no longer needs to exist, keymap was folded into layout.
struct keymap keymap; // owned
};
typedef struct _LevelKeyboard LevelKeyboard;

View File

@ -18,6 +18,8 @@
* 02110-1301 USA
*/
#include "config.h"
#include <math.h>
#include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
@ -31,6 +33,10 @@
static void render_button_label (cairo_t *cr, GtkStyleContext *ctx,
const gchar *label, EekBounds bounds);
void eek_render_button (EekRenderer *self,
cairo_t *cr, const struct squeek_button *button,
gboolean pressed, gboolean locked);
static void
render_outline (cairo_t *cr,
GtkStyleContext *ctx,
@ -54,21 +60,21 @@ render_outline (cairo_t *cr,
position.x, position.y, position.width, position.height);
}
/// Rust interface
void eek_render_button_in_context(uint32_t scale_factor,
static void render_button_in_context(gint scale_factor,
cairo_t *cr,
GtkStyleContext *ctx,
EekBounds bounds,
const char *icon_name,
const gchar *label) {
const struct squeek_button *button) {
/* blank background */
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
cairo_paint (cr);
EekBounds bounds = squeek_button_get_bounds(button);
render_outline (cr, ctx, bounds);
cairo_paint (cr);
/* render icon (if any) */
const char *icon_name = squeek_button_get_icon_name(button);
if (icon_name) {
cairo_surface_t *icon_surface =
eek_renderer_get_icon_surface (icon_name, 16, scale_factor);
@ -98,27 +104,25 @@ void eek_render_button_in_context(uint32_t scale_factor,
}
}
const gchar *label = squeek_button_get_label(button);
if (label) {
render_button_label (cr, ctx, label, bounds);
render_button_label (cr, ctx, label, squeek_button_get_bounds(button));
}
}
/// Prepare context for drawing the button.
/// The context MUST be released using the corresponing "put" procedure
/// before drawing the next button.
/// Interface for Rust.
GtkStyleContext *
eek_get_style_context_for_button (EekRenderer *self,
const char *name,
const char *outline_name,
const char *locked_class,
uint64_t pressed)
void
eek_render_button (EekRenderer *self,
cairo_t *cr,
const struct squeek_button *button,
gboolean pressed,
gboolean locked)
{
GtkStyleContext *ctx = self->button_context;
/* Set the name of the button on the widget path, using the name obtained
from the button's symbol. */
g_autoptr (GtkWidgetPath) path = NULL;
path = gtk_widget_path_copy (gtk_style_context_get_path (ctx));
const char *name = squeek_button_get_name(button);
gtk_widget_path_iter_set_name (path, -1, name);
/* Update the style context with the updated widget path. */
@ -127,22 +131,19 @@ eek_get_style_context_for_button (EekRenderer *self,
(pressed) or normal. */
gtk_style_context_set_state(ctx,
pressed ? GTK_STATE_FLAG_ACTIVE : GTK_STATE_FLAG_NORMAL);
if (locked_class) {
gtk_style_context_add_class(ctx, locked_class);
const char *outline_name = squeek_button_get_outline_name(button);
if (locked) {
gtk_style_context_add_class(ctx, "locked");
}
gtk_style_context_add_class(ctx, outline_name);
return ctx;
}
/// Interface for Rust.
void eek_put_style_context_for_button(GtkStyleContext *ctx,
const char *outline_name,
const char *locked_class) {
render_button_in_context(self->scale_factor, cr, ctx, button);
// Save and restore functions don't work if gtk_render_* was used in between
gtk_style_context_set_state(ctx, GTK_STATE_FLAG_NORMAL);
gtk_style_context_remove_class(ctx, outline_name);
if (locked_class) {
gtk_style_context_remove_class(ctx, locked_class);
if (locked) {
gtk_style_context_remove_class(ctx, "locked");
}
}
@ -193,23 +194,22 @@ render_button_label (cairo_t *cr,
// FIXME: Pass just the active modifiers instead of entire submission
void
eek_renderer_render_keyboard (EekRenderer *self,
struct render_geometry geometry,
struct submission *submission,
cairo_t *cr,
LevelKeyboard *keyboard)
{
g_return_if_fail (geometry.allocation_width > 0.0);
g_return_if_fail (geometry.allocation_height > 0.0);
g_return_if_fail (self->allocation_width > 0.0);
g_return_if_fail (self->allocation_height > 0.0);
/* Paint the background covering the entire widget area */
gtk_render_background (self->view_context,
cr,
0, 0,
geometry.allocation_width, geometry.allocation_height);
self->allocation_width, self->allocation_height);
cairo_save(cr);
cairo_translate (cr, geometry.widget_to_layout.origin_x, geometry.widget_to_layout.origin_y);
cairo_scale (cr, geometry.widget_to_layout.scale, geometry.widget_to_layout.scale);
cairo_translate (cr, self->widget_to_layout.origin_x, self->widget_to_layout.origin_y);
cairo_scale (cr, self->widget_to_layout.scale, self->widget_to_layout.scale);
squeek_draw_layout_base_view(keyboard->layout, self, cr);
squeek_layout_draw_all_changed(keyboard->layout, self, cr, submission);
@ -261,6 +261,8 @@ static void
renderer_init (EekRenderer *self)
{
self->pcontext = NULL;
self->allocation_width = 0.0;
self->allocation_height = 0.0;
self->scale_factor = 1;
self->css_provider = squeek_load_style();
@ -287,7 +289,7 @@ eek_renderer_new (LevelKeyboard *keyboard,
}
gtk_style_context_add_provider (renderer->view_context,
GTK_STYLE_PROVIDER(renderer->css_provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
GTK_STYLE_PROVIDER_PRIORITY_USER);
/* Create a style context for the buttons */
path = gtk_widget_path_new();
@ -303,22 +305,26 @@ eek_renderer_new (LevelKeyboard *keyboard,
gtk_style_context_set_state (renderer->button_context, GTK_STATE_FLAG_NORMAL);
gtk_style_context_add_provider (renderer->button_context,
GTK_STYLE_PROVIDER(renderer->css_provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
GTK_STYLE_PROVIDER_PRIORITY_USER);
return renderer;
}
struct render_geometry
eek_render_geometry_from_allocation_size (struct squeek_layout *layout,
void
eek_renderer_set_allocation_size (EekRenderer *renderer,
struct squeek_layout *layout,
gdouble width,
gdouble height)
{
struct render_geometry ret = {
.allocation_width = width,
.allocation_height = height,
.widget_to_layout = squeek_layout_calculate_transformation(
layout, width, height),
};
return ret;
g_return_if_fail (width > 0.0 && height > 0.0);
renderer->allocation_width = width;
renderer->allocation_height = height;
renderer->widget_to_layout = squeek_layout_calculate_transformation(
layout,
renderer->allocation_width, renderer->allocation_height);
// This is where size-dependent surfaces would be released
}
void
@ -327,11 +333,6 @@ eek_renderer_set_scale_factor (EekRenderer *renderer, gint scale)
renderer->scale_factor = scale;
}
/// Rust interface.
uint32_t eek_renderer_get_scale_factor(EekRenderer *renderer) {
return renderer->scale_factor;
}
cairo_surface_t *
eek_renderer_get_icon_surface (const gchar *icon_name,
gint size,
@ -355,3 +356,8 @@ eek_renderer_get_icon_surface (const gchar *icon_name,
}
return surface;
}
struct transformation
eek_renderer_get_transformation (EekRenderer *renderer) {
return renderer->widget_to_layout;
}

View File

@ -41,23 +41,22 @@ typedef struct EekRenderer
gchar *extra_style; // owned
// Mutable state
gint scale_factor; /* the outputs scale factor */
} EekRenderer;
/// Mutable part of the renderer state.
/// TODO: Possibly should include scale factor.
struct render_geometry {
/// Background extents
gdouble allocation_width;
gdouble allocation_height;
gint scale_factor; /* the outputs scale factor */
/// Coords transformation
struct transformation widget_to_layout;
};
} EekRenderer;
GType eek_renderer_get_type (void) G_GNUC_CONST;
EekRenderer *eek_renderer_new (LevelKeyboard *keyboard,
PangoContext *pcontext);
void eek_renderer_set_allocation_size
(EekRenderer *renderer, struct squeek_layout *layout,
gdouble width,
gdouble height);
void eek_renderer_set_scale_factor (EekRenderer *renderer,
gint scale);
@ -65,14 +64,13 @@ cairo_surface_t *eek_renderer_get_icon_surface(const gchar *icon_name,
gint size,
gint scale);
void eek_renderer_render_keyboard (EekRenderer *renderer, struct render_geometry geometry, struct submission *submission,
void eek_renderer_render_keyboard (EekRenderer *renderer, struct submission *submission,
cairo_t *cr, LevelKeyboard *keyboard);
void
eek_renderer_free (EekRenderer *self);
struct render_geometry
eek_render_geometry_from_allocation_size (struct squeek_layout *layout,
gdouble width, gdouble height);
struct transformation
eek_renderer_get_transformation (EekRenderer *renderer);
G_END_DECLS
#endif /* EEK_RENDERER_H */

View File

@ -90,5 +90,13 @@ struct transformation {
gdouble scale;
};
struct squeek_button;
struct squeek_row;
/// Represents the path to the button within a view
struct button_place {
const struct squeek_row *row;
const struct squeek_button *button;
};
G_END_DECLS
#endif /* EEK_TYPES_H */

View File

@ -312,6 +312,7 @@ on_phosh_layer_surface_unmapped (PhoshLayerSurface *self, gpointer unused)
PhoshLayerSurfacePrivate *priv;
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
priv = phosh_layer_surface_get_instance_private (self);
priv = phosh_layer_surface_get_instance_private (self);
if (priv->layer_surface) {
@ -589,32 +590,27 @@ phosh_layer_surface_set_size(PhoshLayerSurface *self, gint width, gint height)
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
priv = phosh_layer_surface_get_instance_private (self);
if (priv->height == height && priv->width == width) {
if (priv->height == height && priv->width == width)
return;
}
old_width = priv->width;
old_height = priv->height;
if (width != -1) {
if (width != -1)
priv->width = width;
}
if (height != -1) {
if (height != -1)
priv->height = height;
}
if (gtk_widget_get_mapped (GTK_WIDGET (self))) {
zwlr_layer_surface_v1_set_size(priv->layer_surface, priv->width, priv->height);
}
if (priv->height != old_height) {
if (priv->height != old_height)
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT]);
}
if (priv->width != old_width) {
if (priv->width != old_width)
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH]);
}
}
/**
@ -636,31 +632,25 @@ phosh_layer_surface_set_margins(PhoshLayerSurface *self, gint top, gint right, g
old_right = priv->margin_right;
old_bottom = priv->margin_bottom;
if (old_top == top && old_left == left && old_right == right && old_bottom == bottom) {
if (old_top == top && old_left == left && old_right == right && old_bottom == bottom)
return;
}
priv->margin_top = top;
priv->margin_left = left;
priv->margin_right = right;
priv->margin_bottom = bottom;
if (priv->layer_surface) {
if (priv->layer_surface)
zwlr_layer_surface_v1_set_margin(priv->layer_surface, top, right, bottom, left);
}
if (old_top != top) {
if (old_top != top)
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_MARGIN_TOP]);
}
if (old_bottom != bottom) {
if (old_bottom != bottom)
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_MARGIN_BOTTOM]);
}
if (old_left != left) {
if (old_left != left)
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_MARGIN_LEFT]);
}
if (old_right != right) {
if (old_right != right)
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_MARGIN_RIGHT]);
}
}
/**
@ -679,15 +669,13 @@ phosh_layer_surface_set_exclusive_zone(PhoshLayerSurface *self, gint zone)
old_zone = priv->exclusive_zone;
if (old_zone == zone) {
if (old_zone == zone)
return;
}
priv->exclusive_zone = zone;
if (priv->layer_surface) {
if (priv->layer_surface)
zwlr_layer_surface_v1_set_exclusive_zone(priv->layer_surface, zone);
}
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE]);
}
@ -705,14 +693,13 @@ phosh_layer_surface_set_kbd_interactivity (PhoshLayerSurface *self, gboolean int
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
priv = phosh_layer_surface_get_instance_private (self);
if (priv->kbd_interactivity == interactivity) {
if (priv->kbd_interactivity == interactivity)
return;
}
priv->kbd_interactivity = interactivity;
if (priv->layer_surface) {
if (priv->layer_surface)
zwlr_layer_surface_v1_set_keyboard_interactivity (priv->layer_surface, interactivity);
}
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_KBD_INTERACTIVITY]);
}
@ -730,7 +717,6 @@ phosh_layer_surface_wl_surface_commit (PhoshLayerSurface *self)
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
priv = phosh_layer_surface_get_instance_private (self);
if (priv->wl_surface) {
if (priv->wl_surface)
wl_surface_commit (priv->wl_surface);
}
}

View File

@ -128,22 +128,30 @@ settings_get_layout(GSettings *settings, char **type, char **layout)
void
eekboard_context_service_use_layout(EekboardContextService *context, struct squeek_layout_state *state, uint32_t timestamp) {
gchar *layout_name = state->layout_name;
gchar *overlay_name = state->overlay_name;
gchar *layout_name = state->overlay_name;
// try to get the best keyboard layout
if (layout_name == NULL) {
layout_name = "us";
layout_name = state->layout_name;
switch (state->purpose) {
case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER:
case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE:
layout_name = "number";
break;
case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL:
layout_name = "terminal";
break;
default:
;
}
if (layout_name == NULL) {
layout_name = "us";
}
}
// overlay is "Normal" for most layouts, we will only look for "terminal" in rust code.
// for now just avoid passing a null pointer
if (overlay_name == NULL) {
overlay_name = ""; // fallback to Normal
}
// generic part follows
struct squeek_layout *layout = squeek_load_layout(layout_name, state->arrangement, state->purpose, overlay_name);
struct squeek_layout *layout = squeek_load_layout(layout_name, state->arrangement);
LevelKeyboard *keyboard = level_keyboard_new(layout);
// set as current
LevelKeyboard *previous_keyboard = context->keyboard;
@ -151,7 +159,7 @@ eekboard_context_service_use_layout(EekboardContextService *context, struct sque
// Update the keymap if necessary.
// TODO: Update submission on change event
if (context->submission) {
submission_use_layout(context->submission, keyboard->layout, timestamp);
submission_set_keyboard(context->submission, keyboard, timestamp);
}
// Update UI
@ -337,7 +345,7 @@ void eekboard_context_service_set_submission(EekboardContextService *context, st
context->submission = submission;
if (context->submission) {
uint32_t time = gdk_event_get_time(NULL);
submission_use_layout(context->submission, context->keyboard->layout, time);
submission_set_keyboard(context->submission, context->keyboard, time);
}
}

View File

@ -1,7 +1,7 @@
project(
'squeekboard',
'c', 'rust',
version: '1.14.0',
version: '1.9.3',
license: 'GPLv3',
meson_version: '>=0.51.0',
default_options: [
@ -20,16 +20,14 @@ add_project_arguments(
'-Werror=incompatible-pointer-types',
'-Werror=int-conversion',
'-Werror=redundant-decls',
'-Werror=parentheses',
'-Wformat-nonliteral',
'-Wformat-security',
'-Wformat',
'-Winit-self',
'-Wmaybe-uninitialized',
'-Wold-style-definition',
'-Wredundant-decls',
'-Wstrict-prototypes',
'-Wunused',
'-Wunused-function',
],
language: 'c'
)
@ -41,16 +39,6 @@ conf_data = configuration_data()
if get_option('buildtype').startswith('debug')
add_project_arguments('-DDEBUG=1', language : 'c')
endif
if get_option('strict')
add_project_arguments(
[
'-Werror',
],
language: 'c'
)
endif
if get_option('buildtype') != 'plain'
add_project_arguments('-fstack-protector-strong', language: 'c')
endif
@ -83,7 +71,6 @@ summary = [
message('\n'.join(summary))
# Rust deps are changing, depending on compile flags. Cargo can't handle it alone.
# As a side effect, Cargo.toml never gets used.
cargo_toml_in = files('Cargo.toml.in')
path_data = configuration_data()
path_data.set('path', meson.source_root())
@ -97,7 +84,7 @@ cargo_toml_base = configure_file(
cargo_deps = files('Cargo.deps')
if get_option('legacy') == true
cargo_build_flags += ['--features', 'gtk_v0_5,gio_v0_5,rustc_less_1_36']
cargo_build_flags += ['--features', 'gtk_v0_5,gio_v0_5']
cargo_deps = files('Cargo.deps.legacy')
endif
@ -111,7 +98,7 @@ cargo_toml = custom_target(
dep_cargo = find_program('cargo')
cargo_script = find_program('cargo.sh')
cargo_build = find_program('cargo_build.py')
cargo_build = find_program('cargo_build.sh')
subdir('data')
subdir('protocols')

View File

@ -10,7 +10,3 @@ option('tests',
option('legacy',
type: 'boolean', value: false,
description: 'Build with Deban Buster versions of dependencies')
option('strict',
type: 'boolean', value: true,
description: 'Turn more warnings into errors')

View File

@ -294,8 +294,8 @@
The serial number reflects the last state of the zwp_input_method_v2
object known to the client. The value of the serial argument must be
equal to the number of done events already issued on that object.
When the compositor receives a commit request with a serial different than
equal to the number of commit requests already issued on that object.
When the compositor receives a done event with a serial different than
the number of past commit requests, it must proceed as normal, except
it should not change the current state of the zwp_input_method_v2
object.

View File

@ -10,14 +10,13 @@ pub struct KeySym(pub String);
type View = String;
/// Use to send modified keypresses
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Modifier {
/// Control and Alt are the only modifiers
/// which doesn't interfere with levels,
/// so it's simple to implement as levels are deprecated in squeekboard.
Control,
Alt,
Mod4,
}
/// Action to perform on the keypress and, in reverse, on keyrelease
@ -30,11 +29,6 @@ pub enum Action {
lock: View,
/// When unlocked by pressing it or emitting a key
unlock: View,
/// Whether key has a latched state
/// that pops when another key is pressed.
latches: bool,
/// Should take on *locked* appearance whenever latch comes back to those views.
looks_locked_from: Vec<View>,
},
/// Hold this modifier for as long as the button is pressed
ApplyModifier(Modifier),
@ -54,24 +48,14 @@ pub enum Action {
impl Action {
pub fn is_locked(&self, view_name: &str) -> bool {
match self {
Action::LockView { lock, unlock: _, latches: _, looks_locked_from: _ } => lock == view_name,
_ => false,
}
}
pub fn has_locked_appearance_from(&self, locked_view_name: &str) -> bool {
match self {
Action::LockView { lock: _, unlock: _, latches: _, looks_locked_from } => {
looks_locked_from.iter()
.find(|view| locked_view_name == view.as_str())
.is_some()
},
Action::LockView { lock, unlock: _ } => lock == view_name,
_ => false,
}
}
pub fn is_active(&self, view_name: &str) -> bool {
match self {
Action::SetView(view) => view == view_name,
Action::LockView { lock, unlock: _, latches: _, looks_locked_from: _ } => lock == view_name,
Action::LockView { lock, unlock: _ } => lock == view_name,
_ => false,
}
}

View File

@ -1,30 +1,32 @@
/* Copyright (C) 2020-2021 Purism SPC
* SPDX-License-Identifier: GPL-3.0+
*/
/**! The parsing of the data files for layouts */
/*! Parsing of the data files containing layouts */
// TODO: find a nice way to make sure non-positive sizes don't break layouts
use std::cell::RefCell;
use std::collections::{ HashMap, HashSet };
use std::env;
use std::ffi::CString;
use std::fmt;
use std::fs;
use std::io;
use std::path::PathBuf;
use std::rc::Rc;
use std::vec::Vec;
use xkbcommon::xkb;
use super::{ Error, LoadError };
use ::action;
use ::keyboard::{
KeyState, PressType,
generate_keymaps, generate_keycodes, KeyCode, FormattingError
generate_keymap, generate_keycodes, FormattingError
};
use ::layout;
use ::layout::ArrangementKind;
use ::logging;
use ::util::hash_map_map;
use ::resources;
use ::util::c::as_str;
use ::util::hash_map_map;
use ::xdg;
// traits, derives
use serde::Deserialize;
@ -32,7 +34,183 @@ use std::io::BufReader;
use std::iter::FromIterator;
use ::logging::Warn;
// TODO: find a nice way to make sure non-positive sizes don't break layouts
/// Gathers stuff defined in C or called by C
pub mod c {
use super::*;
use std::os::raw::c_char;
#[no_mangle]
pub extern "C"
fn squeek_load_layout(
name: *const c_char,
type_: u32,
) -> *mut ::layout::Layout {
let type_ = match type_ {
0 => ArrangementKind::Base,
1 => ArrangementKind::Wide,
_ => panic!("Bad enum value"),
};
let name = as_str(&name)
.expect("Bad layout name")
.expect("Empty layout name");
let (kind, layout) = load_layout_data_with_fallback(&name, type_);
let layout = ::layout::Layout::new(layout, kind);
Box::into_raw(Box::new(layout))
}
}
const FALLBACK_LAYOUT_NAME: &str = "us";
#[derive(Debug)]
pub enum LoadError {
BadData(Error),
MissingResource,
BadResource(serde_yaml::Error),
BadKeyMap(FormattingError),
}
impl fmt::Display for LoadError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::LoadError::*;
match self {
BadData(e) => write!(f, "Bad data: {}", e),
MissingResource => write!(f, "Missing resource"),
BadResource(e) => write!(f, "Bad resource: {}", e),
BadKeyMap(e) => write!(f, "Bad key map: {}", e),
}
}
}
#[derive(Debug, Clone, PartialEq)]
enum DataSource {
File(PathBuf),
Resource(String),
}
impl fmt::Display for DataSource {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DataSource::File(path) => write!(f, "Path: {:?}", path.display()),
DataSource::Resource(name) => write!(f, "Resource: {}", name),
}
}
}
/// Lists possible sources, with 0 as the most preferred one
/// Trying order: native lang of the right kind, native base,
/// fallback lang of the right kind, fallback base
fn list_layout_sources(
name: &str,
kind: ArrangementKind,
keyboards_path: Option<PathBuf>,
) -> Vec<(ArrangementKind, DataSource)> {
let mut ret = Vec::new();
{
fn name_with_arrangement(name: String, kind: &ArrangementKind)
-> String
{
match kind {
ArrangementKind::Base => name,
ArrangementKind::Wide => name + "_wide",
}
}
let mut add_by_name = |name: &str, kind: &ArrangementKind| {
if let Some(path) = keyboards_path.clone() {
ret.push((
kind.clone(),
DataSource::File(
path.join(name.to_owned()).with_extension("yaml")
)
))
}
ret.push((
kind.clone(),
DataSource::Resource(name.into())
));
};
match &kind {
ArrangementKind::Base => {},
kind => add_by_name(
&name_with_arrangement(name.into(), &kind),
&kind,
),
};
add_by_name(name, &ArrangementKind::Base);
match &kind {
ArrangementKind::Base => {},
kind => add_by_name(
&name_with_arrangement(FALLBACK_LAYOUT_NAME.into(), &kind),
&kind,
),
};
add_by_name(FALLBACK_LAYOUT_NAME, &ArrangementKind::Base);
}
ret
}
fn load_layout_data(source: DataSource)
-> Result<::layout::LayoutData, LoadError>
{
let handler = logging::Print {};
match source {
DataSource::File(path) => {
Layout::from_file(path.clone())
.map_err(LoadError::BadData)
.and_then(|layout|
layout.build(handler).0.map_err(LoadError::BadKeyMap)
)
},
DataSource::Resource(name) => {
Layout::from_resource(&name)
.and_then(|layout|
layout.build(handler).0.map_err(LoadError::BadKeyMap)
)
},
}
}
fn load_layout_data_with_fallback(
name: &str,
kind: ArrangementKind,
) -> (ArrangementKind, ::layout::LayoutData) {
let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR")
.map(PathBuf::from)
.or_else(|| xdg::data_path("squeekboard/keyboards"));
for (kind, source) in list_layout_sources(name, kind, path) {
let layout = load_layout_data(source.clone());
match layout {
Err(e) => match (e, source) {
(
LoadError::BadData(Error::Missing(e)),
DataSource::File(file)
) => log_print!(
logging::Level::Debug,
"Tried file {:?}, but it's missing: {}",
file, e
),
(e, source) => log_print!(
logging::Level::Warning,
"Failed to load layout from {}: {}, skipping",
source, e
),
},
Ok(layout) => {
log_print!(logging::Level::Info, "Loaded layout {}", source);
return (kind, layout);
}
}
}
panic!("No useful layout found!");
}
/// The root element describing an entire keyboard
#[derive(Debug, Deserialize, PartialEq)]
@ -88,13 +266,7 @@ struct ButtonMeta {
#[serde(deny_unknown_fields)]
enum Action {
#[serde(rename="locking")]
Locking {
lock_view: String,
unlock_view: String,
pops: Option<bool>,
#[serde(default)]
looks_locked_from: Vec<String>,
},
Locking { lock_view: String, unlock_view: String },
#[serde(rename="set_view")]
SetView(String),
#[serde(rename="show_prefs")]
@ -125,6 +297,37 @@ struct Outline {
height: f64,
}
/// Errors encountered loading the layout into yaml
#[derive(Debug)]
pub enum Error {
Yaml(serde_yaml::Error),
Io(io::Error),
/// The file was missing.
/// It's distinct from Io in order to make it matchable
/// without calling io::Error::kind()
Missing(io::Error),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Yaml(e) => write!(f, "YAML: {}", e),
Error::Io(e) => write!(f, "IO: {}", e),
Error::Missing(e) => write!(f, "Missing: {}", e),
}
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
let kind = e.kind();
match kind {
io::ErrorKind::NotFound => Error::Missing(e),
_ => Error::Io(e),
}
}
}
pub fn add_offsets<'a, I: 'a, T, F: 'a>(iterator: I, get_size: F)
-> impl Iterator<Item=(f64, T)> + 'a
where I: Iterator<Item=T>,
@ -179,7 +382,7 @@ impl Layout {
)
)}).collect();
let symbolmap: HashMap<String, KeyCode> = generate_keycodes(
let symbolmap: HashMap<String, u32> = generate_keycodes(
extract_symbol_names(&button_actions)
);
@ -188,7 +391,7 @@ impl Layout {
let keycodes = match &action {
::action::Action::Submit { text: _, keys } => {
keys.iter().map(|named_keysym| {
symbolmap.get(named_keysym.0.as_str())
*symbolmap.get(named_keysym.0.as_str())
.expect(
format!(
"keysym {} in key {} missing from symbol map",
@ -196,13 +399,11 @@ impl Layout {
name
).as_str()
)
.clone()
}).collect()
},
action::Action::Erase => vec![
symbolmap.get("BackSpace")
.expect(&format!("BackSpace missing from symbol map"))
.clone(),
*symbolmap.get("BackSpace")
.expect(&format!("BackSpace missing from symbol map")),
],
_ => Vec::new(),
};
@ -217,7 +418,7 @@ impl Layout {
})
);
let keymaps = match generate_keymaps(symbolmap) {
let keymap_str = match generate_keymap(symbolmap) {
Err(e) => { return (Err(e), warning_handler) },
Ok(v) => v,
};
@ -281,10 +482,10 @@ impl Layout {
(
Ok(::layout::LayoutData {
views: views,
keymaps: keymaps.into_iter().map(|keymap_str|
keymap_str: {
CString::new(keymap_str)
.expect("Invalid keymap string generated")
).collect(),
},
// FIXME: use a dedicated field
margins: layout::Margins {
top: self.margins.top,
@ -317,7 +518,7 @@ fn create_action<H: logging::Handler>(
Text(String),
Keysym(String),
Modifier(Modifier),
}
};
let submission = match (
&symbol_meta.action,
@ -374,9 +575,7 @@ fn create_action<H: logging::Handler>(
)
),
SubmitData::Action(Action::Locking {
lock_view, unlock_view,
pops,
looks_locked_from,
lock_view, unlock_view
}) => ::action::Action::LockView {
lock: filter_view_name(
name,
@ -390,8 +589,6 @@ fn create_action<H: logging::Handler>(
&view_names,
warning_handler,
),
latches: pops.unwrap_or(true),
looks_locked_from,
},
SubmitData::Action(
Action::ShowPrefs
@ -436,9 +633,6 @@ fn create_action<H: logging::Handler>(
Modifier::Alt => action::Action::ApplyModifier(
action::Modifier::Alt,
),
Modifier::Mod4 => action::Action::ApplyModifier(
action::Modifier::Mod4,
),
unsupported_modifier => {
warning_handler.handle(
logging::Level::Bug,
@ -528,46 +722,34 @@ fn create_button<H: logging::Handler>(
}
fn extract_symbol_names<'a>(actions: &'a [(&str, action::Action)])
-> impl Iterator<Item=String> + 'a
-> impl Iterator<Item=&'a str>
{
actions.iter()
.filter_map(|(_name, act)| {
match act {
action::Action::Submit {
text: _, keys,
} => Some(keys.clone()),
action::Action::Erase => Some(vec!(action::KeySym("BackSpace".into()))),
} => Some(keys),
_ => None,
}
})
.flatten()
.map(|named_keysym| named_keysym.0)
.map(|named_keysym| named_keysym.0.as_str())
}
#[cfg(test)]
mod tests {
use super::*;
use std::env;
use ::logging::ProblemPanic;
const THIS_FILE: &str = file!();
fn path_from_root(file: &'static str) -> PathBuf {
let source_dir = env::var("SOURCE_DIR")
.map(PathBuf::from)
.unwrap_or_else(|e| {
if let env::VarError::NotPresent = e {
let this_file = file!();
PathBuf::from(this_file)
.parent().unwrap()
.parent().unwrap()
.into()
} else {
panic!("{:?}", e);
}
});
source_dir.join(file)
PathBuf::from(THIS_FILE)
.parent().unwrap()
.parent().unwrap()
.join(file)
}
#[test]
@ -693,13 +875,38 @@ mod tests {
assert_eq!(
out.views["base"].1
.get_rows()[0].1
.get_buttons()[0].1
.buttons[0].1
.state.borrow()
.keycodes.len(),
1
);
}
#[test]
fn parsing_fallback() {
assert!(Layout::from_resource(FALLBACK_LAYOUT_NAME)
.map(|layout| layout.build(ProblemPanic).0.unwrap())
.is_ok()
);
}
/// First fallback should be to builtin, not to FALLBACK_LAYOUT_NAME
#[test]
fn fallbacks_order() {
let sources = list_layout_sources("nb", ArrangementKind::Base, None);
assert_eq!(
sources,
vec!(
(ArrangementKind::Base, DataSource::Resource("nb".into())),
(
ArrangementKind::Base,
DataSource::Resource(FALLBACK_LAYOUT_NAME.into())
),
)
);
}
#[test]
fn unicode_keysym() {
let keysym = xkb::keysym_from_name(
@ -779,7 +986,7 @@ mod tests {
)];
assert_eq!(
extract_symbol_names(&actions[..]).collect::<Vec<_>>(),
vec!["BackSpace"],
Vec::<&str>::new(), //"BackSpace"], // TODO: centralize handling of BackSpace
);
}

View File

@ -1,424 +0,0 @@
/* Copyright (C) 2020-2021 Purism SPC
* SPDX-License-Identifier: GPL-3.0+
*/
/*! Loading layout files */
use std::env;
use std::fmt;
use std::path::PathBuf;
use std::convert::TryFrom;
use super::{ Error, LoadError };
use super::parsing;
use ::layout::ArrangementKind;
use ::logging;
use ::util::c::as_str;
use ::xdg;
use ::imservice::ContentPurpose;
// traits, derives
use ::logging::Warn;
/// Gathers stuff defined in C or called by C
pub mod c {
use super::*;
use std::os::raw::c_char;
#[no_mangle]
pub extern "C"
fn squeek_load_layout(
name: *const c_char, // name of the keyboard
type_: u32, // type like Wide
variant: u32, // purpose variant like numeric, terminal...
overlay: *const c_char, // the overlay (looking for "terminal")
) -> *mut ::layout::Layout {
let type_ = match type_ {
0 => ArrangementKind::Base,
1 => ArrangementKind::Wide,
_ => panic!("Bad enum value"),
};
let name = as_str(&name)
.expect("Bad layout name")
.expect("Empty layout name");
let variant = ContentPurpose::try_from(variant)
.or_print(
logging::Problem::Warning,
"Received invalid purpose value",
)
.unwrap_or(ContentPurpose::Normal);
let overlay_str = as_str(&overlay)
.expect("Bad overlay name")
.expect("Empty overlay name");
let overlay_str = match overlay_str {
"" => None,
other => Some(other),
};
let (kind, layout) = load_layout_data_with_fallback(&name, type_, variant, overlay_str);
let layout = ::layout::Layout::new(layout, kind);
Box::into_raw(Box::new(layout))
}
}
const FALLBACK_LAYOUT_NAME: &str = "us";
#[derive(Debug, Clone, PartialEq)]
enum DataSource {
File(PathBuf),
Resource(String),
}
impl fmt::Display for DataSource {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DataSource::File(path) => write!(f, "Path: {:?}", path.display()),
DataSource::Resource(name) => write!(f, "Resource: {}", name),
}
}
}
/* All functions in this family carry around ArrangementKind,
* because it's not guaranteed to be preserved,
* and the resulting layout needs to know which version was loaded.
* See `squeek_layout_get_kind`.
* Possible TODO: since this is used only in styling,
* and makes the below code nastier than needed, maybe it should go.
*/
/// Returns ordered names treating `name` as the base name,
/// ignoring any `+` inside.
fn _get_arrangement_names(name: &str, arrangement: ArrangementKind)
-> Vec<(ArrangementKind, String)>
{
let name_with_arrangement = match arrangement {
ArrangementKind::Base => name.into(),
ArrangementKind::Wide => format!("{}_wide", name),
};
let mut ret = Vec::new();
if name_with_arrangement != name {
ret.push((arrangement, name_with_arrangement));
}
ret.push((ArrangementKind::Base, name.into()));
ret
}
/// Returns names accounting for any `+` in the `name`,
/// including the fallback to the default layout.
fn get_preferred_names(name: &str, kind: ArrangementKind)
-> Vec<(ArrangementKind, String)>
{
let mut ret = _get_arrangement_names(name, kind);
let base_name_preferences = {
let mut parts = name.splitn(2, '+');
match parts.next() {
Some(base) => {
// The name is already equal to base, so nothing to add
if base == name {
vec![]
} else {
_get_arrangement_names(base, kind)
}
},
// The layout's base name starts with a "+". Weird but OK.
None => {
log_print!(logging::Level::Surprise, "Base layout name is empty: {}", name);
vec![]
}
}
};
ret.extend(base_name_preferences.into_iter());
let fallback_names = _get_arrangement_names(FALLBACK_LAYOUT_NAME, kind);
ret.extend(fallback_names.into_iter());
ret
}
/// Includes the subdirectory before the forward slash.
type LayoutPath = String;
// This is only used inside iter_fallbacks_with_meta.
// Placed at the top scope
// because `use LayoutPurpose::*;`
// complains about "not in scope" otherwise.
// This seems to be a Rust 2015 edition problem.
/// Helper for determining where to look up the layout.
enum LayoutPurpose<'a> {
Default,
Special(&'a str),
}
/// Returns the directory string
/// where the layout should be looked up, including the slash.
fn get_directory_string(
content_purpose: ContentPurpose,
overlay: Option<&str>) -> String
{
use self::LayoutPurpose::*;
let layout_purpose = match overlay {
None => match content_purpose {
ContentPurpose::Number => Special("number"),
ContentPurpose::Digits => Special("number"),
ContentPurpose::Phone => Special("number"),
ContentPurpose::Terminal => Special("terminal"),
_ => Default,
},
Some(overlay) => Special(overlay),
};
// For intuitiveness,
// default purpose layouts are stored in the root directory,
// as they correspond to typical text
// and are seen the most often.
match layout_purpose {
Default => "".into(),
Special(purpose) => format!("{}/", purpose),
}
}
/// Returns an iterator over all fallback paths.
fn to_layout_paths(
name_fallbacks: Vec<(ArrangementKind, String)>,
content_purpose: ContentPurpose,
overlay: Option<&str>,
) -> impl Iterator<Item=(ArrangementKind, LayoutPath)> {
let prepend_directory = get_directory_string(content_purpose, overlay);
name_fallbacks.into_iter()
.map(move |(arrangement, name)|
(arrangement, format!("{}{}", prepend_directory, name))
)
}
type LayoutSource = (ArrangementKind, DataSource);
fn to_layout_sources(
layout_paths: impl Iterator<Item=(ArrangementKind, LayoutPath)>,
filesystem_path: Option<PathBuf>,
) -> impl Iterator<Item=LayoutSource> {
layout_paths.flat_map(move |(arrangement, layout_path)| {
let mut sources = Vec::new();
if let Some(path) = &filesystem_path {
sources.push((
arrangement,
DataSource::File(
path.join(&layout_path)
.with_extension("yaml")
)
));
};
sources.push((arrangement, DataSource::Resource(layout_path.clone())));
sources.into_iter()
})
}
/// Returns possible sources, with first as the most preferred one.
/// Trying order: native lang of the right kind, native base,
/// fallback lang of the right kind, fallback base
fn iter_layout_sources(
name: &str,
arrangement: ArrangementKind,
purpose: ContentPurpose,
ui_overlay: Option<&str>,
layout_storage: Option<PathBuf>,
) -> impl Iterator<Item=LayoutSource> {
let names = get_preferred_names(name, arrangement);
let paths = to_layout_paths(names, purpose, ui_overlay);
to_layout_sources(paths, layout_storage)
}
fn load_layout_data(source: DataSource)
-> Result<::layout::LayoutData, LoadError>
{
let handler = logging::Print {};
match source {
DataSource::File(path) => {
parsing::Layout::from_file(path.clone())
.map_err(LoadError::BadData)
.and_then(|layout|
layout.build(handler).0.map_err(LoadError::BadKeyMap)
)
},
DataSource::Resource(name) => {
parsing::Layout::from_resource(&name)
.and_then(|layout|
layout.build(handler).0.map_err(LoadError::BadKeyMap)
)
},
}
}
fn load_layout_data_with_fallback(
name: &str,
kind: ArrangementKind,
purpose: ContentPurpose,
overlay: Option<&str>,
) -> (ArrangementKind, ::layout::LayoutData) {
// Build the path to the right keyboard layout subdirectory
let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR")
.map(PathBuf::from)
.or_else(|| xdg::data_path("squeekboard/keyboards"));
for (kind, source) in iter_layout_sources(&name, kind, purpose, overlay, path) {
let layout = load_layout_data(source.clone());
match layout {
Err(e) => match (e, source) {
(
LoadError::BadData(Error::Missing(e)),
DataSource::File(file)
) => log_print!(
logging::Level::Debug,
"Tried file {:?}, but it's missing: {}",
file, e
),
(e, source) => log_print!(
logging::Level::Warning,
"Failed to load layout from {}: {}, skipping",
source, e
),
},
Ok(layout) => {
log_print!(logging::Level::Info, "Loaded layout {}", source);
return (kind, layout);
}
}
}
panic!("No useful layout found!");
}
#[cfg(test)]
mod tests {
use super::*;
use ::logging::ProblemPanic;
#[test]
fn parsing_fallback() {
assert!(parsing::Layout::from_resource(FALLBACK_LAYOUT_NAME)
.map(|layout| layout.build(ProblemPanic).0.unwrap())
.is_ok()
);
}
/// First fallback should be to builtin, not to FALLBACK_LAYOUT_NAME
#[test]
fn test_fallback_basic_builtin() {
let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, None, None);
assert_eq!(
sources.collect::<Vec<_>>(),
vec!(
(ArrangementKind::Base, DataSource::Resource("nb".into())),
(
ArrangementKind::Base,
DataSource::Resource(FALLBACK_LAYOUT_NAME.into())
),
)
);
}
/// Prefer loading from file system before builtin.
#[test]
fn test_preferences_order_path() {
let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, None, Some(".".into()));
assert_eq!(
sources.collect::<Vec<_>>(),
vec!(
(ArrangementKind::Base, DataSource::File("./nb.yaml".into())),
(ArrangementKind::Base, DataSource::Resource("nb".into())),
(
ArrangementKind::Base,
DataSource::File("./us.yaml".into())
),
(
ArrangementKind::Base,
DataSource::Resource("us".into())
),
)
);
}
/// If layout contains a "+", it should reach for what's in front of it too.
#[test]
fn test_preferences_order_base() {
let sources = iter_layout_sources("nb+aliens", ArrangementKind::Base, ContentPurpose::Normal, None, None);
assert_eq!(
sources.collect::<Vec<_>>(),
vec!(
(ArrangementKind::Base, DataSource::Resource("nb+aliens".into())),
(ArrangementKind::Base, DataSource::Resource("nb".into())),
(
ArrangementKind::Base,
DataSource::Resource(FALLBACK_LAYOUT_NAME.into())
),
)
);
}
#[test]
fn test_preferences_order_arrangement() {
let sources = iter_layout_sources("nb", ArrangementKind::Wide, ContentPurpose::Normal, None, None);
assert_eq!(
sources.collect::<Vec<_>>(),
vec!(
(ArrangementKind::Wide, DataSource::Resource("nb_wide".into())),
(ArrangementKind::Base, DataSource::Resource("nb".into())),
(
ArrangementKind::Wide,
DataSource::Resource("us_wide".into())
),
(
ArrangementKind::Base,
DataSource::Resource("us".into())
),
)
);
}
#[test]
fn test_preferences_order_overlay() {
let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, Some("terminal"), None);
assert_eq!(
sources.collect::<Vec<_>>(),
vec!(
(ArrangementKind::Base, DataSource::Resource("terminal/nb".into())),
(
ArrangementKind::Base,
DataSource::Resource("terminal/us".into())
),
)
);
}
#[test]
fn test_preferences_order_hint() {
let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Terminal, None, None);
assert_eq!(
sources.collect::<Vec<_>>(),
vec!(
(ArrangementKind::Base, DataSource::Resource("terminal/nb".into())),
(
ArrangementKind::Base,
DataSource::Resource("terminal/us".into())
),
)
);
}
}

View File

@ -1,65 +0,0 @@
/* Copyright (C) 2020-2021 Purism SPC
* SPDX-License-Identifier: GPL-3.0+
*/
/*! Combined module for dealing with layout files */
mod loading;
pub mod parsing;
use std::io;
use std::fmt;
use ::keyboard::FormattingError;
/// Errors encountered loading the layout into yaml
#[derive(Debug)]
pub enum Error {
Yaml(serde_yaml::Error),
Io(io::Error),
/// The file was missing.
/// It's distinct from Io in order to make it matchable
/// without calling io::Error::kind()
Missing(io::Error),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Yaml(e) => write!(f, "YAML: {}", e),
Error::Io(e) => write!(f, "IO: {}", e),
Error::Missing(e) => write!(f, "Missing: {}", e),
}
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
let kind = e.kind();
match kind {
io::ErrorKind::NotFound => Error::Missing(e),
_ => Error::Io(e),
}
}
}
#[derive(Debug)]
pub enum LoadError {
BadData(Error),
MissingResource,
BadResource(serde_yaml::Error),
BadKeyMap(FormattingError),
}
impl fmt::Display for LoadError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::LoadError::*;
match self {
BadData(e) => write!(f, "Bad data: {}", e),
MissingResource => write!(f, "Missing resource"),
BadResource(e) => write!(f, "Bad resource: {}", e),
BadKeyMap(e) => write!(f, "Bad key map: {}", e),
}
}
}

View File

@ -59,7 +59,7 @@ handle_set_visible(SmPuriOSK0 *object, GDBusMethodInvocation *invocation,
if (service->context) {
if (arg_visible) {
server_context_service_force_show_keyboard (service->context);
server_context_service_show_keyboard (service->context);
} else {
server_context_service_hide_keyboard (service->context);
}

View File

@ -3,24 +3,20 @@
use cairo;
use std::cell::RefCell;
use ::action::{ Action, Modifier };
use ::action::Action;
use ::keyboard;
use ::layout::{ Button, Label, LatchedState, Layout };
use ::layout::c::{ Bounds, EekGtkKeyboard, Point };
use ::layout::{ Button, Layout };
use ::layout::c::{ EekGtkKeyboard, Point };
use ::submission::Submission;
use glib::translate::FromGlibPtrNone;
use gtk::WidgetExt;
use std::collections::HashSet;
use std::ffi::CStr;
use std::ptr;
mod c {
use super::*;
use cairo_sys;
use std::os::raw::{ c_char, c_void };
use std::os::raw::c_void;
// This is constructed only in C, no need for warnings
#[allow(dead_code)]
@ -28,44 +24,18 @@ mod c {
#[derive(Clone, Copy)]
pub struct EekRenderer(*const c_void);
// This is constructed only in C, no need for warnings
/// Just don't clone this for no reason.
#[allow(dead_code)]
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct GtkStyleContext(*const c_void);
#[no_mangle]
extern "C" {
// Button and View inside CButtonPlace are safe to pass to C
// as long as they don't outlive the call
// and nothing dereferences them
#[allow(improper_ctypes)]
pub fn eek_renderer_get_scale_factor(
pub fn eek_render_button(
renderer: EekRenderer,
) -> u32;
#[allow(improper_ctypes)]
pub fn eek_render_button_in_context(
scale_factor: u32,
cr: *mut cairo_sys::cairo_t,
ctx: GtkStyleContext,
bounds: Bounds,
icon_name: *const c_char,
label: *const c_char,
);
#[allow(improper_ctypes)]
pub fn eek_get_style_context_for_button(
renderer: EekRenderer,
name: *const c_char,
outline_name: *const c_char,
locked_class: *const c_char,
button: *const Button,
pressed: u64,
) -> GtkStyleContext;
#[allow(improper_ctypes)]
pub fn eek_put_style_context_for_button(
ctx: GtkStyleContext,
outline_name: *const c_char,
locked_class: *const c_char,
locked: u64,
);
}
@ -85,16 +55,13 @@ mod c {
layout.foreach_visible_button(|offset, button| {
let state = RefCell::borrow(&button.state).clone();
let locked = LockedStyle::from_action(
&state.action,
&active_modifiers,
layout.get_view_latched(),
&layout.current_view,
);
if state.pressed == keyboard::PressType::Pressed
|| locked != LockedStyle::Free
{
let active_mod = match &state.action {
Action::ApplyModifier(m) => active_modifiers.contains(m),
_ => false,
};
let locked = state.action.is_active(&layout.current_view)
| active_mod;
if state.pressed == keyboard::PressType::Pressed || locked {
render_button_at_position(
renderer, &cr,
offset,
@ -120,55 +87,20 @@ mod c {
renderer, &cr,
offset,
button.as_ref(),
keyboard::PressType::Released,
LockedStyle::Free,
keyboard::PressType::Released, false,
);
})
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
enum LockedStyle {
Free,
Latched,
Locked,
}
impl LockedStyle {
fn from_action(
action: &Action,
mods: &HashSet<Modifier>,
latched_view: &LatchedState,
current_view: &str,
) -> LockedStyle {
let active_mod = match action {
Action::ApplyModifier(m) => mods.contains(m),
_ => false,
};
let active_view = action.is_active(current_view);
let latched_button = match latched_view {
LatchedState::Not => false,
LatchedState::FromView(view) => !action.has_locked_appearance_from(view),
};
match (active_mod, active_view, latched_button) {
// Modifiers don't latch.
(true, _, _) => LockedStyle::Locked,
(false, true, false) => LockedStyle::Locked,
(false, true, true) => LockedStyle::Latched,
_ => LockedStyle::Free,
}
}
}
/// Renders a button at a position (button's own bounds ignored)
fn render_button_at_position(
pub fn render_button_at_position(
renderer: c::EekRenderer,
cr: &cairo::Context,
position: Point,
button: &Button,
pressed: keyboard::PressType,
locked: LockedStyle,
locked: bool,
) {
cr.save();
cr.translate(position.x, position.y);
@ -177,110 +109,19 @@ fn render_button_at_position(
button.size.width, button.size.height
);
cr.clip();
let scale_factor = unsafe {
c::eek_renderer_get_scale_factor(renderer)
};
let bounds = button.get_bounds();
let (label_c, icon_name_c) = match &button.label {
Label::Text(text) => (text.as_ptr(), ptr::null()),
Label::IconName(name) => {
let l = unsafe {
// CStr doesn't allocate anything, so it only points to
// the 'static str, avoiding a memory leak
CStr::from_bytes_with_nul_unchecked(b"icon\0")
};
(l.as_ptr(), name.as_ptr())
},
};
with_button_context(
renderer,
button,
pressed,
locked,
|ctx| unsafe {
// TODO: split into separate procedures:
// draw outline, draw label, draw icon.
c::eek_render_button_in_context(
scale_factor,
cairo::Context::to_raw_none(&cr),
*ctx,
bounds,
icon_name_c,
label_c,
)
}
);
cr.restore();
}
fn with_button_context<R, F: FnOnce(&c::GtkStyleContext) -> R>(
renderer: c::EekRenderer,
button: &Button,
pressed: keyboard::PressType,
locked: LockedStyle,
operation: F,
) -> R {
let outline_name_c = button.outline_name.as_ptr();
let locked_class_c = match locked {
LockedStyle::Free => ptr::null(),
LockedStyle::Locked => unsafe {
CStr::from_bytes_with_nul_unchecked(b"locked\0").as_ptr()
},
LockedStyle::Latched => unsafe {
CStr::from_bytes_with_nul_unchecked(b"latched\0").as_ptr()
},
};
let ctx = unsafe {
c::eek_get_style_context_for_button(
renderer,
button.name.as_ptr(),
outline_name_c,
locked_class_c,
pressed as u64,
)
};
let r = operation(&ctx);
unsafe {
c::eek_put_style_context_for_button(
ctx,
outline_name_c,
locked_class_c,
c::eek_render_button(
renderer,
cairo::Context::to_raw_none(&cr),
button as *const Button,
pressed as u64,
locked as u64,
)
};
r
cr.restore();
}
pub fn queue_redraw(keyboard: EekGtkKeyboard) {
let widget = unsafe { gtk::Widget::from_glib_none(keyboard.0) };
widget.queue_draw();
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_exit_only() {
assert_eq!(
LockedStyle::from_action(
&Action::LockView {
lock: "ab".into(),
unlock: "a".into(),
latches: true,
looks_locked_from: vec!["b".into()],
},
&HashSet::new(),
&LatchedState::FromView("b".into()),
"ab",
),
LockedStyle::Locked,
);
}
}

View File

@ -25,7 +25,6 @@ static const struct zwp_input_method_v2_listener input_method_listener = {
struct submission* get_submission(struct zwp_input_method_manager_v2 *immanager,
struct zwp_virtual_keyboard_manager_v1 *vkmanager,
struct vis_manager *vis_manager,
struct wl_seat *seat,
EekboardContextService *state) {
struct zwp_input_method_v2 *im = NULL;
@ -36,7 +35,7 @@ struct submission* get_submission(struct zwp_input_method_manager_v2 *immanager,
if (vkmanager) {
vk = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(vkmanager, seat);
}
return submission_new(im, vk, state, vis_manager);
return submission_new(im, vk, state);
}
/// Un-inlined

View File

@ -23,7 +23,7 @@ pub mod c {
use std::os::raw::{c_char, c_void};
pub use ::ui_manager::c::UIManager;
pub use ::submission::c::UIManager;
pub use ::submission::c::StateManager;
// The following defined in C
@ -32,15 +32,17 @@ pub mod c {
#[repr(transparent)]
pub struct InputMethod(*const c_void);
#[no_mangle]
extern "C" {
fn imservice_destroy_im(im: *mut c::InputMethod);
#[allow(improper_ctypes)] // IMService will never be dereferenced in C
pub fn imservice_connect_listeners(im: *mut InputMethod, imservice: *const IMService);
pub fn eek_input_method_commit_string(im: *mut InputMethod, text: *const c_char);
pub fn eek_input_method_delete_surrounding_text(im: *mut InputMethod, before: u32, after: u32);
pub fn eek_input_method_commit(im: *mut InputMethod, serial: u32);
fn eekboard_context_service_set_hint_purpose(state: *const StateManager, hint: u32, purpose: u32);
fn server_context_service_show_keyboard(imservice: *const UIManager);
fn server_context_service_hide_keyboard(imservice: *const UIManager);
}
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
@ -52,7 +54,7 @@ pub mod c {
im: *const InputMethod)
{
let imservice = check_imservice(imservice, im).unwrap();
imservice.preedit_string = String::new();
imservice.preedit_string = String::new(); // I don't think this is ever used. Remove it?
imservice.pending = IMProtocolState {
active: true,
..IMProtocolState::default()
@ -82,7 +84,7 @@ pub mod c {
surrounding_text: into_cstring(text)
.expect("Received invalid string")
.expect("Received null string"),
surrounding_cursor: cursor,
cursor,
..imservice.pending.clone()
};
}
@ -144,16 +146,12 @@ pub mod c {
let active_changed = imservice.current.active ^ imservice.pending.active;
imservice.current = imservice.pending.clone();
imservice.pending = IMProtocolState {
active: imservice.current.active,
..IMProtocolState::default()
};
imservice.serial += Wrapping(1u32);
if active_changed {
(imservice.active_callback)(imservice.current.active);
if imservice.current.active {
if let Some(ui) = imservice.ui_manager {
unsafe { server_context_service_show_keyboard(ui); }
}
unsafe {
eekboard_context_service_set_hint_purpose(
imservice.state_manager,
@ -161,6 +159,10 @@ pub mod c {
imservice.current.content_purpose.clone() as u32,
);
}
} else {
if let Some(ui) = imservice.ui_manager {
unsafe { server_context_service_hide_keyboard(ui); }
}
}
}
}
@ -178,7 +180,9 @@ pub mod c {
// the keyboard is already decommissioned
imservice.current.active = false;
(imservice.active_callback)(imservice.current.active);
if let Some(ui) = imservice.ui_manager {
unsafe { server_context_service_hide_keyboard(ui); }
}
}
// FIXME: destroy and deallocate
@ -306,7 +310,7 @@ impl TryFrom<u32> for ChangeCause {
#[derive(Clone)]
struct IMProtocolState {
surrounding_text: CString,
surrounding_cursor: u32,
cursor: u32,
content_purpose: ContentPurpose,
content_hint: ContentHint,
text_change_cause: ChangeCause,
@ -317,7 +321,7 @@ impl Default for IMProtocolState {
fn default() -> IMProtocolState {
IMProtocolState {
surrounding_text: CString::default(),
surrounding_cursor: 0, // TODO: mark that there's no cursor
cursor: 0, // TODO: mark that there's no cursor
content_hint: ContentHint::NONE,
content_purpose: ContentPurpose::Normal,
text_change_cause: ChangeCause::InputMethod,
@ -331,11 +335,12 @@ pub struct IMService {
pub im: *mut c::InputMethod,
/// Unowned reference. Be careful, it's shared with C at large
state_manager: *const c::StateManager,
active_callback: Box<dyn Fn(bool)>,
/// Unowned reference. Be careful, it's shared with C at large
pub ui_manager: Option<*const c::UIManager>,
pending: IMProtocolState,
current: IMProtocolState, // turn current into an idiomatic representation?
preedit_string: String,
preedit_string: String, // I don't think this is ever used. Remove it?
serial: Wrapping<u32>,
}
@ -348,17 +353,16 @@ impl IMService {
pub fn new(
im: *mut c::InputMethod,
state_manager: *const c::StateManager,
active_callback: Box<dyn Fn(bool)>,
) -> Box<IMService> {
// IMService will be referenced to by C,
// so it needs to stay in the same place in memory via Box
let imservice = Box::new(IMService {
im,
active_callback,
ui_manager: None,
state_manager,
pending: IMProtocolState::default(),
current: IMProtocolState::default(),
preedit_string: String::new(),
preedit_string: String::new(), // I don't think this is ever used. Remove it?
serial: Wrapping(0u32),
});
unsafe {
@ -369,10 +373,15 @@ impl IMService {
}
imservice
}
pub fn commit_string(&self, text: &CString) -> Result<(), SubmitError> {
pub fn commit_string(&mut self, text: &CString) -> Result<(), SubmitError> {
match self.current.active {
true => {
let cursor_position = self.pending.cursor.try_into().unwrap(); // Converts u32 of cursor to usize
self.pending
.surrounding_text
.insert_str(cursor_position, text);
self.pending.cursor += text.len() as u32;
unsafe {
c::eek_input_method_commit_string(self.im, text.as_ptr())
}
@ -383,11 +392,16 @@ impl IMService {
}
pub fn delete_surrounding_text(
&self,
&mut self,
before: u32, after: u32,
) -> Result<(), SubmitError> {
match self.current.active {
true => {
let cursor_position: usize = self.pending.cursor.try_into().unwrap(); // Converts u32 of cursor to usize
self.pending.surrounding_text.replace_range(
cursor_position - (before as usize)..cursor_position + (after as usize),
"",
);
unsafe {
c::eek_input_method_delete_surrounding_text(
self.im,
@ -406,6 +420,8 @@ impl IMService {
unsafe {
c::eek_input_method_commit(self.im, self.serial.0)
}
self.serial += Wrapping(1u32);
imservice_handle_done(self);
Ok(())
},
false => Err(SubmitError::NotActive),

View File

@ -5,13 +5,10 @@ use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
use std::io;
use std::mem;
use std::ptr;
use std::rc::Rc;
use std::string::FromUtf8Error;
use ::action::Action;
use ::util;
// Traits
use std::io::Write;
@ -23,12 +20,7 @@ pub enum PressType {
Pressed = 1,
}
/// The extended, unambiguous layout-keycode
#[derive(Debug, Clone)]
pub struct KeyCode {
pub code: u32,
pub keymap_idx: usize,
}
pub type KeyCode = u32;
bitflags!{
/// Map to `virtual_keyboard.modifiers` modifiers values
@ -87,10 +79,10 @@ impl KeyState {
}
/// Sorts an iterator by converting it to a Vector and back
fn sorted<'a, I: Iterator<Item=String>>(
fn sorted<'a, I: Iterator<Item=&'a str>>(
iter: I
) -> impl Iterator<Item=String> {
let mut v: Vec<String> = iter.collect();
) -> impl Iterator<Item=&'a str> {
let mut v: Vec<&'a str> = iter.collect();
v.sort();
v.into_iter()
}
@ -98,17 +90,15 @@ fn sorted<'a, I: Iterator<Item=String>>(
/// Generates a mapping where each key gets a keycode, starting from ~~8~~
/// HACK: starting from 9, because 8 results in keycode 0,
/// which the compositor likes to discard
pub fn generate_keycodes<'a, C: IntoIterator<Item=String>>(
pub fn generate_keycodes<'a, C: IntoIterator<Item=&'a str>>(
key_names: C,
) -> HashMap<String, KeyCode> {
) -> HashMap<String, u32> {
let special_keysyms = ["BackSpace", "Return"].iter().map(|&s| s);
HashMap::from_iter(
// Sort to remove a source of indeterminism in keycode assignment.
sorted(key_names.into_iter())
.zip(util::cycle_count(9..255))
.map(|(name, (code, keymap_idx))| (
String::from(name),
KeyCode { code, keymap_idx },
))
// sort to remove a source of indeterminism in keycode assignment
sorted(key_names.into_iter().chain(special_keysyms))
.map(|name| String::from(name))
.zip(9..)
)
}
@ -133,54 +123,10 @@ impl From<io::Error> for FormattingError {
}
}
/// Index is the key code, String is the occupant.
/// Starts all empty.
/// https://gitlab.freedesktop.org/xorg/xserver/-/issues/260
type SingleKeyMap = [Option<String>; 256];
fn single_key_map_new() -> SingleKeyMap {
// Why can't we just initialize arrays without tricks -_- ?
unsafe {
// Inspired by
// https://www.reddit.com/r/rust/comments/5n7bh1/how_to_create_an_array_of_a_type_with_clone_but/
#[cfg(feature = "rustc_less_1_36")]
let mut array: SingleKeyMap = mem::uninitialized();
#[cfg(not(feature = "rustc_less_1_36"))]
let mut array: SingleKeyMap = mem::MaybeUninit::uninit().assume_init();
for element in array.iter_mut() {
ptr::write(element, None);
}
array
}
}
pub fn generate_keymaps(symbolmap: HashMap::<String, KeyCode>)
-> Result<Vec<String>, FormattingError>
{
let mut bins: Vec<SingleKeyMap> = Vec::new();
for (name, KeyCode { code, keymap_idx }) in symbolmap.into_iter() {
if keymap_idx >= bins.len() {
bins.resize_with(
keymap_idx + 1,
|| single_key_map_new(),
);
}
bins[keymap_idx][code as usize] = Some(name);
}
let mut out = Vec::new();
for bin in bins {
out.push(generate_keymap(&bin)?);
}
Ok(out)
}
/// Generates a de-facto single level keymap.
/// Key codes must not repeat and must remain between 9 and 255.
fn generate_keymap(
symbolmap: &SingleKeyMap,
/// Key codes must not repeat and should remain between 9 and 255.
pub fn generate_keymap(
symbolmap: HashMap::<String, KeyCode>,
) -> Result<String, FormattingError> {
let mut buf: Vec<u8> = Vec::new();
writeln!(
@ -189,21 +135,14 @@ fn generate_keymap(
xkb_keycodes \"squeekboard\" {{
minimum = 8;
maximum = 255;"
maximum = 999;"
)?;
let pairs: Vec<(&String, usize)> = symbolmap.iter()
// Attach a key code to each cell.
.enumerate()
// Get rid of empty keycodes.
.filter_map(|(code, name)| name.as_ref().map(|n| (n, code)))
.collect();
// Xorg can only consume up to 255 keys, so this may not work in Xwayland.
// Two possible solutions:
// - use levels to cram multiple characters into one key
// - swap layouts on key presses
for (_name, keycode) in &pairs {
for keycode in symbolmap.values() {
write!(
buf,
"
@ -222,7 +161,7 @@ fn generate_keymap(
"
)?;
for (name, keycode) in pairs {
for (name, keycode) in symbolmap.iter() {
write!(
buf,
"
@ -280,15 +219,14 @@ mod tests {
use xkbcommon::xkb;
#[test]
fn test_keymap_single_resolve() {
let mut key_map = single_key_map_new();
key_map[9] = Some("a".into());
key_map[10] = Some("c".into());
let keymap_str = generate_keymap(&key_map).unwrap();
fn test_keymap_multi() {
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let keymap_str = generate_keymap(hashmap!{
"a".into() => 9,
"c".into() => 10,
}).unwrap();
let keymap = xkb::Keymap::new_from_string(
&context,
keymap_str.clone(),
@ -301,36 +239,4 @@ mod tests {
assert_eq!(state.key_get_one_sym(9), xkb::KEY_a);
assert_eq!(state.key_get_one_sym(10), xkb::KEY_c);
}
#[test]
fn test_keymap_second_resolve() {
let keymaps = generate_keymaps(hashmap!(
"a".into() => KeyCode { keymap_idx: 1, code: 9 },
)).unwrap();
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let keymap = xkb::Keymap::new_from_string(
&context,
keymaps[1].clone(), // this index is part of the test
xkb::KEYMAP_FORMAT_TEXT_V1,
xkb::KEYMAP_COMPILE_NO_FLAGS,
).expect("Failed to create keymap");
let state = xkb::State::new(&keymap);
assert_eq!(state.key_get_one_sym(9), xkb::KEY_a);
}
#[test]
fn test_symbolmap_overflow() {
// The 257th key (U1101) is interesting.
// Use Unicode encoding for being able to use in xkb keymaps.
let keynames = (0..258).map(|num| format!("U{:04X}", 0x1000 + num));
let keycodes = generate_keycodes(keynames);
// test now
let code = keycodes.get("U1101").expect("Did not find the tested keysym");
assert_eq!(code.keymap_idx, 1);
}
}

View File

@ -26,12 +26,20 @@ struct squeek_layout_state {
struct squeek_layout;
EekBounds squeek_button_get_bounds(const struct squeek_button*);
const char *squeek_button_get_label(const struct squeek_button*);
const char *squeek_button_get_icon_name(const struct squeek_button*);
const char *squeek_button_get_name(const struct squeek_button*);
const char *squeek_button_get_outline_name(const struct squeek_button*);
void squeek_button_print(const struct squeek_button* button);
struct transformation squeek_layout_calculate_transformation(
const struct squeek_layout *layout,
double allocation_width, double allocation_size);
struct squeek_layout *squeek_load_layout(const char *name, uint32_t type, uint32_t variant_type, const char *overlay_name);
struct squeek_layout *squeek_load_layout(const char *name, uint32_t type);
const char *squeek_layout_get_keymap(const struct squeek_layout*);
enum squeek_arrangement_kind squeek_layout_get_kind(const struct squeek_layout *);
void squeek_layout_free(struct squeek_layout*);

View File

@ -41,7 +41,9 @@ pub mod c {
use super::*;
use gtk_sys;
use std::os::raw::c_void;
use std::ffi::CStr;
use std::os::raw::{ c_char, c_void };
use std::ptr;
use std::ops::{ Add, Sub };
@ -50,6 +52,7 @@ pub mod c {
#[derive(Copy, Clone)]
pub struct EekGtkKeyboard(pub *const gtk_sys::GtkWidget);
#[no_mangle]
extern "C" {
#[allow(improper_ctypes)]
pub fn eek_gtk_keyboard_emit_feedback(
@ -159,6 +162,64 @@ pub mod c {
pub struct LevelKeyboard(*const c_void);
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
#[no_mangle]
pub extern "C"
fn squeek_button_get_bounds(button: *const ::layout::Button) -> Bounds {
let button = unsafe { &*button };
Bounds {
x: 0.0, y: 0.0,
width: button.size.width, height: button.size.height
}
}
#[no_mangle]
pub extern "C"
fn squeek_button_get_label(
button: *const ::layout::Button
) -> *const c_char {
let button = unsafe { &*button };
match &button.label {
Label::Text(text) => text.as_ptr(),
// returning static strings to C is a bit cumbersome
Label::IconName(_) => unsafe {
// CStr doesn't allocate anything, so it only points to
// the 'static str, avoiding a memory leak
CStr::from_bytes_with_nul_unchecked(b"icon\0")
}.as_ptr(),
}
}
#[no_mangle]
pub extern "C"
fn squeek_button_get_icon_name(button: *const Button) -> *const c_char {
let button = unsafe { &*button };
match &button.label {
Label::Text(_) => ptr::null(),
Label::IconName(name) => name.as_ptr(),
}
}
#[no_mangle]
pub extern "C"
fn squeek_button_get_name(button: *const Button) -> *const c_char {
let button = unsafe { &*button };
button.name.as_ptr()
}
#[no_mangle]
pub extern "C"
fn squeek_button_get_outline_name(button: *const Button) -> *const c_char {
let button = unsafe { &*button };
button.outline_name.as_ptr()
}
#[no_mangle]
pub extern "C"
fn squeek_button_print(button: *const ::layout::Button) {
let button = unsafe { &*button };
println!("{:?}", button);
}
/// Positions the layout contents within the available space.
/// The origin of the transformation is the point inside the margins.
@ -175,6 +236,13 @@ pub mod c {
height: allocation_height,
})
}
#[no_mangle]
pub extern "C"
fn squeek_layout_get_keymap(layout: *const Layout) -> *const c_char {
let layout = unsafe { &*layout };
layout.keymap_str.as_ptr()
}
#[no_mangle]
pub extern "C"
@ -424,15 +492,6 @@ pub struct Button {
pub state: Rc<RefCell<KeyState>>,
}
impl Button {
pub fn get_bounds(&self) -> c::Bounds {
c::Bounds {
x: 0.0, y: 0.0,
width: self.size.width, height: self.size.height,
}
}
}
/// The graphical representation of a row of buttons
#[derive(Clone, Debug)]
pub struct Row {
@ -500,7 +559,6 @@ pub struct Spacing {
pub button: f64,
}
#[derive(Clone)]
pub struct View {
/// Rows together with their offsets from the top left
rows: Vec<(c::Point, Row)>,
@ -600,7 +658,7 @@ impl View {
}
/// The physical characteristic of layout for the purpose of styling
#[derive(Clone, Copy, PartialEq, Debug)]
#[derive(Clone, PartialEq, Debug)]
pub enum ArrangementKind {
Base = 0,
Wide = 1,
@ -614,13 +672,6 @@ pub struct Margins {
pub right: f64,
}
#[derive(Clone, Debug, PartialEq)]
pub enum LatchedState {
/// Holds view to return to.
FromView(String),
Not,
}
// TODO: split into sth like
// Arrangement (views) + details (keymap) + State (keys)
/// State of the UI, contains the backend as well
@ -628,12 +679,6 @@ pub struct Layout {
pub margins: Margins,
pub kind: ArrangementKind,
pub current_view: String,
// If current view is latched,
// clicking any button that emits an action (erase, submit, set modifier)
// will cause lock buttons to unlatch.
view_latched: LatchedState,
// Views own the actual buttons which have state
// Maybe they should own UI only,
// and keys should be owned by a dedicated non-UI-State?
@ -641,8 +686,8 @@ pub struct Layout {
pub views: HashMap<String, (c::Point, View)>,
// Non-UI stuff
/// xkb keymaps applicable to the contained keys. Unchangeable
pub keymaps: Vec<CString>,
/// xkb keymap applicable to the contained keys. Unchangeable
pub keymap_str: CString,
// Changeable state
// a Vec would be enough, but who cares, this will be small & fast enough
// TODO: turn those into per-input point *_buttons to track dragging.
@ -658,7 +703,7 @@ pub struct Layout {
pub struct LayoutData {
/// Point is the offset within layout
pub views: HashMap<String, (c::Point, View)>,
pub keymaps: Vec<CString>,
pub keymap_str: CString,
pub margins: Margins,
}
@ -680,9 +725,8 @@ impl Layout {
Layout {
kind,
current_view: "base".to_owned(),
view_latched: LatchedState::Not,
views: data.views,
keymaps: data.keymaps,
keymap_str: data.keymap_str,
pressed_keys: HashSet::new(),
margins: data.margins,
}
@ -706,12 +750,6 @@ impl Layout {
}
}
// Layout is passed around mutably,
// so better keep the field away from direct access.
pub fn get_view_latched(&self) -> &LatchedState {
&self.view_latched
}
/// Calculates size without margins
fn calculate_inner_size(&self) -> Size {
View::calculate_super_size(
@ -770,117 +808,25 @@ impl Layout {
}
}
}
fn apply_view_transition(
&mut self,
action: &Action,
) {
let (transition, new_latched) = Layout::process_action_for_view(
action,
&self.current_view,
&self.view_latched,
);
match transition {
ViewTransition::UnlatchAll => self.unstick_locks(),
ViewTransition::ChangeTo(view) => try_set_view(self, view.into()),
ViewTransition::NoChange => {},
};
self.view_latched = new_latched;
}
/// Unlatch all latched keys,
/// so that the new view is the one before first press.
fn unstick_locks(&mut self) {
if let LatchedState::FromView(name) = self.view_latched.clone() {
match self.set_view(name.clone()) {
Ok(_) => { self.view_latched = LatchedState::Not; }
Err(e) => log_print!(
logging::Level::Bug,
"Bad view {}, can't unlatch ({:?})",
name,
e,
),
pub fn get_locked_keys(&self) -> Vec<Rc<RefCell<KeyState>>> {
let mut out = Vec::new();
let view = self.get_current_view();
for (_, row) in view.get_rows() {
for (_, button) in &row.buttons {
let locked = {
let state = RefCell::borrow(&button.state).clone();
state.action.is_locked(&self.current_view)
};
if locked {
out.push(button.state.clone());
}
}
}
}
/// Last bool is new latch state.
/// It doesn't make sense when the result carries UnlatchAll,
/// but let's not be picky.
///
/// Although the state is not defined at the keys
/// (it's in the relationship between view and action),
/// keys go through the following stages when clicked repeatedly:
/// unlocked+unlatched -> locked+latched -> locked+unlatched
/// -> unlocked+unlatched
fn process_action_for_view<'a>(
action: &'a Action,
current_view: &str,
latched: &LatchedState,
) -> (ViewTransition<'a>, LatchedState) {
match action {
Action::Submit { text: _, keys: _ }
| Action::Erase
| Action::ApplyModifier(_)
=> {
let t = match latched {
LatchedState::FromView(_) => ViewTransition::UnlatchAll,
LatchedState::Not => ViewTransition::NoChange,
};
(t, LatchedState::Not)
},
Action::SetView(view) => (
ViewTransition::ChangeTo(view),
LatchedState::Not,
),
Action::LockView { lock, unlock, latches, looks_locked_from: _ } => {
use self::ViewTransition as VT;
let locked = action.is_locked(current_view);
match (locked, latched, latches) {
// Was unlocked, now make locked but latched.
(false, LatchedState::Not, true) => (
VT::ChangeTo(lock),
LatchedState::FromView(current_view.into()),
),
// Layout is latched for reason other than this button.
(false, LatchedState::FromView(view), true) => (
VT::ChangeTo(lock),
LatchedState::FromView(view.clone()),
),
// Was latched, now only locked.
(true, LatchedState::FromView(_), true)
=> (VT::NoChange, LatchedState::Not),
// Was unlocked, can't latch so now make fully locked.
(false, _, false)
=> (VT::ChangeTo(lock), LatchedState::Not),
// Was locked, now make unlocked.
(true, _, _)
=> (VT::ChangeTo(unlock), LatchedState::Not),
}
},
_ => (ViewTransition::NoChange, latched.clone()),
}
out
}
}
#[derive(Debug, PartialEq)]
enum ViewTransition<'a> {
ChangeTo(&'a str),
UnlatchAll,
NoChange,
}
fn try_set_view(layout: &mut Layout, view_name: &str) {
layout.set_view(view_name.into())
.or_print(
logging::Problem::Bug,
&format!("Bad view {}, ignoring", view_name),
);
}
mod procedures {
use super::*;
@ -959,6 +905,67 @@ pub struct UIBackend {
mod seat {
use super::*;
fn try_set_view(layout: &mut Layout, view_name: String) {
layout.set_view(view_name.clone())
.or_print(
logging::Problem::Bug,
&format!("Bad view {}, ignoring", view_name),
);
}
/// A vessel holding an obligation to switch view.
/// Use with #[must_use]
struct ViewChange<'a> {
layout: &'a mut Layout,
view_name: Option<String>,
}
impl<'a> ViewChange<'a> {
fn choose_view(self, view_name: String) -> ViewChange<'a> {
ViewChange {
view_name: Some(view_name),
..self
}
}
fn apply(self) {
if let Some(name) = self.view_name {
try_set_view(self.layout, name);
}
}
}
/// Find all impermanent view changes and undo them in an arbitrary order.
/// Return an obligation to actually switch the view.
/// The final view is the "unlock" view
/// from one of the currently stuck keys.
// As long as only one stuck button is used, this should be fine.
// This is guaranteed because pressing a lock button unlocks all others.
// TODO: Make some broader guarantee about the resulting view,
// e.g. by maintaining a stack of stuck keys.
#[must_use]
fn unstick_locks(layout: &mut Layout) -> ViewChange {
let mut new_view = None;
for key in layout.get_locked_keys().clone() {
let key: &Rc<RefCell<KeyState>> = key.borrow();
let key = RefCell::borrow(key);
match &key.action {
Action::LockView { lock: _, unlock: view } => {
new_view = Some(view.clone());
},
a => log_print!(
logging::Level::Bug,
"Non-locking action {:?} was found inside locked keys",
a,
),
};
}
ViewChange {
layout,
view_name: new_view,
}
}
pub fn handle_press_key(
layout: &mut Layout,
submission: &mut Submission,
@ -1018,22 +1025,37 @@ mod seat {
};
let action = key.action.clone();
layout.apply_view_transition(&action);
// update
let key = key.into_released();
// process non-view switching
// process changes
match action {
Action::Submit { text: _, keys: _ }
| Action::Erase
=> {
unstick_locks(layout).apply();
submission.handle_release(KeyState::get_id(rckey), time);
},
Action::SetView(view) => {
try_set_view(layout, view)
},
Action::LockView { lock, unlock } => {
let gets_locked = !key.action.is_locked(&layout.current_view);
unstick_locks(layout)
// It doesn't matter what the resulting view should be,
// it's getting changed anyway.
.choose_view(
match gets_locked {
true => lock.clone(),
false => unlock.clone(),
}
)
.apply()
},
Action::ApplyModifier(modifier) => {
// FIXME: key id is unneeded with stateless locks
let key_id = KeyState::get_id(rckey);
let gets_locked = !submission.is_modifier_active(modifier);
let gets_locked = !submission.is_modifier_active(modifier.clone());
match gets_locked {
true => submission.handle_add_modifier(
key_id,
@ -1068,8 +1090,6 @@ mod seat {
}
}
},
// Other keys are handled in view switcher before.
_ => {}
};
let pointer = ::util::Pointer(rckey.clone());
@ -1087,20 +1107,14 @@ mod test {
use std::ffi::CString;
use ::keyboard::PressType;
pub fn make_state_with_action(action: Action)
-> Rc<RefCell<::keyboard::KeyState>>
{
pub fn make_state() -> Rc<RefCell<::keyboard::KeyState>> {
Rc::new(RefCell::new(::keyboard::KeyState {
pressed: PressType::Released,
keycodes: Vec::new(),
action,
action: Action::SetView("default".into()),
}))
}
pub fn make_state() -> Rc<RefCell<::keyboard::KeyState>> {
make_state_with_action(Action::SetView("default".into()))
}
pub fn make_button_with_state(
name: String,
state: Rc<RefCell<::keyboard::KeyState>>,
@ -1114,242 +1128,6 @@ mod test {
})
}
#[test]
fn latch_lock_unlock() {
let action = Action::LockView {
lock: "lock".into(),
unlock: "unlock".into(),
latches: true,
looks_locked_from: vec![],
};
assert_eq!(
Layout::process_action_for_view(&action, "unlock", &LatchedState::Not),
(ViewTransition::ChangeTo("lock"), LatchedState::FromView("unlock".into())),
);
assert_eq!(
Layout::process_action_for_view(&action, "lock", &LatchedState::FromView("unlock".into())),
(ViewTransition::NoChange, LatchedState::Not),
);
assert_eq!(
Layout::process_action_for_view(&action, "lock", &LatchedState::Not),
(ViewTransition::ChangeTo("unlock"), LatchedState::Not),
);
assert_eq!(
Layout::process_action_for_view(&Action::Erase, "lock", &LatchedState::FromView("base".into())),
(ViewTransition::UnlatchAll, LatchedState::Not),
);
}
#[test]
fn latch_pop_layout() {
let switch = Action::LockView {
lock: "locked".into(),
unlock: "base".into(),
latches: true,
looks_locked_from: vec![],
};
let submit = Action::Erase;
let view = View::new(vec![(
0.0,
Row::new(vec![
(
0.0,
make_button_with_state(
"switch".into(),
make_state_with_action(switch.clone())
),
),
(
1.0,
make_button_with_state(
"submit".into(),
make_state_with_action(submit.clone())
),
),
]),
)]);
let mut layout = Layout {
current_view: "base".into(),
view_latched: LatchedState::Not,
keymaps: Vec::new(),
kind: ArrangementKind::Base,
pressed_keys: HashSet::new(),
margins: Margins {
top: 0.0,
left: 0.0,
right: 0.0,
bottom: 0.0,
},
views: hashmap! {
// Both can use the same structure.
// Switching doesn't depend on the view shape
// as long as the switching button is present.
"base".into() => (c::Point { x: 0.0, y: 0.0 }, view.clone()),
"locked".into() => (c::Point { x: 0.0, y: 0.0 }, view),
},
};
// Basic cycle
layout.apply_view_transition(&switch);
assert_eq!(&layout.current_view, "locked");
layout.apply_view_transition(&switch);
assert_eq!(&layout.current_view, "locked");
layout.apply_view_transition(&submit);
assert_eq!(&layout.current_view, "locked");
layout.apply_view_transition(&switch);
assert_eq!(&layout.current_view, "base");
layout.apply_view_transition(&switch);
// Unlatch
assert_eq!(&layout.current_view, "locked");
layout.apply_view_transition(&submit);
assert_eq!(&layout.current_view, "base");
}
#[test]
fn reverse_unlatch_layout() {
let switch = Action::LockView {
lock: "locked".into(),
unlock: "base".into(),
latches: true,
looks_locked_from: vec![],
};
let unswitch = Action::LockView {
lock: "locked".into(),
unlock: "unlocked".into(),
latches: false,
looks_locked_from: vec![],
};
let submit = Action::Erase;
let view = View::new(vec![(
0.0,
Row::new(vec![
(
0.0,
make_button_with_state(
"switch".into(),
make_state_with_action(switch.clone())
),
),
(
1.0,
make_button_with_state(
"submit".into(),
make_state_with_action(submit.clone())
),
),
]),
)]);
let mut layout = Layout {
current_view: "base".into(),
view_latched: LatchedState::Not,
keymaps: Vec::new(),
kind: ArrangementKind::Base,
pressed_keys: HashSet::new(),
margins: Margins {
top: 0.0,
left: 0.0,
right: 0.0,
bottom: 0.0,
},
views: hashmap! {
// Both can use the same structure.
// Switching doesn't depend on the view shape
// as long as the switching button is present.
"base".into() => (c::Point { x: 0.0, y: 0.0 }, view.clone()),
"locked".into() => (c::Point { x: 0.0, y: 0.0 }, view.clone()),
"unlocked".into() => (c::Point { x: 0.0, y: 0.0 }, view),
},
};
layout.apply_view_transition(&switch);
assert_eq!(&layout.current_view, "locked");
layout.apply_view_transition(&unswitch);
assert_eq!(&layout.current_view, "unlocked");
}
#[test]
fn latch_twopop_layout() {
let switch = Action::LockView {
lock: "locked".into(),
unlock: "base".into(),
latches: true,
looks_locked_from: vec![],
};
let switch_again = Action::LockView {
lock: "ĄĘ".into(),
unlock: "locked".into(),
latches: true,
looks_locked_from: vec![],
};
let submit = Action::Erase;
let view = View::new(vec![(
0.0,
Row::new(vec![
(
0.0,
make_button_with_state(
"switch".into(),
make_state_with_action(switch.clone())
),
),
(
1.0,
make_button_with_state(
"submit".into(),
make_state_with_action(submit.clone())
),
),
]),
)]);
let mut layout = Layout {
current_view: "base".into(),
view_latched: LatchedState::Not,
keymaps: Vec::new(),
kind: ArrangementKind::Base,
pressed_keys: HashSet::new(),
margins: Margins {
top: 0.0,
left: 0.0,
right: 0.0,
bottom: 0.0,
},
views: hashmap! {
// All can use the same structure.
// Switching doesn't depend on the view shape
// as long as the switching button is present.
"base".into() => (c::Point { x: 0.0, y: 0.0 }, view.clone()),
"locked".into() => (c::Point { x: 0.0, y: 0.0 }, view.clone()),
"ĄĘ".into() => (c::Point { x: 0.0, y: 0.0 }, view),
},
};
// Latch twice, then Ąto-unlatch across 2 levels
layout.apply_view_transition(&switch);
println!("{:?}", layout.view_latched);
assert_eq!(&layout.current_view, "locked");
layout.apply_view_transition(&switch_again);
println!("{:?}", layout.view_latched);
assert_eq!(&layout.current_view, "ĄĘ");
layout.apply_view_transition(&submit);
println!("{:?}", layout.view_latched);
assert_eq!(&layout.current_view, "base");
}
#[test]
fn check_centering() {
// A B
@ -1422,8 +1200,7 @@ mod test {
]);
let layout = Layout {
current_view: String::new(),
view_latched: LatchedState::Not,
keymaps: Vec::new(),
keymap_str: CString::new("").unwrap(),
kind: ArrangementKind::Base,
pressed_keys: HashSet::new(),
// Lots of bottom margin

View File

@ -24,6 +24,7 @@ mod c {
#[repr(C)]
pub struct GnomeXkbInfo(*const c_void);
#[no_mangle]
extern "C" {
// from libc
pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int;

View File

@ -9,6 +9,7 @@ pub mod c {
#[derive(Clone, Copy)]
pub struct Manager(*const c_void);
#[no_mangle]
extern "C" {
pub fn eekboard_context_service_set_overlay(
manager: Manager,

View File

@ -80,7 +80,6 @@ test(
'rstest',
cargo_script,
args: ['test'] + cargo_build_flags,
env: ['SOURCE_DIR=' + meson.source_root()],
# this is a whole Carg-based test suite, let it run for a while
timeout: 900,
depends: [build_rstests, cargo_toml],

9
src/popover.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef POPOVER_H__
#define POPOVER_H__
#include <gtk/gtk.h>
#include "eek/eek-keyboard.h"
void squeek_popover_show(GtkWidget*, struct button_place);
#endif

View File

@ -29,6 +29,7 @@ use ::logging::Warn;
mod c {
use std::os::raw::c_char;
#[no_mangle]
extern "C" {
pub fn popover_open_settings_panel(panel: *const c_char);
}
@ -213,16 +214,7 @@ fn set_visible_layout(
layout_id: LayoutId,
) {
match layout_id {
LayoutId::System { kind, name } => {
unsafe {
use std::ptr;
manager::c::eekboard_context_service_set_overlay(
manager,
ptr::null(),
);
}
set_layout(kind, name);
}
LayoutId::System { kind, name } => set_layout(kind, name),
LayoutId::Local(name) => {
let name = CString::new(name.as_str()).unwrap();
let name_ptr = name.as_ptr();
@ -401,7 +393,6 @@ pub fn show(
width: position.width.floor() as i32,
height: position.width.floor() as i32,
});
menu.set_constrain_to(gtk::PopoverConstraint::None);
if let Some(current_layout) = get_current_layout(manager, &system_layouts) {
let current_name_variant = choices.iter()
@ -446,8 +437,7 @@ pub fn show(
let settings_action = gio::SimpleAction::new("settings", None);
settings_action.connect_activate(move |_, _| {
let s = CString::new("region").unwrap();
unsafe { c::popover_open_settings_panel(s.as_ptr()) };
unsafe { c::popover_open_settings_panel(CString::new("region").unwrap().as_ptr()) };
});
let action_group = gio::SimpleActionGroup::new();

View File

@ -10,114 +10,71 @@ use std::iter::FromIterator;
// TODO: keep a list of what is a language layout,
// and what a convenience layout. "_wide" is not a layout,
// neither is "number"
/// List of builtin layouts
static KEYBOARDS: &[(&'static str, &'static str)] = &[
const KEYBOARDS: &[(*const str, *const str)] = &[
// layouts: us must be left as first, as it is the,
// fallback layout.
// fallback layout. The others should be alphabetical.
("us", include_str!("../data/keyboards/us.yaml")),
("us_wide", include_str!("../data/keyboards/us_wide.yaml")),
// Language layouts: keep alphabetical.
("ara", include_str!("../data/keyboards/ara.yaml")),
("ara_wide", include_str!("../data/keyboards/ara_wide.yaml")),
("br", include_str!("../data/keyboards/br.yaml")),
("de", include_str!("../data/keyboards/de.yaml")),
("be", include_str!("../data/keyboards/be.yaml")),
("be_wide", include_str!("../data/keyboards/be_wide.yaml")),
("bg", include_str!("../data/keyboards/bg.yaml")),
("bg+phonetic", include_str!("../data/keyboards/bg+phonetic.yaml")),
("br", include_str!("../data/keyboards/br.yaml")),
("ch+fr", include_str!("../data/keyboards/ch+fr.yaml")),
("de", include_str!("../data/keyboards/de.yaml")),
("de_wide", include_str!("../data/keyboards/de_wide.yaml")),
("cz", include_str!("../data/keyboards/cz.yaml")),
("cz_wide", include_str!("../data/keyboards/cz_wide.yaml")),
("cz+qwerty", include_str!("../data/keyboards/cz+qwerty.yaml")),
("cz+qwerty_wide", include_str!("../data/keyboards/cz+qwerty_wide.yaml")),
("dk", include_str!("../data/keyboards/dk.yaml")),
("epo", include_str!("../data/keyboards/epo.yaml")),
("es", include_str!("../data/keyboards/es.yaml")),
("es+cat", include_str!("../data/keyboards/es+cat.yaml")),
("fi", include_str!("../data/keyboards/fi.yaml")),
("fr", include_str!("../data/keyboards/fr.yaml")),
("fr_wide", include_str!("../data/keyboards/fr_wide.yaml")),
("gr", include_str!("../data/keyboards/gr.yaml")),
("il", include_str!("../data/keyboards/il.yaml")),
("ir", include_str!("../data/keyboards/ir.yaml")),
("ir_wide", include_str!("../data/keyboards/ir_wide.yaml")),
("it", include_str!("../data/keyboards/it.yaml")),
("it+fur", include_str!("../data/keyboards/it+fur.yaml")),
("jp+kana", include_str!("../data/keyboards/jp+kana.yaml")),
("jp+kana_wide", include_str!("../data/keyboards/jp+kana_wide.yaml")),
("no", include_str!("../data/keyboards/no.yaml")),
("number", include_str!("../data/keyboards/number.yaml")),
("pl", include_str!("../data/keyboards/pl.yaml")),
("pl_wide", include_str!("../data/keyboards/pl_wide.yaml")),
("ru", include_str!("../data/keyboards/ru.yaml")),
("se", include_str!("../data/keyboards/se.yaml")),
("th", include_str!("../data/keyboards/th.yaml")),
("th_wide", include_str!("../data/keyboards/th_wide.yaml")),
("ua", include_str!("../data/keyboards/ua.yaml")),
("us+colemak", include_str!("../data/keyboards/us+colemak.yaml")),
("us+colemak_wide", include_str!("../data/keyboards/us+colemak_wide.yaml")),
("us+dvorak", include_str!("../data/keyboards/us+dvorak.yaml")),
("us+dvorak_wide", include_str!("../data/keyboards/us+dvorak_wide.yaml")),
// Others
("number/us", include_str!("../data/keyboards/number/us.yaml")),
// Terminal
("terminal/fr", include_str!("../data/keyboards/terminal/fr.yaml")),
("terminal/us", include_str!("../data/keyboards/terminal/us.yaml")),
("terminal/us_wide", include_str!("../data/keyboards/terminal/us_wide.yaml")),
// layout+overlay
("terminal", include_str!("../data/keyboards/terminal.yaml")),
("terminal_wide", include_str!("../data/keyboards/terminal_wide.yaml")),
// Overlays
("emoji/us", include_str!("../data/keyboards/emoji/us.yaml")),
("emoji", include_str!("../data/keyboards/emoji.yaml")),
];
pub fn get_keyboard(needle: &str) -> Option<&'static str> {
KEYBOARDS.iter().find(|(name, _)| *name == needle).map(|(_, layout)| *layout)
// Need to dereference in unsafe code
// comparing *const str to &str will compare pointers
KEYBOARDS.iter()
.find(|(name, _)| {
let name: *const str = *name;
(unsafe { &*name }) == needle
})
.map(|(_, value)| {
let value: *const str = *value;
unsafe { &*value }
})
}
static OVERLAY_NAMES: &[&'static str] = &[
const OVERLAY_NAMES: &[*const str] = &[
"emoji",
"terminal",
];
pub fn get_overlays() -> Vec<&'static str> {
OVERLAY_NAMES.to_vec()
OVERLAY_NAMES.iter()
.map(|name| {
let name: *const str = *name;
unsafe { &*name }
}).collect()
}
/// Translations of the layout identifier strings
static LAYOUT_NAMES: &[(&'static str, &'static str)] = &[
const LAYOUT_NAMES: &[(*const str, *const str)] = &[
("de-DE", include_str!("../data/langs/de-DE.txt")),
("en-US", include_str!("../data/langs/en-US.txt")),
("es-ES", include_str!("../data/langs/es-ES.txt")),
("fur-IT", include_str!("../data/langs/fur-IT.txt")),
("he-IL", include_str!("../data/langs/he-IL.txt")),
("ja-JP", include_str!("../data/langs/ja-JP.txt")),
("pl-PL", include_str!("../data/langs/pl-PL.txt")),
("ru-RU", include_str!("../data/langs/ru-RU.txt")),
@ -127,8 +84,14 @@ pub fn get_layout_names(lang: &str)
-> Option<HashMap<&'static str, Translation<'static>>>
{
let translations = LAYOUT_NAMES.iter()
.find(|(name, _data)| *name == lang)
.map(|(_name, data)| *data);
.find(|(name, _data)| {
let name: *const str = *name;
(unsafe { &*name }) == lang
})
.map(|(_name, data)| {
let data: *const str = *data;
unsafe { &*data }
});
translations.map(make_mapping)
}
@ -158,7 +121,7 @@ mod test {
#[test]
fn check_overlays_present() {
for name in get_overlays() {
assert!(get_keyboard(&format!("{}/us", name)).is_some());
assert!(get_keyboard(name).is_some());
}
}

View File

@ -43,9 +43,9 @@ struct _ServerContextService {
struct submission *submission; // unowned
struct squeek_layout_state *layout;
struct ui_manager *manager; // unowned
struct vis_manager *vis_manager; // owned
gboolean visible;
gboolean enabled;
PhoshLayerSurface *window;
GtkWidget *widget; // nullable
guint hiding;
@ -125,17 +125,14 @@ on_surface_configure(ServerContextService *self, PhoshLayerSurface *surface)
// we can use different algorithms for portrait and landscape mode.
// Note: this is a temporary fix until the size manager is complete.
display = gdk_display_get_default ();
if (display) {
if (display)
window = gtk_widget_get_window (GTK_WIDGET (surface));
}
if (window) {
if (window)
monitor = gdk_display_get_monitor_at_window (display, window);
}
if (monitor) {
if (monitor)
gdk_monitor_get_geometry (monitor, &geometry);
} else {
else
geometry.width = geometry.height = 0;
}
// When the geometry event comes after surface.configure,
// this entire height calculation does nothing.
@ -162,9 +159,8 @@ on_surface_configure(ServerContextService *self, PhoshLayerSurface *surface)
static void
make_window (ServerContextService *self)
{
if (self->window) {
if (self->window)
g_error("Window already present");
}
struct squeek_output_handle output = squeek_outputs_get_current(squeek_wayland->outputs);
squeek_uiman_set_output(self->manager, output);
@ -226,110 +222,64 @@ make_widget (ServerContextService *self)
gtk_widget_show_all(self->widget);
}
static void
server_context_service_real_show_keyboard (ServerContextService *self)
{
if (!self->window) {
make_window (self);
}
if (!self->widget) {
make_widget (self);
}
self->visible = TRUE;
gtk_widget_show (GTK_WIDGET(self->window));
}
static gboolean
show_keyboard_source_func(ServerContextService *context)
{
server_context_service_real_show_keyboard(context);
return G_SOURCE_REMOVE;
}
static void
server_context_service_real_hide_keyboard (ServerContextService *self)
{
gtk_widget_hide (GTK_WIDGET(self->window));
self->visible = FALSE;
}
static gboolean
hide_keyboard_source_func(ServerContextService *context)
{
server_context_service_real_hide_keyboard(context);
return G_SOURCE_REMOVE;
}
static gboolean
on_hide (ServerContextService *self)
{
server_context_service_real_hide_keyboard(self);
gtk_widget_hide (GTK_WIDGET(self->window));
self->hiding = 0;
return G_SOURCE_REMOVE;
}
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;
}
if (!self->window)
make_window (self);
if (!self->widget)
make_widget (self);
self->visible = TRUE;
gtk_widget_show (GTK_WIDGET(self->window));
}
static void
server_context_service_real_hide_keyboard (ServerContextService *self)
{
if (!self->hiding)
self->hiding = g_timeout_add (200, (GSourceFunc) on_hide, self);
self->visible = FALSE;
}
void
server_context_service_show_keyboard (ServerContextService *self)
{
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE(self));
if (self->hiding) {
g_source_remove (self->hiding);
self->hiding = 0;
}
if (!self->visible) {
g_idle_add((GSourceFunc)show_keyboard_source_func, self);
server_context_service_real_show_keyboard (self);
}
}
void
server_context_service_force_show_keyboard (ServerContextService *self)
{
if (!submission_hint_available(self->submission)) {
eekboard_context_service_set_hint_purpose(
self->state,
ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE,
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL
);
}
server_context_service_show_keyboard(self);
}
void
server_context_service_hide_keyboard (ServerContextService *self)
{
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE(self));
if (self->visible) {
g_idle_add((GSourceFunc)hide_keyboard_source_func, self);
server_context_service_real_hide_keyboard (self);
}
}
/// Meant for use by the input-method handler:
/// the visible keyboard is no longer needed.
/// The implementation will delay it slightly,
/// because the release may be due to switching from one text field to another.
/// In this case, the user doesn't really need the keyboard surface
/// to disappear completely.
void
server_context_service_release_visibility (ServerContextService *self)
{
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE(self));
if (!self->hiding && self->visible) {
self->hiding = g_timeout_add (200, (GSourceFunc) on_hide, self);
}
}
static void
server_context_service_set_physical_keyboard_present (ServerContextService *self, gboolean physical_keyboard_present)
{
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE (self));
squeek_visman_set_keyboard_present(self->vis_manager, physical_keyboard_present);
}
static void
server_context_service_set_property (GObject *object,
guint prop_id,
@ -343,7 +293,7 @@ server_context_service_set_property (GObject *object,
self->visible = g_value_get_boolean (value);
break;
case PROP_ENABLED:
server_context_service_set_physical_keyboard_present (self, !g_value_get_boolean (value));
server_context_service_set_enabled (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -418,14 +368,12 @@ server_context_service_class_init (ServerContextServiceClass *klass)
}
static void
server_context_service_init (ServerContextService *self) {}
static void
init (ServerContextService *self) {
server_context_service_init (ServerContextService *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;
@ -442,24 +390,27 @@ init (ServerContextService *self) {
}
ServerContextService *
server_context_service_new (EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman, struct vis_manager *visman)
server_context_service_new (EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman)
{
ServerContextService *ui = g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL);
ui->submission = submission;
ui->state = self;
ui->layout = layout;
ui->manager = uiman;
ui->vis_manager = visman;
init(ui);
return ui;
}
void
server_context_service_update_visible (ServerContextService *self, gboolean visible) {
if (visible) {
server_context_service_show_keyboard(self);
} else {
server_context_service_hide_keyboard(self);
}
}
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);
}

View File

@ -29,10 +29,11 @@ G_BEGIN_DECLS
/** Manages the lifecycle of the window displaying layouts. */
G_DECLARE_FINAL_TYPE (ServerContextService, server_context_service, SERVER, CONTEXT_SERVICE, GObject)
ServerContextService *server_context_service_new(EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman, struct vis_manager *visman);
ServerContextService *server_context_service_new(EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman);
enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *);
void server_context_service_force_show_keyboard (ServerContextService *self);
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 */

View File

@ -50,16 +50,9 @@ struct squeekboard {
};
GMainLoop *loop;
static gboolean opt_system = FALSE;
static gchar *opt_address = NULL;
static void
quit (void)
{
g_main_loop_quit (loop);
}
// D-Bus
static void
@ -83,6 +76,7 @@ on_name_lost (GDBusConnection *connection,
(void)name;
(void)user_data;
g_error("DBus unavailable, unclear how to continue.");
exit (1);
}
// Wayland
@ -137,67 +131,6 @@ static const struct wl_registry_listener registry_listener = {
#define SESSION_NAME "sm.puri.OSK0"
GDBusProxy *_proxy = NULL;
GDBusProxy *_client_proxy = NULL;
gchar *_client_path = NULL;
static void
send_quit_response (GDBusProxy *proxy)
{
g_debug ("Calling EndSessionResponse");
g_dbus_proxy_call (proxy, "EndSessionResponse",
g_variant_new ("(bs)", TRUE, ""), G_DBUS_CALL_FLAGS_NONE,
G_MAXINT, NULL, NULL, NULL);
}
static void
unregister_client (void)
{
g_autoptr (GError) error = NULL;
g_return_if_fail (G_IS_DBUS_PROXY (_proxy));
g_return_if_fail (_client_path != NULL);
g_debug ("Unregistering client");
g_dbus_proxy_call_sync (_proxy,
"UnregisterClient",
g_variant_new ("(o)", _client_path),
G_DBUS_CALL_FLAGS_NONE,
G_MAXINT,
NULL,
&error);
if (error) {
g_warning ("Failed to unregister client: %s", error->message);
}
g_clear_object (&_client_proxy);
g_clear_pointer (&_client_path, g_free);
}
static void client_proxy_signal (GDBusProxy *proxy,
const gchar *sender_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
if (g_str_equal (signal_name, "QueryEndSession")) {
g_debug ("Received QueryEndSession");
send_quit_response (proxy);
} else if (g_str_equal (signal_name, "CancelEndSession")) {
g_debug ("Received CancelEndSession");
} else if (g_str_equal (signal_name, "EndSession")) {
g_debug ("Received EndSession");
send_quit_response (proxy);
unregister_client ();
quit ();
} else if (g_str_equal (signal_name, "Stop")) {
g_debug ("Received Stop");
unregister_client ();
quit ();
}
}
static void
session_register(void) {
@ -218,8 +151,7 @@ session_register(void) {
return;
}
g_autoptr (GVariant) res = NULL;
res = g_dbus_proxy_call_sync(_proxy, "RegisterClient",
g_dbus_proxy_call_sync(_proxy, "RegisterClient",
g_variant_new("(ss)", SESSION_NAME, autostart_id),
G_DBUS_CALL_FLAGS_NONE, 1000, NULL, &error);
if (error) {
@ -228,22 +160,6 @@ session_register(void) {
g_clear_error(&error);
return;
}
g_variant_get (res, "(o)", &_client_path);
g_debug ("Registered client at '%s'", _client_path);
_client_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
0, NULL, "org.gnome.SessionManager", _client_path,
"org.gnome.SessionManager.ClientPrivate", NULL, &error);
if (error) {
g_warning ("Failed to get client proxy: %s", error->message);
g_clear_error (&error);
g_free (_client_path);
_client_path = NULL;
return;
}
g_signal_connect (_client_proxy, "g-signal", G_CALLBACK (client_proxy_signal), NULL);
}
int
@ -263,6 +179,7 @@ main (int argc, char **argv)
if (display == NULL) {
g_error ("Failed to get display: %m\n");
exit(1);
}
@ -275,12 +192,11 @@ main (int argc, char **argv)
if (!instance.wayland.seat) {
g_error("No seat Wayland global available.");
exit(1);
}
if (!instance.wayland.virtual_keyboard_manager) {
g_error("No virtual keyboard manager Wayland global available.");
}
if (!instance.wayland.layer_shell) {
g_error("No layer shell global available.");
exit(1);
}
if (!instance.wayland.input_method_manager) {
@ -297,13 +213,12 @@ main (int argc, char **argv)
// dbus is not strictly necessary for the useful operation
// if text-input is used, as it can bring the keyboard in and out
GBusType bus_type;
if (opt_system) {
if (opt_system)
bus_type = G_BUS_TYPE_SYSTEM;
} else if (opt_address) {
else if (opt_address)
bus_type = G_BUS_TYPE_NONE;
} else {
else
bus_type = G_BUS_TYPE_SESSION;
}
GDBusConnection *connection = NULL;
GError *error = NULL;
@ -361,11 +276,8 @@ main (int argc, char **argv)
}
}
struct vis_manager *vis_manager = squeek_visman_new();
instance.submission = get_submission(instance.wayland.input_method_manager,
instance.wayland.virtual_keyboard_manager,
vis_manager,
instance.wayland.seat,
instance.settings_context);
@ -375,14 +287,15 @@ main (int argc, char **argv)
instance.settings_context,
instance.submission,
&instance.layout_choice,
instance.ui_manager,
vis_manager);
instance.ui_manager);
if (!ui_context) {
g_error("Could not initialize GUI");
exit(1);
}
instance.ui_context = ui_context;
squeek_visman_set_ui(vis_manager, instance.ui_context);
if (instance.submission) {
submission_set_ui(instance.submission, instance.ui_context);
}
if (instance.dbus_handler) {
dbus_handler_set_ui_context(instance.dbus_handler, instance.ui_context);
}
@ -390,7 +303,8 @@ main (int argc, char **argv)
session_register();
loop = g_main_loop_new (NULL, FALSE);
GMainLoop *loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
if (connection) {

View File

@ -4,20 +4,16 @@
#include "input-method-unstable-v2-client-protocol.h"
#include "virtual-keyboard-unstable-v1-client-protocol.h"
#include "eek/eek-types.h"
#include "src/ui_manager.h"
struct submission;
struct squeek_layout;
struct submission* get_submission(struct zwp_input_method_manager_v2 *immanager,
struct zwp_virtual_keyboard_manager_v1 *vkmanager,
struct vis_manager *vis_manager,
struct wl_seat *seat,
EekboardContextService *state);
// Defined in Rust
struct submission* submission_new(struct zwp_input_method_v2 *im, struct zwp_virtual_keyboard_v1 *vk, EekboardContextService *state, struct vis_manager *vis_manager);
uint8_t submission_hint_available(struct submission *self);
struct submission* submission_new(struct zwp_input_method_v2 *im, struct zwp_virtual_keyboard_v1 *vk, EekboardContextService *state);
void submission_set_ui(struct submission *self, ServerContextService *ui_context);
void submission_use_layout(struct submission *self, struct squeek_layout *layout, uint32_t time);
void submission_set_keyboard(struct submission *self, LevelKeyboard *keyboard, uint32_t time);
#endif

View File

@ -23,10 +23,8 @@ use ::action::Modifier;
use ::imservice;
use ::imservice::IMService;
use ::keyboard::{ KeyCode, KeyStateId, Modifiers, PressType };
use ::layout;
use ::ui_manager::VisibilityManager;
use ::layout::c::LevelKeyboard;
use ::util::vec_remove;
use ::vkeyboard;
use ::vkeyboard::VirtualKeyboard;
// traits
@ -39,11 +37,14 @@ pub mod c {
use std::os::raw::c_void;
use ::imservice::c::InputMethod;
use ::util::c::Wrapped;
use ::vkeyboard::c::ZwpVirtualKeyboardV1;
// The following defined in C
/// ServerContextService*
#[repr(transparent)]
pub struct UIManager(*const c_void);
/// EekboardContextService*
#[repr(transparent)]
pub struct StateManager(*const c_void);
@ -53,18 +54,12 @@ pub mod c {
fn submission_new(
im: *mut InputMethod,
vk: ZwpVirtualKeyboardV1,
state_manager: *const StateManager,
visibility_manager: Wrapped<VisibilityManager>,
state_manager: *const StateManager
) -> *mut Submission {
let imservice = if im.is_null() {
None
} else {
let visibility_manager = visibility_manager.clone_ref();
Some(IMService::new(
im,
state_manager,
Box::new(move |active| visibility_manager.borrow_mut().set_im_active(active)),
))
Some(IMService::new(im, state_manager))
};
// TODO: add vkeyboard too
Box::<Submission>::into_raw(Box::new(
@ -73,37 +68,39 @@ pub mod c {
modifiers_active: Vec::new(),
virtual_keyboard: VirtualKeyboard(vk),
pressed: Vec::new(),
keymap_fds: Vec::new(),
keymap_idx: None,
}
))
}
/// Use to initialize the UI reference
#[no_mangle]
pub extern "C"
fn submission_use_layout(
fn submission_set_ui(submission: *mut Submission, ui_manager: *const UIManager) {
if submission.is_null() {
panic!("Null submission pointer");
}
let submission: &mut Submission = unsafe { &mut *submission };
if let Some(ref mut imservice) = &mut submission.imservice {
imservice.ui_manager = if ui_manager.is_null() {
None
} else {
Some(ui_manager)
}
};
}
#[no_mangle]
pub extern "C"
fn submission_set_keyboard(
submission: *mut Submission,
layout: *const layout::Layout,
keyboard: LevelKeyboard,
time: u32,
) {
if submission.is_null() {
panic!("Null submission pointer");
}
let submission: &mut Submission = unsafe { &mut *submission };
let layout = unsafe { &*layout };
submission.use_layout(layout, Timestamp(time));
}
#[no_mangle]
pub extern "C"
fn submission_hint_available(submission: *mut Submission) -> u8 {
if submission.is_null() {
panic!("Null submission pointer");
}
let submission: &mut Submission = unsafe { &mut *submission };
let active = submission.imservice.as_ref()
.map(|imservice| imservice.is_active());
(Some(true) == active) as u8
submission.update_keymap(keyboard, Timestamp(time));
}
}
@ -122,8 +119,6 @@ pub struct Submission {
virtual_keyboard: VirtualKeyboard,
modifiers_active: Vec<(KeyStateId, Modifier)>,
pressed: Vec<(KeyStateId, SubmittedAction)>,
keymap_fds: Vec<vkeyboard::c::KeyMap>,
keymap_idx: Option<usize>,
}
pub enum SubmitData<'a> {
@ -149,7 +144,7 @@ impl Submission {
enum Outcome {
Submitted(Result<(), imservice::SubmitError>),
NotSubmitted,
}
};
let submit_outcome = match data {
SubmitData::Text(text) => {
@ -182,34 +177,11 @@ impl Submission {
let submit_action = match was_committed_as_text {
true => SubmittedAction::IMService,
false => {
let keycodes_count = keycodes.len();
for keycode in keycodes.iter() {
self.select_keymap(keycode.keymap_idx, time);
let keycode = keycode.code;
match keycodes_count {
// Pressing a key made out of a single keycode is simple:
// press on press, release on release.
1 => self.virtual_keyboard.switch(
keycode,
PressType::Pressed,
time,
),
// A key made of multiple keycodes
// has to submit them one after the other.
_ => {
self.virtual_keyboard.switch(
keycode.clone(),
PressType::Pressed,
time,
);
self.virtual_keyboard.switch(
keycode.clone(),
PressType::Released,
time,
);
},
};
}
self.virtual_keyboard.switch(
keycodes,
PressType::Pressed,
time,
);
SubmittedAction::VirtualKeyboard(keycodes.clone())
},
};
@ -227,21 +199,11 @@ impl Submission {
// no matter if the imservice got activated,
// keys must be released
SubmittedAction::VirtualKeyboard(keycodes) => {
let keycodes_count = keycodes.len();
match keycodes_count {
1 => {
let keycode = &keycodes[0];
self.select_keymap(keycode.keymap_idx, time);
self.virtual_keyboard.switch(
keycode.code,
PressType::Released,
time,
);
},
// Design choice here: submit multiple all at press time
// and do nothing at release time.
_ => {},
};
self.virtual_keyboard.switch(
&keycodes,
PressType::Released,
time,
)
},
}
};
@ -270,7 +232,6 @@ impl Submission {
.map(|(_id, m)| match m {
Modifier::Control => Modifiers::CONTROL,
Modifier::Alt => Modifiers::MOD1,
Modifier::Mod4 => Modifiers::MOD4,
})
.fold(Modifiers::empty(), |m, n| m | n);
self.virtual_keyboard.set_modifiers_state(raw_modifiers);
@ -313,7 +274,6 @@ impl Submission {
}
}
/// Changes keymap and clears pressed keys and modifiers.
///
/// It's not obvious if clearing is the right thing to do,
@ -323,28 +283,9 @@ impl Submission {
/// Alternatively, modifiers could be restored on the new keymap.
/// That approach might be difficult
/// due to modifiers meaning different things in different keymaps.
fn select_keymap(&mut self, idx: usize, time: Timestamp) {
if self.keymap_idx != Some(idx) {
self.keymap_idx = Some(idx);
self.clear_all_modifiers();
self.release_all_virtual_keys(time);
let keymap = &self.keymap_fds[idx];
self.virtual_keyboard.update_keymap(keymap);
}
}
pub fn use_layout(&mut self, layout: &layout::Layout, time: Timestamp) {
self.keymap_fds = layout.keymaps.iter()
.map(|keymap_str| vkeyboard::c::KeyMap::from_cstr(
keymap_str.as_c_str()
))
.collect();
self.keymap_idx = None;
// This can probably be eliminated,
// because key presses can trigger an update anyway.
// However, self.keymap_idx needs to become Option<>
// in order to force update on new layouts.
self.select_keymap(0, time);
pub fn update_keymap(&mut self, keyboard: LevelKeyboard, time: Timestamp) {
self.clear_all_modifiers();
self.release_all_virtual_keys(time);
self.virtual_keyboard.update_keymap(keyboard);
}
}

View File

@ -1,6 +1,6 @@
/*! Testing functionality */
use ::data::parsing::Layout;
use ::data::Layout;
use ::logging;
use xkbcommon::xkb;
@ -40,29 +40,21 @@ pub fn check_layout_file(path: &str) {
)
}
fn check_sym_in_keymap(state: &xkb::State, sym_name: &str) -> bool {
let sym = xkb::keysym_from_name(sym_name, xkb::KEYSYM_NO_FLAGS);
if sym == xkb::KEY_NoSymbol {
panic!("Entered invalid keysym: {}", sym_name);
}
let map = state.get_keymap();
let range = map.min_keycode()..=map.max_keycode();
range.flat_map(|code| state.key_get_syms(code))
.find(|s| **s == sym)
.is_some()
}
fn check_sym_presence(
states: &[xkb::State],
state: &xkb::State,
sym_name: &str,
handler: &mut dyn logging::Handler,
) {
let found = states.iter()
.position(|state| {
check_sym_in_keymap(&state, sym_name)
});
if let None = found {
let sym = xkb::keysym_from_name(sym_name, xkb::KEYSYM_NO_FLAGS);
if sym == xkb::KEY_NoSymbol {
panic!(format!("Entered invalid keysym: {}", sym_name));
}
let map = state.get_keymap();
let range = map.min_keycode()..=map.max_keycode();
let found = range.flat_map(|code| state.key_get_syms(code))
.find(|s| **s == sym)
.is_some();
if !found {
handler.handle(
logging::Level::Surprise,
&format!("There's no way to input the keysym {} on this layout", sym_name),
@ -79,27 +71,26 @@ fn check_layout(layout: Layout, allow_missing_return: bool) {
}
let layout = layout.expect("layout broken");
let xkb_states: Vec<xkb::State> = layout.keymaps.iter()
.map(|keymap_str| {
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let keymap_str = keymap_str
.clone()
.into_string().expect("Failed to decode keymap string");
let keymap = xkb::Keymap::new_from_string(
&context,
keymap_str.clone(),
xkb::KEYMAP_FORMAT_TEXT_V1,
xkb::KEYMAP_COMPILE_NO_FLAGS,
).expect("Failed to create keymap");
xkb::State::new(&keymap)
})
.collect();
check_sym_presence(&xkb_states, "BackSpace", &mut handler);
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let keymap_str = layout.keymap_str
.clone()
.into_string().expect("Failed to decode keymap string");
let keymap = xkb::Keymap::new_from_string(
&context,
keymap_str.clone(),
xkb::KEYMAP_FORMAT_TEXT_V1,
xkb::KEYMAP_COMPILE_NO_FLAGS,
).expect("Failed to create keymap");
let state = xkb::State::new(&keymap);
check_sym_presence(&state, "BackSpace", &mut handler);
let mut printer = logging::Print;
check_sym_presence(
&xkb_states,
&state,
"Return",
if allow_missing_return { &mut printer }
else { &mut handler },
@ -111,19 +102,10 @@ fn check_layout(layout: Layout, allow_missing_return: bool) {
for (_x, button) in row.get_buttons() {
let keystate = button.state.borrow();
for keycode in &keystate.keycodes {
match xkb_states[keycode.keymap_idx].key_get_one_sym(keycode.code) {
match state.key_get_one_sym(*keycode) {
xkb::KEY_NoSymbol => {
eprintln!(
"keymap {}: {}",
keycode.keymap_idx,
layout.keymaps[keycode.keymap_idx].to_str().unwrap(),
);
panic!(
"Keysym for code {:?} on key {} ({:?}) can't be resolved",
keycode,
button.name.to_string_lossy(),
button.name,
);
eprintln!("{}", keymap_str);
panic!("Keysym {} on key {:?} can't be resolved", keycode, button.name);
},
_ => {},
}

View File

@ -3,7 +3,6 @@
#include <inttypes.h>
#include "eek/eek-types.h"
#include "outputs.h"
struct ui_manager;
@ -12,9 +11,4 @@ struct ui_manager *squeek_uiman_new(void);
void squeek_uiman_set_output(struct ui_manager *uiman, struct squeek_output_handle output);
uint32_t squeek_uiman_get_perceptual_height(struct ui_manager *uiman);
struct vis_manager;
struct vis_manager *squeek_visman_new(void);
void squeek_visman_set_ui(struct vis_manager *visman, ServerContextService *ui_context);
void squeek_visman_set_keyboard_present(struct vis_manager *visman, uint32_t keyboard_present);
#endif

View File

@ -10,48 +10,9 @@
use std::cmp::min;
use ::outputs::c::OutputHandle;
pub mod c {
mod c {
use super::*;
use std::os::raw::c_void;
use ::util::c::Wrapped;
/// ServerContextService*
#[repr(transparent)]
pub struct UIManager(*const c_void);
extern "C" {
pub fn server_context_service_update_visible(imservice: *const UIManager, active: u32);
pub fn server_context_service_release_visibility(imservice: *const UIManager);
}
#[no_mangle]
pub extern "C"
fn squeek_visman_new() -> Wrapped<VisibilityManager> {
Wrapped::new(VisibilityManager {
ui_manager: None,
visibility_state: VisibilityFactors {
im_active: false,
physical_keyboard_present: false,
}
})
}
/// Use to initialize the UI reference
#[no_mangle]
pub extern "C"
fn squeek_visman_set_ui(visman: Wrapped<VisibilityManager>, ui_manager: *const UIManager) {
let visman = visman.clone_ref();
let mut visman = visman.borrow_mut();
visman.set_ui_manager(Some(ui_manager))
}
#[no_mangle]
pub extern "C"
fn squeek_visman_set_keyboard_present(visman: Wrapped<VisibilityManager>, present: u32) {
let visman = visman.clone_ref();
let mut visman = visman.borrow_mut();
visman.set_keyboard_present(present != 0)
}
#[no_mangle]
pub extern "C"
@ -118,131 +79,3 @@ impl Manager {
}
}
}
#[derive(PartialEq, Debug)]
enum Visibility {
Hidden,
Visible,
}
#[derive(Debug)]
enum VisibilityTransition {
/// Hide immediately
Hide,
/// Hide if no show request comes soon
Release,
/// Show instantly
Show,
/// Don't do anything
NoTransition,
}
/// Contains visibility policy
#[derive(Clone, Debug)]
struct VisibilityFactors {
im_active: bool,
physical_keyboard_present: bool,
}
impl VisibilityFactors {
/// Static policy.
/// Use when transitioning from an undefined state (e.g. no UI before).
fn desired(&self) -> Visibility {
match self {
VisibilityFactors {
im_active: true,
physical_keyboard_present: false,
} => Visibility::Visible,
_ => Visibility::Hidden,
}
}
/// Stateful policy
fn transition_to(&self, next: &Self) -> VisibilityTransition {
use self::Visibility::*;
let im_deactivation = self.im_active && !next.im_active;
match (self.desired(), next.desired(), im_deactivation) {
(Visible, Hidden, true) => VisibilityTransition::Release,
(Visible, Hidden, _) => VisibilityTransition::Hide,
(Hidden, Visible, _) => VisibilityTransition::Show,
_ => VisibilityTransition::NoTransition,
}
}
}
// Temporary struct for migration. Should be integrated with Manager eventually.
pub struct VisibilityManager {
/// Owned reference. Be careful, it's shared with C at large
ui_manager: Option<*const c::UIManager>,
visibility_state: VisibilityFactors,
}
impl VisibilityManager {
fn set_ui_manager(&mut self, ui_manager: Option<*const c::UIManager>) {
let new = VisibilityManager {
ui_manager,
..unsafe { self.clone() }
};
self.apply_changes(new);
}
fn apply_changes(&mut self, new: Self) {
if let Some(ui) = &new.ui_manager {
if self.ui_manager.is_none() {
// Previous state was never applied, so effectively undefined.
// Just apply the new one.
let new_state = new.visibility_state.desired();
unsafe {
c::server_context_service_update_visible(
*ui,
(new_state == Visibility::Visible) as u32,
);
}
} else {
match self.visibility_state.transition_to(&new.visibility_state) {
VisibilityTransition::Hide => unsafe {
c::server_context_service_update_visible(*ui, 0);
},
VisibilityTransition::Show => unsafe {
c::server_context_service_update_visible(*ui, 1);
},
VisibilityTransition::Release => unsafe {
c::server_context_service_release_visibility(*ui);
},
VisibilityTransition::NoTransition => {}
}
}
}
*self = new;
}
pub fn set_im_active(&mut self, im_active: bool) {
let new = VisibilityManager {
visibility_state: VisibilityFactors {
im_active,
..self.visibility_state.clone()
},
..unsafe { self.clone() }
};
self.apply_changes(new);
}
pub fn set_keyboard_present(&mut self, keyboard_present: bool) {
let new = VisibilityManager {
visibility_state: VisibilityFactors {
physical_keyboard_present: keyboard_present,
..self.visibility_state.clone()
},
..unsafe { self.clone() }
};
self.apply_changes(new);
}
/// The struct is not really safe to clone due to the ui_manager reference.
/// This is only a helper for getting desired visibility.
unsafe fn clone(&self) -> Self {
VisibilityManager {
ui_manager: self.ui_manager.clone(),
visibility_state: self.visibility_state.clone(),
}
}
}

View File

@ -203,23 +203,6 @@ pub fn vec_remove<T, F: FnMut(&T) -> bool>(v: &mut Vec<T>, pred: F) -> Option<T>
idx.map(|idx| v.remove(idx))
}
/// Repeats all the items of the iterator forever,
/// but returns the cycle number alongside.
/// Inefficient due to all the vectors, but doesn't have to be fast.
pub fn cycle_count<T, I: Clone + Iterator<Item=T>>(iter: I)
-> impl Iterator<Item=(T, usize)>
{
let numbered_copies = vec![iter].into_iter()
.cycle()
.enumerate();
numbered_copies.flat_map(|(idx, cycle)|
// Pair each element from the cycle with a copy of the index.
cycle.zip(
vec![idx].into_iter().cycle() // Repeat the index forever.
)
)
}
#[cfg(test)]
mod tests {
use super::*;
@ -234,12 +217,4 @@ mod tests {
assert_eq!(s.insert(Pointer(Rc::new(2u32))), true);
assert_eq!(s.remove(&Pointer(first)), true);
}
#[test]
fn check_count() {
assert_eq!(
cycle_count(5..8).take(7).collect::<Vec<_>>(),
vec![(5, 0), (6, 0), (7, 0), (5, 1), (6, 1), (7, 1), (5, 2)]
);
}
}

View File

@ -1,46 +1,20 @@
/*! Managing the events belonging to virtual-keyboard interface. */
use ::keyboard::{ Modifiers, PressType };
use ::keyboard::{ KeyCode, Modifiers, PressType };
use ::layout::c::LevelKeyboard;
use ::submission::Timestamp;
/// Standard xkb keycode
type KeyCode = u32;
/// Gathers stuff defined in C or called by C
pub mod c {
use std::ffi::CStr;
use std::os::raw::{ c_char, c_void };
use super::*;
use std::os::raw::c_void;
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct ZwpVirtualKeyboardV1(*const c_void);
#[repr(C)]
pub struct KeyMap {
fd: u32,
fd_len: usize,
}
impl KeyMap {
pub fn from_cstr(s: &CStr) -> KeyMap {
unsafe {
squeek_key_map_from_str(s.as_ptr())
}
}
}
impl Drop for KeyMap {
fn drop(&mut self) {
unsafe {
close(self.fd as u32);
}
}
}
#[no_mangle]
extern "C" {
// From libc, to let KeyMap get deallocated.
fn close(fd: u32);
pub fn eek_virtual_keyboard_v1_key(
virtual_keyboard: ZwpVirtualKeyboardV1,
timestamp: u32,
@ -50,15 +24,13 @@ pub mod c {
pub fn eek_virtual_keyboard_update_keymap(
virtual_keyboard: ZwpVirtualKeyboardV1,
keymap: *const KeyMap,
keyboard: LevelKeyboard,
);
pub fn eek_virtual_keyboard_set_modifiers(
virtual_keyboard: ZwpVirtualKeyboardV1,
modifiers: u32,
);
pub fn squeek_key_map_from_str(keymap_str: *const c_char) -> KeyMap;
}
}
@ -69,15 +41,35 @@ impl VirtualKeyboard {
// TODO: error out if keymap not set
pub fn switch(
&self,
keycode: KeyCode,
keycodes: &[KeyCode],
action: PressType,
timestamp: Timestamp,
) {
let keycode = keycode - 8;
unsafe {
c::eek_virtual_keyboard_v1_key(
self.0, timestamp.0, keycode, action.clone() as u32
);
let keycodes_count = keycodes.len();
for keycode in keycodes.iter() {
let keycode = keycode - 8;
match (action, keycodes_count) {
// Pressing a key made out of a single keycode is simple:
// press on press, release on release.
(_, 1) => unsafe {
c::eek_virtual_keyboard_v1_key(
self.0, timestamp.0, keycode, action.clone() as u32
);
},
// A key made of multiple keycodes
// has to submit them one after the other
(PressType::Pressed, _) => unsafe {
c::eek_virtual_keyboard_v1_key(
self.0, timestamp.0, keycode, PressType::Pressed as u32
);
c::eek_virtual_keyboard_v1_key(
self.0, timestamp.0, keycode, PressType::Released as u32
);
},
// Design choice here: submit multiple all at press time
// and do nothing at release time
(PressType::Released, _) => {},
}
}
}
@ -88,12 +80,9 @@ impl VirtualKeyboard {
}
}
pub fn update_keymap(&self, keymap: &c::KeyMap) {
pub fn update_keymap(&self, keyboard: LevelKeyboard) {
unsafe {
c::eek_virtual_keyboard_update_keymap(
self.0,
keymap as *const c::KeyMap,
);
c::eek_virtual_keyboard_update_keymap(self.0, keyboard);
}
}
}

View File

@ -14,10 +14,10 @@ eek_virtual_keyboard_v1_key(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard
}
void eek_virtual_keyboard_update_keymap(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, struct keymap *keymap) {
void eek_virtual_keyboard_update_keymap(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, const LevelKeyboard *keyboard) {
zwp_virtual_keyboard_v1_keymap(zwp_virtual_keyboard_v1,
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
keymap->fd, keymap->fd_len);
keyboard->keymap.fd, keyboard->keymap.fd_len);
}
void

View File

@ -46,78 +46,40 @@ endforeach
# The layout test is in the examples directory
# due to the way Cargo builds executables
# and the need to call it manually.
# This is the list of tested builtin layouts.
# Please keep each block alphabetical!
# Please keep shapes (with _) on the same line,
# variants (with +) on separate lines.
# and the need to call it manually
foreach layout : [
# This is the fallback layout,
# so stays first to make sure it never goes missing.
'us', 'us_wide',
# Block: Languages
'ara', 'ara_wide',
'be', 'be_wide',
'bg',
'bg+phonetic',
'br',
'ch+fr',
'cz', 'cz_wide',
'cz+qwerty', 'cz+qwerty_wide',
'be', 'be_wide',
'de', 'de_wide',
'dk',
'epo',
'es',
'es+cat',
'fi',
'fr', 'fr_wide',
'gr',
'il',
'ir',
'it',
'it+fur',
'jp+kana','jp+kana_wide',
'no',
'number',
'pl', 'pl_wide',
'ru',
'se',
'th', 'th_wide',
'ua',
'us+colemak', 'us+colemak_wide',
'us+dvorak', 'us+dvorak_wide',
'terminal', 'terminal_wide',
# Terminal keyboards
'terminal/fr',
'terminal/us',
'terminal/us_wide',
# Block: Not languages.
'emoji/us',
'number/us',
'emoji',
]
extra = []
if layout.startswith('emoji/')
if layout == 'emoji'
extra += ['allow_missing_return']
endif
# Older Cargo seens to be sensitive to something
# about the RUST_FLAGS env var, and rebuilds all tests when it's set,
# increasing test time by 2 orders of magnitude.
# Let it have its way.
if get_option('legacy') == true
timeout = 300
else
timeout = 30
endif
test(
'test_layout_' + layout,
cargo_script,
args: ['run'] + cargo_build_flags
+ ['--example', 'test_layout', '--', layout]
+ extra,
timeout: timeout,
workdir: meson.build_root(),
)
endforeach