Compare commits
196 Commits
x11kb
...
pureos/1.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 8293c5f10d | |||
| 601c835416 | |||
| 07d7486e06 | |||
| 5cb70a096c | |||
| cb211bb764 | |||
| 8c8728aa0f | |||
| f71e769315 | |||
| 273179e1ec | |||
| eb4b630b39 | |||
| b60ebdbd99 | |||
| 99f062fe31 | |||
| 0bc654b832 | |||
| 00e9641a5f | |||
| ea3da22f9b | |||
| 8aefae9634 | |||
| 52e2384f72 | |||
| 0eb9d89de3 | |||
| c23b6f5f50 | |||
| e4f1b121eb | |||
| 4f3bec3989 | |||
| 4fdce2802a | |||
| 99c04fd8f5 | |||
| 2b7e8f829e | |||
| 1908769032 | |||
| 93e4345e82 | |||
| acac00bc88 | |||
| ac03c26d5d | |||
| 608be930f7 | |||
| 36d4f6726c | |||
| d289129404 | |||
| e49de34d0e | |||
| 225e53df07 | |||
| 37820bf169 | |||
| d8e58fd774 | |||
| fcb57c9093 | |||
| b578414655 | |||
| 89b1f51ed5 | |||
| 7b1755a489 | |||
| 676a2b60ac | |||
| 32dc25dfbf | |||
| 484d64cfb9 | |||
| 637da2c177 | |||
| 3210a363ab | |||
| 8da8d55b98 | |||
| d8ca9f47ca | |||
| a3638f4bfb | |||
| f45f2db948 | |||
| 40bf3ca5de | |||
| e800a88893 | |||
| 24c3fac505 | |||
| 46f8790fc0 | |||
| 3cdced0c0c | |||
| bffd212e10 | |||
| c2c379b870 | |||
| 1ae29ff7bc | |||
| d3cd7dc11f | |||
| d3695d3bc9 | |||
| 11952ed29a | |||
| 842e616cd3 | |||
| a265427e8e | |||
| e6c45a63fb | |||
| e82e256581 | |||
| bedabb6188 | |||
| a030f55a7c | |||
| 49aa4256a9 | |||
| eb7d0d5db9 | |||
| 575619e812 | |||
| 630cfc8e59 | |||
| 2a11bce945 | |||
| a332efca45 | |||
| 5b3c185a16 | |||
| fefebf7f6e | |||
| 21c3a74019 | |||
| 47a483da2a | |||
| 0c179560b3 | |||
| 38842f9743 | |||
| 3cbfd8351c | |||
| 6e7c0e6f67 | |||
| 0e83697b61 | |||
| 66c3926eb2 | |||
| 1856e7023d | |||
| 976f0a6e37 | |||
| 4d24af4e1a | |||
| 422d06d582 | |||
| 4890c86b4e | |||
| b72c6b53e4 | |||
| 701168c32b | |||
| 658df98e18 | |||
| 6f7252ec7c | |||
| 558a2568e3 | |||
| 9517c347b6 | |||
| 8dd92c81e7 | |||
| 03ccfe77ad | |||
| c103b84fa6 | |||
| 9a72db2fcc | |||
| 61a84c47f1 | |||
| a9ecc13185 | |||
| 7143fb2497 | |||
| c6cc58fd8e | |||
| 9522d4e302 | |||
| 8f62520648 | |||
| e36c4e597f | |||
| 8ab6997b21 | |||
| 3b06eadef5 | |||
| 287e851770 | |||
| dfee95430d | |||
| fcd0eaddf2 | |||
| ba2e191918 | |||
| cc4f14e8c6 | |||
| 103e64b96c | |||
| 2796362d34 | |||
| af00d74f71 | |||
| 02d579d757 | |||
| 01d06d0f5f | |||
| 1d1c98c27a | |||
| 696d77293e | |||
| 225c204e37 | |||
| c3b428e517 | |||
| 1fe6d65525 | |||
| 39a3c40d67 | |||
| 963f52bbc3 | |||
| 9dcc4c9868 | |||
| df8e885983 | |||
| 540c4d9c05 | |||
| 42483234e3 | |||
| c9f9a3b577 | |||
| 81041b8035 | |||
| c731124f7b | |||
| fca8984225 | |||
| bd6ab663c0 | |||
| 4049e66307 | |||
| 046a516a11 | |||
| b5d1e8c3eb | |||
| aee296ad96 | |||
| 5f59db478a | |||
| dda070e84e | |||
| 17db3db296 | |||
| ebbb3b1138 | |||
| 277986bcdf | |||
| 96461cf2aa | |||
| 2029f48b4d | |||
| 943d2de536 | |||
| 5aa7334787 | |||
| 955a138849 | |||
| 44c80a0406 | |||
| 12c9ca1e02 | |||
| 91acfa0138 | |||
| cf09d1b3bc | |||
| 81fb7e0df3 | |||
| 0e533c5e94 | |||
| 8d01d17b8c | |||
| 74a5b0937b | |||
| 17ce0b6b46 | |||
| c0525946ae | |||
| 8bb5c4f16c | |||
| a0322f0d7e | |||
| d07b5ed0d6 | |||
| 153f9c39e5 | |||
| c0b6ea51fa | |||
| 5d81cf78f8 | |||
| 0ed1dd925a | |||
| 39464f9c99 | |||
| eeb7e252c7 | |||
| 65425ff928 | |||
| 229b3bac51 | |||
| a4e7ad06d3 | |||
| db298b0fb8 | |||
| 4373cf7bc3 | |||
| 2f613ea4c7 | |||
| 8f526bd357 | |||
| b77b3f7816 | |||
| 87eb775377 | |||
| f64e5a3627 | |||
| 595bbccfdf | |||
| afd47ef8b4 | |||
| 7e38d17cb7 | |||
| ef7df433d8 | |||
| 8e32de86a9 | |||
| 6871452c7b | |||
| 192824be39 | |||
| 938d3c335e | |||
| 9dd67ad2bc | |||
| 9f4cb3c791 | |||
| 6ed2a47620 | |||
| 4253bf1299 | |||
| d283ced2ce | |||
| 776c0c5f4b | |||
| 8cf6c5f948 | |||
| de3bf54dc9 | |||
| 2219eb67e1 | |||
| 61400c9584 | |||
| b21734bf57 | |||
| 93ac94b83f | |||
| 07bcaa8e2b | |||
| c16c686592 | |||
| 74479ff226 |
@ -136,7 +136,10 @@ 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
430
Cargo.lock
generated
@ -4,483 +4,481 @@
|
||||
name = "atk"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86b7499272acf036bb5820c6e346bbfb5acc5dceb104bc2c4fd7e6e33dfcde6a"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"atk-sys",
|
||||
"bitflags",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atk-sys"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e552c1776737a4c80110d06b36d099f47c727335f9aaa5d942a72b6863a8ec6f"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[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 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)",
|
||||
"bitflags",
|
||||
"cairo-sys-rs",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cairo-sys-rs"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff65ba02cac715be836f63429ab00a767d48336efc5497c5637afb53b4f14d63"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"glib-sys",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.54"
|
||||
version = "1.0.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.1"
|
||||
version = "2.33.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"bitflags",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.5"
|
||||
version = "0.4.8"
|
||||
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 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)",
|
||||
"bitflags",
|
||||
"cairo-rs",
|
||||
"cairo-sys-rs",
|
||||
"gdk-pixbuf",
|
||||
"gdk-sys",
|
||||
"gio",
|
||||
"gio-sys",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"pango",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdk-pixbuf"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9726408ee1bbada83094326a99b9c68fea275f9dbb515de242a69e72051f4fcc"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"gdk-pixbuf-sys",
|
||||
"gio",
|
||||
"gio-sys",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdk-pixbuf-sys"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8991b060a9e9161bafd09bf4a202e6fd404f5b4dd1a08d53a1e84256fb34ab0"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"gio-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdk-sys"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6adf679e91d1bff0c06860287f80403e7db54c2d2424dce0a470023b56c88fbb"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"cairo-sys-rs",
|
||||
"gdk-pixbuf-sys",
|
||||
"gio-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"pango-sys",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gio"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6261b5d34c30c2d59f879e643704cf54cb44731f3a2038000b68790c03e360e3"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"bitflags",
|
||||
"fragile",
|
||||
"gio-sys",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gio-sys"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fad225242b9eae7ec8a063bb86974aca56885014672375e5775dc0ea3533911"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be27232841baa43e0fd5ae003f7941925735b2f733a336dc75f07b9eff415e7b"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"bitflags",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib-sys"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95856f3802f446c05feffa5e24859fe6a183a7cb849c8449afc35c86b1e316e2"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gobject-sys"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31d1a804f62034eccf370006ccaef3708a71c31d561fee88564abe71177553d9"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"glib-sys",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gtk"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "709f1074259d4685b96133f92b75c7f35b504715b0fcdc96ec95de2607296a60"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gtk-sys"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53def660c7b48b00b510c81ef2d2fbd3c570f1527081d8d7947f471513e1a4c1"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"atk-sys",
|
||||
"cairo-sys-rs",
|
||||
"gdk-pixbuf-sys",
|
||||
"gdk-sys",
|
||||
"gio-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"pango-sys",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[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.71"
|
||||
version = "0.2.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.3"
|
||||
version = "0.5.4"
|
||||
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 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)",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pango"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "393fa071b144f8ffb83ede273758983cf414ca3c0b1d2a5a9ce325b3ba3dd786"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"bitflags",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"pango-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pango-sys"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86b93d84907b3cf0819bff8f13598ba72843bee579d5ebc2502e4b0367b4be7d"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.17"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.18"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.7"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
|
||||
dependencies = [
|
||||
"regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.18"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "rs"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"bitflags",
|
||||
"cairo-rs",
|
||||
"cairo-sys-rs",
|
||||
"clap",
|
||||
"gdk",
|
||||
"gio",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gtk",
|
||||
"gtk-sys",
|
||||
"maplit",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"xkbcommon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.111"
|
||||
version = "1.0.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
|
||||
dependencies = [
|
||||
"serde_derive 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.111"
|
||||
version = "1.0.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.8.13"
|
||||
version = "0.8.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"dtoa",
|
||||
"linked-hash-map",
|
||||
"serde",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.31"
|
||||
version = "1.0.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.7"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.8"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[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 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)",
|
||||
"libc",
|
||||
"memmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.4"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||
dependencies = [
|
||||
"linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
||||
[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"
|
||||
|
||||
@ -19,6 +19,7 @@ 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]
|
||||
|
||||
49
cargo_build.py
Normal file
49
cargo_build.py
Normal file
@ -0,0 +1,49 @@
|
||||
#!/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)
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
#!/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
|
||||
89
data/keyboards/be_wide.yaml
Normal file
89
data/keyboards/be_wide.yaml
Normal file
@ -0,0 +1,89 @@
|
||||
---
|
||||
outlines:
|
||||
default: { width: 54, height: 42 }
|
||||
altline: { width: 81, height: 42 }
|
||||
wide: { width: 100, height: 42 }
|
||||
spaceline: { width: 205, height: 42 }
|
||||
special: { width: 54, height: 42 }
|
||||
|
||||
views:
|
||||
base:
|
||||
- "a z e r t y u i o p"
|
||||
- "q s d f g h j k l m"
|
||||
- "Shift_L w x c v b n . BackSpace"
|
||||
- "show_numbers preferences space show_eschars Return"
|
||||
upper:
|
||||
- "A Z E R T Y U I O P"
|
||||
- "Q S D F G H J K L M"
|
||||
- "Shift_L W X C V B N , BackSpace"
|
||||
- "show_numbers preferences space show_eschars Return"
|
||||
numbers:
|
||||
- "1 2 3 4 5 6 7 8 9 0"
|
||||
- "@ # € % & - _ + ( )"
|
||||
- "show_symbols , \" ' colon ; ! ? BackSpace"
|
||||
- "show_letters preferences space show_eschars Return"
|
||||
symbols:
|
||||
- "~ ` | · √ π τ ÷ × ¶"
|
||||
- "© ® £ $ ¥ ^ ° * { }"
|
||||
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
|
||||
- "show_letters preferences space show_eschars Return"
|
||||
eschars:
|
||||
- "à â ç é è ê î ô ù û"
|
||||
- "À Â Ç É È Ê Î Ô Ù Û"
|
||||
- "show_numbers_from_symbols æ œ ä ë ï ö ü BackSpace"
|
||||
- "show_letters preferences space show_eschars Return"
|
||||
|
||||
buttons:
|
||||
Shift_L:
|
||||
action:
|
||||
locking:
|
||||
lock_view: "upper"
|
||||
unlock_view: "base"
|
||||
outline: "altline"
|
||||
icon: "key-shift"
|
||||
BackSpace:
|
||||
outline: "altline"
|
||||
icon: "edit-clear-symbolic"
|
||||
action: erase
|
||||
preferences:
|
||||
action: "show_prefs"
|
||||
outline: "special"
|
||||
icon: "keyboard-mode-symbolic"
|
||||
show_numbers:
|
||||
action:
|
||||
set_view: "numbers"
|
||||
outline: "wide"
|
||||
label: "123"
|
||||
show_numbers_from_symbols:
|
||||
action:
|
||||
set_view: "numbers"
|
||||
outline: "altline"
|
||||
label: "123"
|
||||
show_letters:
|
||||
action:
|
||||
set_view: "base"
|
||||
outline: "wide"
|
||||
label: "abc"
|
||||
show_symbols:
|
||||
action:
|
||||
set_view: "symbols"
|
||||
outline: "altline"
|
||||
label: "*/="
|
||||
show_eschars:
|
||||
action:
|
||||
locking:
|
||||
lock_view: "eschars"
|
||||
unlock_view: "base"
|
||||
outline: "altline"
|
||||
label: "âÂ"
|
||||
space:
|
||||
outline: "spaceline"
|
||||
text: " "
|
||||
Return:
|
||||
outline: "wide"
|
||||
icon: "key-enter"
|
||||
keysym: "Return"
|
||||
colon:
|
||||
text: ":"
|
||||
"\"":
|
||||
keysym: "quotedbl"
|
||||
78
data/keyboards/bg.yaml
Normal file
78
data/keyboards/bg.yaml
Normal file
@ -0,0 +1,78 @@
|
||||
---
|
||||
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"
|
||||
106
data/keyboards/cz+qwerty.yaml
Normal file
106
data/keyboards/cz+qwerty.yaml
Normal file
@ -0,0 +1,106 @@
|
||||
---
|
||||
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: ":"
|
||||
106
data/keyboards/cz+qwerty_wide.yaml
Normal file
106
data/keyboards/cz+qwerty_wide.yaml
Normal file
@ -0,0 +1,106 @@
|
||||
---
|
||||
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: ":"
|
||||
106
data/keyboards/cz.yaml
Normal file
106
data/keyboards/cz.yaml
Normal file
@ -0,0 +1,106 @@
|
||||
---
|
||||
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: ":"
|
||||
106
data/keyboards/cz_wide.yaml
Normal file
106
data/keyboards/cz_wide.yaml
Normal file
@ -0,0 +1,106 @@
|
||||
---
|
||||
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: ":"
|
||||
@ -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:
|
||||
- "~ ` ´ | · √ µ ÷ × ¶"
|
||||
|
||||
@ -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:
|
||||
- "~ ` ´ · © ® ÷ × ¶"
|
||||
|
||||
81
data/keyboards/epo.yaml
Normal file
81
data/keyboards/epo.yaml
Normal file
@ -0,0 +1,81 @@
|
||||
---
|
||||
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"
|
||||
87
data/keyboards/es+cat.yaml
Normal file
87
data/keyboards/es+cat.yaml
Normal file
@ -0,0 +1,87 @@
|
||||
---
|
||||
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: ":"
|
||||
|
||||
89
data/keyboards/fr_wide.yaml
Normal file
89
data/keyboards/fr_wide.yaml
Normal file
@ -0,0 +1,89 @@
|
||||
---
|
||||
outlines:
|
||||
default: { width: 54, height: 42 }
|
||||
altline: { width: 81, height: 42 }
|
||||
wide: { width: 100, height: 42 }
|
||||
spaceline: { width: 205, height: 42 }
|
||||
special: { width: 54, height: 42 }
|
||||
|
||||
views:
|
||||
base:
|
||||
- "a z e r t y u i o p"
|
||||
- "q s d f g h j k l m"
|
||||
- "Shift_L w x c v b n . BackSpace"
|
||||
- "show_numbers preferences space show_eschars Return"
|
||||
upper:
|
||||
- "A Z E R T Y U I O P"
|
||||
- "Q S D F G H J K L M"
|
||||
- "Shift_L W X C V B N , BackSpace"
|
||||
- "show_numbers preferences space show_eschars Return"
|
||||
numbers:
|
||||
- "1 2 3 4 5 6 7 8 9 0"
|
||||
- "@ # € % & - _ + ( )"
|
||||
- "show_symbols , \" ' colon ; ! ? BackSpace"
|
||||
- "show_letters preferences space show_eschars Return"
|
||||
symbols:
|
||||
- "~ ` | · √ π τ ÷ × ¶"
|
||||
- "© ® £ $ ¥ ^ ° * { }"
|
||||
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
|
||||
- "show_letters preferences space show_eschars Return"
|
||||
eschars:
|
||||
- "à â ç é è ê î ô ù û"
|
||||
- "À Â Ç É È Ê Î Ô Ù Û"
|
||||
- "show_numbers_from_symbols æ œ ä ë ï ö ü BackSpace"
|
||||
- "show_letters preferences space show_eschars Return"
|
||||
|
||||
buttons:
|
||||
Shift_L:
|
||||
action:
|
||||
locking:
|
||||
lock_view: "upper"
|
||||
unlock_view: "base"
|
||||
outline: "altline"
|
||||
icon: "key-shift"
|
||||
BackSpace:
|
||||
outline: "altline"
|
||||
icon: "edit-clear-symbolic"
|
||||
action: erase
|
||||
preferences:
|
||||
action: "show_prefs"
|
||||
outline: "special"
|
||||
icon: "keyboard-mode-symbolic"
|
||||
show_numbers:
|
||||
action:
|
||||
set_view: "numbers"
|
||||
outline: "wide"
|
||||
label: "123"
|
||||
show_numbers_from_symbols:
|
||||
action:
|
||||
set_view: "numbers"
|
||||
outline: "altline"
|
||||
label: "123"
|
||||
show_letters:
|
||||
action:
|
||||
set_view: "base"
|
||||
outline: "wide"
|
||||
label: "abc"
|
||||
show_symbols:
|
||||
action:
|
||||
set_view: "symbols"
|
||||
outline: "altline"
|
||||
label: "*/="
|
||||
show_eschars:
|
||||
action:
|
||||
locking:
|
||||
lock_view: "eschars"
|
||||
unlock_view: "base"
|
||||
outline: "altline"
|
||||
label: "âÂ"
|
||||
space:
|
||||
outline: "spaceline"
|
||||
text: " "
|
||||
Return:
|
||||
outline: "wide"
|
||||
icon: "key-enter"
|
||||
keysym: "Return"
|
||||
colon:
|
||||
text: ":"
|
||||
"\"":
|
||||
keysym: "quotedbl"
|
||||
71
data/keyboards/il.yaml
Normal file
71
data/keyboards/il.yaml
Normal file
@ -0,0 +1,71 @@
|
||||
---
|
||||
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: ":"
|
||||
|
||||
78
data/keyboards/ir.yaml
Normal file
78
data/keyboards/ir.yaml
Normal file
@ -0,0 +1,78 @@
|
||||
---
|
||||
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: ":"
|
||||
78
data/keyboards/ir_wide.yaml
Normal file
78
data/keyboards/ir_wide.yaml
Normal file
@ -0,0 +1,78 @@
|
||||
---
|
||||
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: ":"
|
||||
89
data/keyboards/it+fur.yaml
Normal file
89
data/keyboards/it+fur.yaml
Normal file
@ -0,0 +1,89 @@
|
||||
# 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"
|
||||
|
||||
@ -22,7 +22,7 @@ views:
|
||||
numbers:
|
||||
- "1 2 3 4 5 6 7 8 9 0"
|
||||
- "@ # € % & - _ + ( )"
|
||||
- "show_symbols , \" ' colon ; ! ? BackSpace"
|
||||
- "show_symbols , \" ' : ; ! ? BackSpace"
|
||||
- "show_letters show_eschars preferences space ? . Return"
|
||||
symbols:
|
||||
- "~ ` | · √ π τ ÷ × ¶"
|
||||
@ -84,7 +84,4 @@ buttons:
|
||||
outline: "altline"
|
||||
icon: "key-enter"
|
||||
keysym: "Return"
|
||||
colon:
|
||||
label: ":"
|
||||
"\"":
|
||||
keysym: "quotedbl"
|
||||
|
||||
|
||||
@ -438,7 +438,7 @@ buttons:
|
||||
unlock_view: "カタカナ"
|
||||
outline: "altline"
|
||||
label: "。"
|
||||
# Buttons for Latin charachters
|
||||
# Buttons for Latin characters
|
||||
RSYM1:
|
||||
action:
|
||||
locking:
|
||||
|
||||
@ -438,7 +438,7 @@ buttons:
|
||||
unlock_view: "カタカナ"
|
||||
outline: "altline"
|
||||
label: "。"
|
||||
# Buttons for Latin charachters
|
||||
# Buttons for Latin characters
|
||||
RSYM1:
|
||||
action:
|
||||
locking:
|
||||
|
||||
@ -2,9 +2,9 @@
|
||||
outlines:
|
||||
default: { width: 32, height: 52 }
|
||||
altline: { width: 48.39024, height: 52 }
|
||||
wide: { width: 62, height: 52 }
|
||||
outline7: { width: 88.97561, height: 52 }
|
||||
spaceline: { width: 150.5853, height: 52 }
|
||||
wide: { width: 64, height: 52 }
|
||||
spaceline: { width: 142, height: 52 }
|
||||
special: { width: 44, 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 \\ / < > = [ ] BackSpace"
|
||||
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
|
||||
- "show_letters preferences space . Return"
|
||||
|
||||
buttons:
|
||||
@ -42,17 +42,22 @@ buttons:
|
||||
action: erase
|
||||
preferences:
|
||||
action: "show_prefs"
|
||||
outline: "altline"
|
||||
outline: "special"
|
||||
icon: "keyboard-mode-symbolic"
|
||||
show_numbers:
|
||||
action:
|
||||
set_view: "numbers"
|
||||
outline: "altline"
|
||||
outline: "wide"
|
||||
label: "123"
|
||||
show_numbers_from_symbols:
|
||||
action:
|
||||
set_view: "numbers"
|
||||
outline: altline
|
||||
label: "123"
|
||||
show_letters:
|
||||
action:
|
||||
set_view: "base"
|
||||
outline: "altline"
|
||||
outline: "wide"
|
||||
label: "ABC"
|
||||
show_symbols:
|
||||
action:
|
||||
@ -60,7 +65,7 @@ buttons:
|
||||
outline: "altline"
|
||||
label: "*/="
|
||||
".":
|
||||
outline: altline
|
||||
outline: "special"
|
||||
space:
|
||||
outline: spaceline
|
||||
text: " "
|
||||
|
||||
@ -52,6 +52,8 @@ buttons:
|
||||
locking:
|
||||
lock_view: "upper_accents"
|
||||
unlock_view: "accents"
|
||||
looks_locked_from:
|
||||
- "upper"
|
||||
outline: "altline"
|
||||
icon: "key-shift"
|
||||
BackSpace:
|
||||
@ -94,6 +96,8 @@ buttons:
|
||||
locking:
|
||||
lock_view: "upper_accents"
|
||||
unlock_view: "upper"
|
||||
looks_locked_from:
|
||||
- "accents"
|
||||
outline: "altline"
|
||||
label: "ĄĘ"
|
||||
period:
|
||||
|
||||
220
data/keyboards/terminal/fr.yaml
Normal file
220
data/keyboards/terminal/fr.yaml
Normal file
@ -0,0 +1,220 @@
|
||||
---
|
||||
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"
|
||||
223
data/keyboards/terminal/fr_wide.yaml
Normal file
223
data/keyboards/terminal/fr_wide.yaml
Normal file
@ -0,0 +1,223 @@
|
||||
---
|
||||
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"
|
||||
@ -147,9 +147,6 @@ buttons:
|
||||
Pause:
|
||||
outline: "action"
|
||||
keysym: "Pause"
|
||||
Menu:
|
||||
outline: "action"
|
||||
keysym: "Menu"
|
||||
Break:
|
||||
outline: "action"
|
||||
keysym: "Break"
|
||||
@ -201,4 +198,3 @@ buttons:
|
||||
modifier: "Alt"
|
||||
outline: "small"
|
||||
label: "Alt"
|
||||
|
||||
208
data/keyboards/terminal/us_wide.yaml
Normal file
208
data/keyboards/terminal/us_wide.yaml
Normal file
@ -0,0 +1,208 @@
|
||||
---
|
||||
outlines:
|
||||
default: { width: 54, height: 37 }
|
||||
action: { width: 90, height: 37 }
|
||||
altline: { width: 81, height: 37 }
|
||||
wide: { width: 90, height: 37 }
|
||||
spaceline: { width: 225, height: 37 }
|
||||
special: { width: 54, height: 37 }
|
||||
small: { width: 67.4, height: 22 }
|
||||
|
||||
views:
|
||||
base:
|
||||
- "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
|
||||
- "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 space show_actions Return"
|
||||
upper:
|
||||
- "EscSmall TabSmall Ctrl Alt PgUp PgDn Home End"
|
||||
- "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 space 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 period Return"
|
||||
symbols:
|
||||
- "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
|
||||
- "~ ` | · √ π τ ÷ × ¶"
|
||||
- "© ® £ € ¥ ^ ° @ { }"
|
||||
- "show_numbers_from_symbols \\ % < > = [ ] BackSpace"
|
||||
- "show_letters preferences space period 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:
|
||||
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_actions:
|
||||
action:
|
||||
set_view: "actions"
|
||||
outline: "altline"
|
||||
label: ">_"
|
||||
period:
|
||||
outline: "altline"
|
||||
text: "."
|
||||
space:
|
||||
outline: "spaceline"
|
||||
text: " "
|
||||
Return:
|
||||
outline: "wide"
|
||||
icon: "key-enter"
|
||||
keysym: "Return"
|
||||
colon:
|
||||
text: ":"
|
||||
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"
|
||||
80
data/keyboards/th.yaml
Normal file
80
data/keyboards/th.yaml
Normal file
@ -0,0 +1,80 @@
|
||||
---
|
||||
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: ":"
|
||||
84
data/keyboards/th_wide.yaml
Normal file
84
data/keyboards/th_wide.yaml
Normal file
@ -0,0 +1,84 @@
|
||||
---
|
||||
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: ":"
|
||||
78
data/keyboards/us+colemak.yaml
Normal file
78
data/keyboards/us+colemak.yaml
Normal file
@ -0,0 +1,78 @@
|
||||
---
|
||||
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: ":"
|
||||
78
data/keyboards/us+colemak_wide.yaml
Normal file
78
data/keyboards/us+colemak_wide.yaml
Normal file
@ -0,0 +1,78 @@
|
||||
---
|
||||
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: ":"
|
||||
89
data/keyboards/us+dvorak.yaml
Normal file
89
data/keyboards/us+dvorak.yaml
Normal file
@ -0,0 +1,89 @@
|
||||
---
|
||||
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.
|
||||
89
data/keyboards/us+dvorak_wide.yaml
Normal file
89
data/keyboards/us+dvorak_wide.yaml
Normal file
@ -0,0 +1,89 @@
|
||||
---
|
||||
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.
|
||||
13
data/langs/bg-BG.txt
Normal file
13
data/langs/bg-BG.txt
Normal file
@ -0,0 +1,13 @@
|
||||
bg Български
|
||||
de Немски
|
||||
es Испански
|
||||
emoji Емоджи
|
||||
fi Френски
|
||||
gr Гръцки
|
||||
it Италянски
|
||||
no Норевежки
|
||||
pl Полски
|
||||
ru Руски
|
||||
se Шведски
|
||||
terminal Терминал
|
||||
us Английски (САЩ)
|
||||
21
data/langs/cs-CZ.txt
Normal file
21
data/langs/cs-CZ.txt
Normal file
@ -0,0 +1,21 @@
|
||||
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)
|
||||
2
data/langs/fa-IR.txt
Normal file
2
data/langs/fa-IR.txt
Normal file
@ -0,0 +1,2 @@
|
||||
emoji ایموجی
|
||||
terminal ترمینال
|
||||
18
data/langs/fur-IT.txt
Normal file
18
data/langs/fur-IT.txt
Normal file
@ -0,0 +1,18 @@
|
||||
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)
|
||||
19
data/langs/he-IL.txt
Normal file
19
data/langs/he-IL.txt
Normal file
@ -0,0 +1,19 @@
|
||||
be בלגית
|
||||
br פורטוגזית (ברזיל)
|
||||
cz צ'כית
|
||||
de גרמנית
|
||||
dk דנית
|
||||
es ספרדית
|
||||
emoji אימוג'י
|
||||
fi פינית
|
||||
fr צרפתית
|
||||
gr יוונית
|
||||
il עברית
|
||||
it איטלקית
|
||||
no נורווגית
|
||||
pl פולנית
|
||||
ru רוסית
|
||||
se שוודית
|
||||
terminal טרמינל
|
||||
ua אוקראינית
|
||||
us אנגלית (ארה"ב)
|
||||
@ -31,11 +31,16 @@ sq_button.wide {
|
||||
border-color: #3e3a44;
|
||||
}
|
||||
|
||||
sq_button.locked {
|
||||
sq_button.latched {
|
||||
background: #ffffff;
|
||||
color: #2b292f;
|
||||
}
|
||||
|
||||
sq_button.locked {
|
||||
background: #ffffff;
|
||||
color: #1c71d8;
|
||||
}
|
||||
|
||||
sq_button.action {
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
@ -34,11 +34,16 @@ sq_button.wide {
|
||||
border-color: @borders; /* #3e3a44; */
|
||||
}
|
||||
|
||||
sq_button.locked {
|
||||
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;*/
|
||||
}
|
||||
|
||||
sq_button.action {
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
239
debian/changelog
vendored
239
debian/changelog
vendored
@ -1,3 +1,242 @@
|
||||
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 ]
|
||||
|
||||
3
debian/check_release.py
vendored
3
debian/check_release.py
vendored
@ -5,6 +5,7 @@ Feed it the first changelog line, and then all available tags.
|
||||
"""
|
||||
|
||||
import re, sys
|
||||
tag = "v" + re.findall("\\((.*)\\)", input())[0]
|
||||
version = re.findall("\\((.*)\\)", input())[0]
|
||||
tag = 'v' + re.findall("([0-9]+\\.[0-9]+\\.[0-9]+).*", version)[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!")
|
||||
|
||||
3
debian/control
vendored
3
debian/control
vendored
@ -26,6 +26,7 @@ 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
|
||||
@ -38,6 +39,8 @@ Depends:
|
||||
gnome-themes-extra-data,
|
||||
${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
Breaks:
|
||||
librem5-base (<< 24),
|
||||
Description: On-screen keyboard for Wayland
|
||||
Virtual keyboard supporting Wayland, built primarily for the Librem 5 phone.
|
||||
|
||||
|
||||
21
debian/rules
vendored
21
debian/rules
vendored
@ -2,6 +2,27 @@
|
||||
|
||||
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))
|
||||
|
||||
@ -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
|
||||
- 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))
|
||||
|
||||
Bad example:
|
||||
|
||||
@ -179,7 +179,10 @@ Dependencies must be specified in `Cargo.toml` with 2 numbers: "major.minor". Si
|
||||
|
||||
```
|
||||
cd build_dir
|
||||
ninja build src/Cargo.toml
|
||||
ninja ./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.
|
||||
|
||||
@ -6,6 +6,7 @@ Contents
|
||||
|
||||
* [Tutorial](tutorial.md)
|
||||
* [Contributing](hacking.md)
|
||||
* [Switching views](views.md)
|
||||
|
||||
Introduction
|
||||
------------
|
||||
@ -21,6 +22,8 @@ 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
|
||||
-------------
|
||||
|
||||
|
||||
594
doc/latching.svg
Normal file
594
doc/latching.svg
Normal file
@ -0,0 +1,594 @@
|
||||
<?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>
|
||||
|
After Width: | Height: | Size: 26 KiB |
631
doc/latching_return.svg
Normal file
631
doc/latching_return.svg
Normal file
@ -0,0 +1,631 @@
|
||||
<?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>
|
||||
|
After Width: | Height: | Size: 39 KiB |
386
doc/switching.svg
Normal file
386
doc/switching.svg
Normal file
@ -0,0 +1,386 @@
|
||||
<?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>
|
||||
|
After Width: | Height: | Size: 16 KiB |
@ -1,55 +1,92 @@
|
||||
Kareema's guide to creating layouts
|
||||
===================================
|
||||
A guide to creating layouts
|
||||
===========================
|
||||
|
||||
It’s long overdue to write a comprehensive guide how to add a keyboard layout from start. But unfortunately, I don’t have much time left ATM. A lot of information can be found in [this ](https://forums.puri.sm/t/using-non-latin-language-on-librem-5/7103/5) thread.
|
||||
This guide is based on the original Kareema's [forum post](https://forums.puri.sm/t/translations-and-virtual-touch-keyboards-tracking-localization/7669/48).
|
||||
|
||||
So at least I will try to start writing a short how-to here and edit this post as I find the time. Hope this helps a bit - comments and corrections welcome.
|
||||
It’s long overdue to write a comprehensive guide how to add a keyboard layout from start. But unfortunately, I don’t have much time left ATM. A lot of information can be found in [this](https://forums.puri.sm/t/using-non-latin-language-on-librem-5/7103/5) thread.
|
||||
|
||||
**Get one of the existing keyboard layouts**
|
||||
So at least I will try to start writing a short how-to here and edit this post as I find the time. Hope this helps a bit - comments and corrections [welcome](https://source.puri.sm/Librem5/squeekboard/-/merge_requests/)
|
||||
|
||||
* You can get one of the keyboards from the squeekboard git repository : [https://source.puri.sm/Librem5/squeekboard ](https://source.puri.sm/Librem5/squeekboard)
|
||||
* The keyboard layouts are located in the subdirectory `data/keyboard/` in the `.yaml` files
|
||||
## Creating a new layout
|
||||
|
||||
Creating a layout is easy. You don't need to recompile things, just edit and test. It's easiest to start with an existing layout.
|
||||
|
||||
### Get one of the existing keyboard layouts
|
||||
|
||||
* You can get one of the keyboards from the squeekboard git repository : [https://source.puri.sm/Librem5/squeekboard](https://source.puri.sm/Librem5/squeekboard)
|
||||
* The keyboard layouts are located in the subdirectory [`data/keyboards/`](https://source.puri.sm/Librem5/squeekboard/-/tree/master/data/keyboards) in the `.yaml` files
|
||||
* Take a look and try to understand them :slight_smile:
|
||||
|
||||
**Fork your own copy of squeekboard**
|
||||
|
||||
### Creating the keyboard layout
|
||||
|
||||
* To be written: For the time being, take a look at [Using non-latin language on Librem 5](https://forums.puri.sm/t/using-non-latin-language-on-librem-5/7103/5)
|
||||
* The correct name of the .yaml file can be found with the command
|
||||
|
||||
```
|
||||
gsettings get org.gnome.desktop.input-sources sources
|
||||
```
|
||||
|
||||
The output should be something like this: `[('xkb', 'us'), ('xkb', 'de')]`
|
||||
So for example “de.yaml” would be the correct name for the German keyboard layout.
|
||||
|
||||
If the name of your layout is not translated correctly in the list, you can fix it by adding it and recompiling Squeekboard.
|
||||
|
||||
### Testing the layout
|
||||
|
||||
Copy your yaml file to `~/.local/share/squeekboard/keyboards/` for testing purposes. From there it should get picked up by squeekboard automatically.
|
||||
|
||||
You can also use the `test_layout` tool from the -devel package to check it for errors:
|
||||
|
||||
```
|
||||
# squeekboard_test_layout ./mylayout.yaml
|
||||
Test result: OK
|
||||
```
|
||||
|
||||
## Contributing your changes
|
||||
|
||||
If you want to share your layout with the world, the best way is to submit it to the Squeekboard project. The workflow is similar to any other Gitlab-based project.
|
||||
|
||||
Above all, your layout should be working, be tested, not break anything, and make sense.
|
||||
|
||||
### Fork your own copy of squeekboard
|
||||
|
||||
* Best way would be to start with a fork of the squeekboard repository: Create a user account at https://source.puri.sm/, go the the squeekboard git repository, press “Fork” in the web interface. You can find further instructions [here](https://docs.gitlab.com/ee/user/project/repository/forking_workflow.html#creating-a-fork).
|
||||
* Clone your fork locally with `git clone` and use the uri of your forked repo there
|
||||
|
||||
**Workflow to edit your keyboard and get it merged**
|
||||
### Edit your keyboard and get it merged
|
||||
|
||||
* A generic guide how the workflow to contribute works, can be found at https://developer.puri.sm/Librem5/Contact/Contributing.html
|
||||
* It may be useful to check out the [generic guide how the workflow to contribute works](https://developer.puri.sm/Librem5/Contact/Contributing.html)
|
||||
* Create a branch: Name it “keyboard-layout-mylanguage” or whatever
|
||||
* Checkout your branch, edit your keyboard layout and commit your changes
|
||||
* Your layout **must** be correctly named, and in `data/keyboards/`.
|
||||
* Your layout **must** pass the `test_layout` tool with zero problems.
|
||||
* Your translation **must** be correctly named, and in `data/langs/`.
|
||||
* Your layout or translation **must** be added to automatic tests. **Don’t forget to add it** to `src/resources.rs` and the layout to `tests/meson.build` (that’s for me, because I always forget it).
|
||||
|
||||
### Get it merged
|
||||
|
||||
It's always recommended to **compile and run** squeekboard before submitting your changes. This serves as a test that all is working. See instructions in the [compiling section](#compiling-and-running-squeekboard).
|
||||
|
||||
* Push the local changes (to the branch of your fork of squeekboard)
|
||||
* Create a merge request for the branch to get your changes merged to the official squeekboard git repository
|
||||
|
||||
**Compile squeekboard**
|
||||
If your changes pass automated tests (CI), then the merge request will be reviewed by the maintainers, and you might be asked to change a thing or two.
|
||||
|
||||
* Follow the instructions found in “Building” section of the squeekboard’s README: Running squeekboard: [https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#building ](https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#building)
|
||||
## Compiling and running Squeekboard
|
||||
|
||||
**Running squeekboard**
|
||||
If you want your change to become part of official Squeekboard, or if you want to add a translation of your layout name, you will have to recompile Squeekboard and test your changes there.
|
||||
|
||||
* Follow these instructions to run squeekboard: [https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#running ](https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#running)
|
||||
### Compile squeekboard
|
||||
|
||||
* Follow the instructions found in “Building” section of the squeekboard’s README: Running squeekboard: [https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#building](https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#building)
|
||||
|
||||
### Run squeekboard
|
||||
|
||||
* Follow these instructions to run squeekboard: [https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#running](https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#running)
|
||||
* Additionally take a look at the contribution document for [testing info](HACKING.md#testing)
|
||||
* You can either test it locally on your Linux system or use the [QEMU Librem 5 image ](https://developer.puri.sm/Librem5/Development_Environment/Boards/emulators.html)
|
||||
* You can either test it locally on your Linux system or use the [QEMU Librem 5 image](https://developer.puri.sm/Librem5/Development_Environment/Boards/emulators.html)
|
||||
* To test squeekboard locally, you need phoc. Either compile that from the sources as well or use the CI repository ci.puri.sm for Debian based systems:
|
||||
`deb [arch=amd64] http://ci.puri.sm/ scratch librem5`
|
||||
|
||||
Squeekboard can be installed from there as a Debian package, too (that’s what I often do). But beware - there be dragons! You could bork your system with these packages and you should probably disable this repository again after installing what you need - these packages are not meant for production systems (or so I heard :wink: )
|
||||
|
||||
**Creating the keyboard layout**
|
||||
|
||||
* To be written: For the time being, take a look at [Using non-latin language on Librem 5 ](https://forums.puri.sm/t/using-non-latin-language-on-librem-5/7103/5)
|
||||
* The correct name of the .yaml file can be found with the command `gsettings get org.gnome.desktop.input-sources sources`
|
||||
|
||||
The output should be something like this: `[('xkb', 'us'), ('xkb', 'de')]`
|
||||
So f.ex. “de.yaml” would be the correct name for the German keyboard layout.
|
||||
* The translations for the keyboard layout names in the different languages can be found at `data/langs/`
|
||||
* Don’t forget to add your newly created layout or translation to `src/resources.rs` and the layout to `tests/meson.build` (that’s for me, because I always forget it)
|
||||
|
||||
**Testing the layout**
|
||||
|
||||
* Copy your yaml file to `~/.local/share/squeekboard/keyboards/` for testing purposes. From there it should get picked up by squeekboard
|
||||
* To test the translations in `data/langs/` , you have to compile squeekboard
|
||||
|
||||
|
||||
64
doc/views.md
Normal file
64
doc/views.md
Normal file
@ -0,0 +1,64 @@
|
||||
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`.
|
||||
|
||||
 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.
|
||||
|
||||
 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.
|
||||
|
||||
 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.
|
||||
@ -45,6 +45,8 @@
|
||||
typedef struct _EekGtkKeyboardPrivate
|
||||
{
|
||||
EekRenderer *renderer; // owned, nullable
|
||||
struct render_geometry render_geometry; // mutable
|
||||
|
||||
EekboardContextService *eekboard_context; // unowned reference
|
||||
struct submission *submission; // unowned reference
|
||||
|
||||
@ -72,12 +74,23 @@ 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 (EEK_GTK_KEYBOARD (self));
|
||||
eek_gtk_keyboard_get_instance_private (keyboard);
|
||||
GtkAllocation allocation;
|
||||
gtk_widget_get_allocation (self, &allocation);
|
||||
|
||||
@ -92,22 +105,21 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
|
||||
priv->keyboard,
|
||||
pcontext);
|
||||
|
||||
eek_renderer_set_allocation_size (priv->renderer,
|
||||
priv->keyboard->layout,
|
||||
allocation.width,
|
||||
allocation.height);
|
||||
set_allocation_size (keyboard, 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->submission, cr, priv->keyboard);
|
||||
eek_renderer_render_keyboard (priv->renderer, priv->render_geometry,
|
||||
priv->submission, cr, priv->keyboard);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Units of pixel size
|
||||
// Units of virtual pixels size
|
||||
static enum squeek_arrangement_kind get_type(uint32_t width, uint32_t height) {
|
||||
(void)height;
|
||||
if (width < 1080) {
|
||||
if (width < 540) {
|
||||
return ARRANGEMENT_KIND_BASE;
|
||||
}
|
||||
return ARRANGEMENT_KIND_WIDE;
|
||||
@ -117,24 +129,23 @@ 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 (EEK_GTK_KEYBOARD (self));
|
||||
uint32_t scale = (uint32_t)gtk_widget_get_scale_factor(self);
|
||||
eek_gtk_keyboard_get_instance_private (keyboard);
|
||||
// check if the change would switch types
|
||||
enum squeek_arrangement_kind new_type = get_type(
|
||||
(uint32_t)(allocation->width - allocation->x) * scale,
|
||||
(uint32_t)(allocation->height - allocation->y) * scale);
|
||||
(uint32_t)(allocation->width - allocation->x),
|
||||
(uint32_t)(allocation->height - allocation->y));
|
||||
if (priv->layout->arrangement != new_type) {
|
||||
priv->layout->arrangement = new_type;
|
||||
uint32_t time = gdk_event_get_time(NULL);
|
||||
eekboard_context_service_use_layout(priv->eekboard_context, priv->layout, time);
|
||||
}
|
||||
|
||||
if (priv->renderer)
|
||||
eek_renderer_set_allocation_size (priv->renderer,
|
||||
priv->keyboard->layout,
|
||||
allocation->width,
|
||||
allocation->height);
|
||||
if (priv->renderer) {
|
||||
set_allocation_size (keyboard, priv->keyboard->layout,
|
||||
allocation->width, allocation->height);
|
||||
}
|
||||
|
||||
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->
|
||||
size_allocate (self, allocation);
|
||||
@ -162,7 +173,7 @@ static void depress(EekGtkKeyboard *self,
|
||||
}
|
||||
squeek_layout_depress(priv->keyboard->layout,
|
||||
priv->submission,
|
||||
x, y, eek_renderer_get_transformation(priv->renderer), time, self);
|
||||
x, y, priv->render_geometry.widget_to_layout, time, self);
|
||||
}
|
||||
|
||||
static void drag(EekGtkKeyboard *self,
|
||||
@ -174,7 +185,7 @@ static void drag(EekGtkKeyboard *self,
|
||||
}
|
||||
squeek_layout_drag(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout,
|
||||
priv->submission,
|
||||
x, y, eek_renderer_get_transformation(priv->renderer), time,
|
||||
x, y, priv->render_geometry.widget_to_layout, time,
|
||||
priv->eekboard_context, self);
|
||||
}
|
||||
|
||||
@ -185,8 +196,7 @@ static void release(EekGtkKeyboard *self, guint32 time)
|
||||
return;
|
||||
}
|
||||
squeek_layout_release(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout,
|
||||
priv->submission,
|
||||
eek_renderer_get_transformation(priv->renderer), time,
|
||||
priv->submission, priv->render_geometry.widget_to_layout, time,
|
||||
priv->eekboard_context, self);
|
||||
}
|
||||
|
||||
@ -356,10 +366,11 @@ 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 ();
|
||||
|
||||
@ -395,6 +406,24 @@ 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),
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "eek/eek-renderer.h"
|
||||
#include "eek/eek-types.h"
|
||||
|
||||
struct submission;
|
||||
|
||||
@ -31,46 +31,31 @@
|
||||
|
||||
#include "eek-keyboard.h"
|
||||
|
||||
void level_keyboard_free(LevelKeyboard *self) {
|
||||
xkb_keymap_unref(self->keymap);
|
||||
close(self->keymap_fd);
|
||||
squeek_layout_free(self->layout);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
LevelKeyboard*
|
||||
level_keyboard_new (struct squeek_layout *layout)
|
||||
{
|
||||
LevelKeyboard *keyboard = g_new0(LevelKeyboard, 1);
|
||||
|
||||
if (!keyboard) {
|
||||
g_error("Failed to create a keyboard");
|
||||
}
|
||||
keyboard->layout = layout;
|
||||
|
||||
/// External linkage for Rust.
|
||||
/// The corresponding deinit is implemented in vkeyboard::KeyMap::drop
|
||||
struct keymap squeek_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");
|
||||
}
|
||||
|
||||
const gchar *keymap_str = squeek_layout_get_keymap(keyboard->layout);
|
||||
|
||||
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);
|
||||
keyboard->keymap = keymap;
|
||||
|
||||
char * xkb_keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
|
||||
keyboard->keymap_len = strlen(xkb_keymap_str) + 1;
|
||||
char *xkb_keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
|
||||
size_t keymap_len = strlen(xkb_keymap_str) + 1;
|
||||
|
||||
g_autofree char *path = strdup("/eek_keymap-XXXXXX");
|
||||
char *r = &path[strlen(path) - 6];
|
||||
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...
|
||||
@ -79,18 +64,39 @@ level_keyboard_new (struct squeek_layout *layout)
|
||||
if (keymap_fd < 0) {
|
||||
g_error("Failed to set up keymap fd");
|
||||
}
|
||||
keyboard->keymap_fd = keymap_fd;
|
||||
|
||||
shm_unlink(path);
|
||||
if (ftruncate(keymap_fd, (off_t)keyboard->keymap_len)) {
|
||||
if (ftruncate(keymap_fd, (off_t)keymap_len)) {
|
||||
g_error("Failed to increase keymap fd size");
|
||||
}
|
||||
char *ptr = mmap(NULL, keyboard->keymap_len, PROT_WRITE, MAP_SHARED,
|
||||
char *ptr = mmap(NULL, keymap_len, PROT_WRITE, MAP_SHARED,
|
||||
keymap_fd, 0);
|
||||
if ((void*)ptr == (void*)-1) {
|
||||
g_error("Failed to set up mmap");
|
||||
}
|
||||
strncpy(ptr, xkb_keymap_str, keyboard->keymap_len);
|
||||
strncpy(ptr, xkb_keymap_str, keymap_len);
|
||||
munmap(ptr, keymap_len);
|
||||
free(xkb_keymap_str);
|
||||
munmap(ptr, keyboard->keymap_len);
|
||||
xkb_keymap_unref(keymap);
|
||||
struct keymap km = {
|
||||
.fd = keymap_fd,
|
||||
.fd_len = keymap_len,
|
||||
};
|
||||
return km;
|
||||
}
|
||||
|
||||
void level_keyboard_free(LevelKeyboard *self) {
|
||||
squeek_layout_free(self->layout);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
LevelKeyboard*
|
||||
level_keyboard_new (struct squeek_layout *layout)
|
||||
{
|
||||
LevelKeyboard *keyboard = g_new0(LevelKeyboard, 1);
|
||||
if (!keyboard) {
|
||||
g_error("Failed to create a keyboard");
|
||||
}
|
||||
keyboard->layout = layout;
|
||||
return keyboard;
|
||||
}
|
||||
|
||||
@ -32,19 +32,20 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/// Keymap container for Rust interoperability.
|
||||
struct keymap {
|
||||
uint32_t fd; // keymap formatted as XKB string
|
||||
size_t fd_len; // length of the data inside keymap_fd
|
||||
};
|
||||
|
||||
/// Keyboard state holder
|
||||
struct _LevelKeyboard {
|
||||
struct squeek_layout *layout; // owned
|
||||
struct xkb_keymap *keymap; // owned
|
||||
int keymap_fd; // keymap formatted as XKB string
|
||||
size_t keymap_len; // length of the data inside keymap_fd
|
||||
|
||||
guint id; // as a key to layout choices
|
||||
// FIXME: This no longer needs to exist, keymap was folded into layout.
|
||||
};
|
||||
typedef struct _LevelKeyboard LevelKeyboard;
|
||||
|
||||
gchar * eek_keyboard_get_keymap
|
||||
(LevelKeyboard *keyboard);
|
||||
gchar *eek_keyboard_get_keymap(LevelKeyboard *keyboard);
|
||||
|
||||
LevelKeyboard*
|
||||
level_keyboard_new (struct squeek_layout *layout);
|
||||
|
||||
@ -18,8 +18,6 @@
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
@ -33,10 +31,6 @@
|
||||
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,
|
||||
@ -60,21 +54,21 @@ render_outline (cairo_t *cr,
|
||||
position.x, position.y, position.width, position.height);
|
||||
}
|
||||
|
||||
static void render_button_in_context(gint scale_factor,
|
||||
/// Rust interface
|
||||
void eek_render_button_in_context(uint32_t scale_factor,
|
||||
cairo_t *cr,
|
||||
GtkStyleContext *ctx,
|
||||
const struct squeek_button *button) {
|
||||
EekBounds bounds,
|
||||
const char *icon_name,
|
||||
const gchar *label) {
|
||||
/* 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);
|
||||
@ -104,25 +98,27 @@ static void render_button_in_context(gint scale_factor,
|
||||
}
|
||||
}
|
||||
|
||||
const gchar *label = squeek_button_get_label(button);
|
||||
if (label) {
|
||||
render_button_label (cr, ctx, label, squeek_button_get_bounds(button));
|
||||
render_button_label (cr, ctx, label, bounds);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
eek_render_button (EekRenderer *self,
|
||||
cairo_t *cr,
|
||||
const struct squeek_button *button,
|
||||
gboolean pressed,
|
||||
gboolean locked)
|
||||
/// 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)
|
||||
{
|
||||
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. */
|
||||
@ -131,19 +127,22 @@ eek_render_button (EekRenderer *self,
|
||||
(pressed) or normal. */
|
||||
gtk_style_context_set_state(ctx,
|
||||
pressed ? GTK_STATE_FLAG_ACTIVE : GTK_STATE_FLAG_NORMAL);
|
||||
const char *outline_name = squeek_button_get_outline_name(button);
|
||||
if (locked) {
|
||||
gtk_style_context_add_class(ctx, "locked");
|
||||
if (locked_class) {
|
||||
gtk_style_context_add_class(ctx, locked_class);
|
||||
}
|
||||
gtk_style_context_add_class(ctx, outline_name);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
render_button_in_context(self->scale_factor, cr, ctx, button);
|
||||
|
||||
/// Interface for Rust.
|
||||
void eek_put_style_context_for_button(GtkStyleContext *ctx,
|
||||
const char *outline_name,
|
||||
const char *locked_class) {
|
||||
// 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) {
|
||||
gtk_style_context_remove_class(ctx, "locked");
|
||||
if (locked_class) {
|
||||
gtk_style_context_remove_class(ctx, locked_class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,22 +193,23 @@ 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 (self->allocation_width > 0.0);
|
||||
g_return_if_fail (self->allocation_height > 0.0);
|
||||
g_return_if_fail (geometry.allocation_width > 0.0);
|
||||
g_return_if_fail (geometry.allocation_height > 0.0);
|
||||
|
||||
/* Paint the background covering the entire widget area */
|
||||
gtk_render_background (self->view_context,
|
||||
cr,
|
||||
0, 0,
|
||||
self->allocation_width, self->allocation_height);
|
||||
geometry.allocation_width, geometry.allocation_height);
|
||||
|
||||
cairo_save(cr);
|
||||
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);
|
||||
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);
|
||||
|
||||
squeek_draw_layout_base_view(keyboard->layout, self, cr);
|
||||
squeek_layout_draw_all_changed(keyboard->layout, self, cr, submission);
|
||||
@ -261,8 +261,6 @@ 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();
|
||||
@ -289,7 +287,7 @@ eek_renderer_new (LevelKeyboard *keyboard,
|
||||
}
|
||||
gtk_style_context_add_provider (renderer->view_context,
|
||||
GTK_STYLE_PROVIDER(renderer->css_provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
|
||||
/* Create a style context for the buttons */
|
||||
path = gtk_widget_path_new();
|
||||
@ -305,26 +303,22 @@ 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_USER);
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
return renderer;
|
||||
}
|
||||
|
||||
void
|
||||
eek_renderer_set_allocation_size (EekRenderer *renderer,
|
||||
struct squeek_layout *layout,
|
||||
struct render_geometry
|
||||
eek_render_geometry_from_allocation_size (struct squeek_layout *layout,
|
||||
gdouble width,
|
||||
gdouble height)
|
||||
{
|
||||
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
|
||||
struct render_geometry ret = {
|
||||
.allocation_width = width,
|
||||
.allocation_height = height,
|
||||
.widget_to_layout = squeek_layout_calculate_transformation(
|
||||
layout, width, height),
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
@ -333,6 +327,11 @@ 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,
|
||||
@ -356,8 +355,3 @@ eek_renderer_get_icon_surface (const gchar *icon_name,
|
||||
}
|
||||
return surface;
|
||||
}
|
||||
|
||||
struct transformation
|
||||
eek_renderer_get_transformation (EekRenderer *renderer) {
|
||||
return renderer->widget_to_layout;
|
||||
}
|
||||
|
||||
@ -41,22 +41,23 @@ 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);
|
||||
|
||||
@ -64,13 +65,14 @@ cairo_surface_t *eek_renderer_get_icon_surface(const gchar *icon_name,
|
||||
gint size,
|
||||
gint scale);
|
||||
|
||||
void eek_renderer_render_keyboard (EekRenderer *renderer, struct submission *submission,
|
||||
void eek_renderer_render_keyboard (EekRenderer *renderer, struct render_geometry geometry, struct submission *submission,
|
||||
cairo_t *cr, LevelKeyboard *keyboard);
|
||||
void
|
||||
eek_renderer_free (EekRenderer *self);
|
||||
|
||||
struct transformation
|
||||
eek_renderer_get_transformation (EekRenderer *renderer);
|
||||
struct render_geometry
|
||||
eek_render_geometry_from_allocation_size (struct squeek_layout *layout,
|
||||
gdouble width, gdouble height);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* EEK_RENDERER_H */
|
||||
|
||||
@ -90,13 +90,5 @@ 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 */
|
||||
|
||||
@ -590,27 +590,32 @@ 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]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -632,25 +637,31 @@ 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]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -669,13 +680,15 @@ 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]);
|
||||
}
|
||||
@ -693,13 +706,14 @@ 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]);
|
||||
}
|
||||
@ -717,6 +731,7 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,30 +128,22 @@ 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->overlay_name;
|
||||
gchar *layout_name = state->layout_name;
|
||||
gchar *overlay_name = state->overlay_name;
|
||||
|
||||
// try to get the best keyboard layout
|
||||
if (layout_name == NULL) {
|
||||
layout_name = state->layout_name;
|
||||
layout_name = "us";
|
||||
}
|
||||
|
||||
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);
|
||||
struct squeek_layout *layout = squeek_load_layout(layout_name, state->arrangement, state->purpose, overlay_name);
|
||||
LevelKeyboard *keyboard = level_keyboard_new(layout);
|
||||
// set as current
|
||||
LevelKeyboard *previous_keyboard = context->keyboard;
|
||||
@ -159,7 +151,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_set_keyboard(context->submission, keyboard, timestamp);
|
||||
submission_use_layout(context->submission, keyboard->layout, timestamp);
|
||||
}
|
||||
|
||||
// Update UI
|
||||
@ -345,7 +337,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_set_keyboard(context->submission, context->keyboard, time);
|
||||
submission_use_layout(context->submission, context->keyboard->layout, time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ use std::env;
|
||||
|
||||
fn main() -> () {
|
||||
check_builtin_layout(
|
||||
env::args().nth(1).expect("No argument given").as_str()
|
||||
env::args().nth(1).expect("No argument given").as_str(),
|
||||
env::args().nth(2).map(|s| s == "allow_missing_return").unwrap_or(false),
|
||||
);
|
||||
}
|
||||
|
||||
22
meson.build
22
meson.build
@ -1,7 +1,7 @@
|
||||
project(
|
||||
'squeekboard',
|
||||
'c', 'rust',
|
||||
version: '1.9.3',
|
||||
version: '1.14.0',
|
||||
license: 'GPLv3',
|
||||
meson_version: '>=0.51.0',
|
||||
default_options: [
|
||||
@ -19,14 +19,17 @@ add_project_arguments(
|
||||
'-Werror=missing-field-initializers',
|
||||
'-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-function',
|
||||
'-Wunused',
|
||||
],
|
||||
language: 'c'
|
||||
)
|
||||
@ -38,6 +41,16 @@ 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
|
||||
@ -70,6 +83,7 @@ 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())
|
||||
@ -83,7 +97,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']
|
||||
cargo_build_flags += ['--features', 'gtk_v0_5,gio_v0_5,rustc_less_1_36']
|
||||
cargo_deps = files('Cargo.deps.legacy')
|
||||
endif
|
||||
|
||||
@ -97,7 +111,7 @@ cargo_toml = custom_target(
|
||||
|
||||
dep_cargo = find_program('cargo')
|
||||
cargo_script = find_program('cargo.sh')
|
||||
cargo_build = find_program('cargo_build.sh')
|
||||
cargo_build = find_program('cargo_build.py')
|
||||
|
||||
subdir('data')
|
||||
subdir('protocols')
|
||||
|
||||
@ -10,3 +10,7 @@ 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')
|
||||
|
||||
@ -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 commit requests already issued on that object.
|
||||
When the compositor receives a done event with a serial different than
|
||||
equal to the number of done events already issued on that object.
|
||||
When the compositor receives a commit request 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.
|
||||
|
||||
@ -10,13 +10,14 @@ pub struct KeySym(pub String);
|
||||
type View = String;
|
||||
|
||||
/// Use to send modified keypresses
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Clone, Copy, 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
|
||||
@ -29,6 +30,11 @@ 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),
|
||||
@ -48,14 +54,24 @@ pub enum Action {
|
||||
impl Action {
|
||||
pub fn is_locked(&self, view_name: &str) -> bool {
|
||||
match self {
|
||||
Action::LockView { lock, unlock: _ } => lock == view_name,
|
||||
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()
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
pub fn is_active(&self, view_name: &str) -> bool {
|
||||
match self {
|
||||
Action::SetView(view) => view == view_name,
|
||||
Action::LockView { lock, unlock: _ } => lock == view_name,
|
||||
Action::LockView { lock, unlock: _, latches: _, looks_locked_from: _ } => lock == view_name,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
424
src/data/loading.rs
Normal file
424
src/data/loading.rs
Normal file
@ -0,0 +1,424 @@
|
||||
/* 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())
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
65
src/data/mod.rs
Normal file
65
src/data/mod.rs
Normal file
@ -0,0 +1,65 @@
|
||||
/* 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,32 +1,30 @@
|
||||
/**! The parsing of the data files for layouts */
|
||||
/* Copyright (C) 2020-2021 Purism SPC
|
||||
* SPDX-License-Identifier: GPL-3.0+
|
||||
*/
|
||||
|
||||
// TODO: find a nice way to make sure non-positive sizes don't break layouts
|
||||
/*! Parsing of the data files containing 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_keymap, generate_keycodes, FormattingError
|
||||
generate_keymaps, generate_keycodes, KeyCode, FormattingError
|
||||
};
|
||||
use ::layout;
|
||||
use ::layout::ArrangementKind;
|
||||
use ::logging;
|
||||
use ::resources;
|
||||
use ::util::c::as_str;
|
||||
use ::util::hash_map_map;
|
||||
use ::xdg;
|
||||
use ::resources;
|
||||
|
||||
// traits, derives
|
||||
use serde::Deserialize;
|
||||
@ -34,183 +32,7 @@ use std::io::BufReader;
|
||||
use std::iter::FromIterator;
|
||||
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,
|
||||
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!");
|
||||
}
|
||||
// TODO: find a nice way to make sure non-positive sizes don't break layouts
|
||||
|
||||
/// The root element describing an entire keyboard
|
||||
#[derive(Debug, Deserialize, PartialEq)]
|
||||
@ -266,7 +88,13 @@ struct ButtonMeta {
|
||||
#[serde(deny_unknown_fields)]
|
||||
enum Action {
|
||||
#[serde(rename="locking")]
|
||||
Locking { lock_view: String, unlock_view: String },
|
||||
Locking {
|
||||
lock_view: String,
|
||||
unlock_view: String,
|
||||
pops: Option<bool>,
|
||||
#[serde(default)]
|
||||
looks_locked_from: Vec<String>,
|
||||
},
|
||||
#[serde(rename="set_view")]
|
||||
SetView(String),
|
||||
#[serde(rename="show_prefs")]
|
||||
@ -297,37 +125,6 @@ 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>,
|
||||
@ -382,56 +179,45 @@ impl Layout {
|
||||
)
|
||||
)}).collect();
|
||||
|
||||
let keymap: HashMap<String, u32> = generate_keycodes(
|
||||
button_actions.iter()
|
||||
.filter_map(|(_name, action)| {
|
||||
match action {
|
||||
::action::Action::Submit {
|
||||
text: _, keys,
|
||||
} => Some(keys),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.map(|named_keysym| named_keysym.0.as_str())
|
||||
let symbolmap: HashMap<String, KeyCode> = generate_keycodes(
|
||||
extract_symbol_names(&button_actions)
|
||||
);
|
||||
|
||||
let button_states = button_actions.into_iter().map(|(name, action)| {
|
||||
let keycodes = match &action {
|
||||
::action::Action::Submit { text: _, keys } => {
|
||||
keys.iter().map(|named_keycode| {
|
||||
*keymap.get(named_keycode.0.as_str())
|
||||
.expect(
|
||||
format!(
|
||||
"keycode {} in key {} missing from keymap",
|
||||
named_keycode.0,
|
||||
name
|
||||
).as_str()
|
||||
)
|
||||
}).collect()
|
||||
},
|
||||
action::Action::Erase => vec![
|
||||
*keymap.get("BackSpace")
|
||||
.expect(&format!("BackSpace missing from keymap")),
|
||||
],
|
||||
_ => Vec::new(),
|
||||
};
|
||||
(
|
||||
name.into(),
|
||||
KeyState {
|
||||
pressed: PressType::Released,
|
||||
keycodes,
|
||||
action,
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
let button_states = HashMap::<String, KeyState>::from_iter(
|
||||
button_states
|
||||
button_actions.into_iter().map(|(name, action)| {
|
||||
let keycodes = match &action {
|
||||
::action::Action::Submit { text: _, keys } => {
|
||||
keys.iter().map(|named_keysym| {
|
||||
symbolmap.get(named_keysym.0.as_str())
|
||||
.expect(
|
||||
format!(
|
||||
"keysym {} in key {} missing from symbol map",
|
||||
named_keysym.0,
|
||||
name
|
||||
).as_str()
|
||||
)
|
||||
.clone()
|
||||
}).collect()
|
||||
},
|
||||
action::Action::Erase => vec![
|
||||
symbolmap.get("BackSpace")
|
||||
.expect(&format!("BackSpace missing from symbol map"))
|
||||
.clone(),
|
||||
],
|
||||
_ => Vec::new(),
|
||||
};
|
||||
(
|
||||
name.into(),
|
||||
KeyState {
|
||||
pressed: PressType::Released,
|
||||
keycodes,
|
||||
action,
|
||||
}
|
||||
)
|
||||
})
|
||||
);
|
||||
|
||||
// TODO: generate from symbols
|
||||
let keymap_str = match generate_keymap(&button_states) {
|
||||
let keymaps = match generate_keymaps(symbolmap) {
|
||||
Err(e) => { return (Err(e), warning_handler) },
|
||||
Ok(v) => v,
|
||||
};
|
||||
@ -459,14 +245,14 @@ impl Layout {
|
||||
&mut warning_handler,
|
||||
))
|
||||
});
|
||||
layout::Row {
|
||||
buttons: add_offsets(
|
||||
layout::Row::new(
|
||||
add_offsets(
|
||||
buttons,
|
||||
|button| button.size.width,
|
||||
).collect()
|
||||
}
|
||||
)
|
||||
});
|
||||
let rows = add_offsets(rows, |row| row.get_height())
|
||||
let rows = add_offsets(rows, |row| row.get_size().height)
|
||||
.collect();
|
||||
(
|
||||
name.clone(),
|
||||
@ -484,8 +270,8 @@ impl Layout {
|
||||
name,
|
||||
(
|
||||
layout::c::Point {
|
||||
x: (total_size.width - view.get_width()) / 2.0,
|
||||
y: (total_size.height - view.get_height()) / 2.0,
|
||||
x: (total_size.width - view.get_size().width) / 2.0,
|
||||
y: (total_size.height - view.get_size().height) / 2.0,
|
||||
},
|
||||
view,
|
||||
),
|
||||
@ -495,10 +281,10 @@ impl Layout {
|
||||
(
|
||||
Ok(::layout::LayoutData {
|
||||
views: views,
|
||||
keymap_str: {
|
||||
keymaps: keymaps.into_iter().map(|keymap_str|
|
||||
CString::new(keymap_str)
|
||||
.expect("Invalid keymap string generated")
|
||||
},
|
||||
).collect(),
|
||||
// FIXME: use a dedicated field
|
||||
margins: layout::Margins {
|
||||
top: self.margins.top,
|
||||
@ -531,7 +317,7 @@ fn create_action<H: logging::Handler>(
|
||||
Text(String),
|
||||
Keysym(String),
|
||||
Modifier(Modifier),
|
||||
};
|
||||
}
|
||||
|
||||
let submission = match (
|
||||
&symbol_meta.action,
|
||||
@ -588,7 +374,9 @@ fn create_action<H: logging::Handler>(
|
||||
)
|
||||
),
|
||||
SubmitData::Action(Action::Locking {
|
||||
lock_view, unlock_view
|
||||
lock_view, unlock_view,
|
||||
pops,
|
||||
looks_locked_from,
|
||||
}) => ::action::Action::LockView {
|
||||
lock: filter_view_name(
|
||||
name,
|
||||
@ -602,6 +390,8 @@ fn create_action<H: logging::Handler>(
|
||||
&view_names,
|
||||
warning_handler,
|
||||
),
|
||||
latches: pops.unwrap_or(true),
|
||||
looks_locked_from,
|
||||
},
|
||||
SubmitData::Action(
|
||||
Action::ShowPrefs
|
||||
@ -646,6 +436,9 @@ 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,
|
||||
@ -734,19 +527,47 @@ fn create_button<H: logging::Handler>(
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_symbol_names<'a>(actions: &'a [(&str, action::Action)])
|
||||
-> impl Iterator<Item=String> + 'a
|
||||
{
|
||||
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()))),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.map(|named_keysym| named_keysym.0)
|
||||
}
|
||||
|
||||
|
||||
#[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 {
|
||||
PathBuf::from(THIS_FILE)
|
||||
.parent().unwrap()
|
||||
.parent().unwrap()
|
||||
.join(file)
|
||||
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)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -824,7 +645,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
out.views["base"].1
|
||||
.get_rows()[0].1
|
||||
.buttons[0].1
|
||||
.get_buttons()[0].1
|
||||
.label,
|
||||
::layout::Label::Text(CString::new("test").unwrap())
|
||||
);
|
||||
@ -839,7 +660,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
out.views["base"].1
|
||||
.get_rows()[0].1
|
||||
.buttons[0].1
|
||||
.get_buttons()[0].1
|
||||
.label,
|
||||
::layout::Label::Text(CString::new("test").unwrap())
|
||||
);
|
||||
@ -855,35 +676,27 @@ mod tests {
|
||||
assert_eq!(
|
||||
out.views["base"].1
|
||||
.get_rows()[0].1
|
||||
.buttons[0].1
|
||||
.get_buttons()[0].1
|
||||
.state.borrow()
|
||||
.keycodes.len(),
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
/// Test if erase yields a useable keycode
|
||||
#[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);
|
||||
|
||||
fn test_layout_erase() {
|
||||
let out = Layout::from_file(path_from_root("tests/layout_erase.yaml"))
|
||||
.unwrap()
|
||||
.build(ProblemPanic).0
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
sources,
|
||||
vec!(
|
||||
(ArrangementKind::Base, DataSource::Resource("nb".into())),
|
||||
(
|
||||
ArrangementKind::Base,
|
||||
DataSource::Resource(FALLBACK_LAYOUT_NAME.into())
|
||||
),
|
||||
)
|
||||
out.views["base"].1
|
||||
.get_rows()[0].1
|
||||
.get_buttons()[0].1
|
||||
.state.borrow()
|
||||
.keycodes.len(),
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
@ -939,4 +752,35 @@ mod tests {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_symbols() {
|
||||
let actions = [(
|
||||
"ac",
|
||||
action::Action::Submit {
|
||||
text: None,
|
||||
keys: vec![
|
||||
action::KeySym("a".into()),
|
||||
action::KeySym("c".into()),
|
||||
],
|
||||
},
|
||||
)];
|
||||
assert_eq!(
|
||||
extract_symbol_names(&actions[..]).collect::<Vec<_>>(),
|
||||
vec!["a", "c"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_symbols_erase() {
|
||||
let actions = [(
|
||||
"Erase",
|
||||
action::Action::Erase,
|
||||
)];
|
||||
assert_eq!(
|
||||
extract_symbol_names(&actions[..]).collect::<Vec<_>>(),
|
||||
vec!["BackSpace"],
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -59,7 +59,7 @@ handle_set_visible(SmPuriOSK0 *object, GDBusMethodInvocation *invocation,
|
||||
|
||||
if (service->context) {
|
||||
if (arg_visible) {
|
||||
server_context_service_show_keyboard (service->context);
|
||||
server_context_service_force_show_keyboard (service->context);
|
||||
} else {
|
||||
server_context_service_hide_keyboard (service->context);
|
||||
}
|
||||
|
||||
213
src/drawing.rs
213
src/drawing.rs
@ -3,20 +3,24 @@
|
||||
use cairo;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use ::action::Action;
|
||||
use ::action::{ Action, Modifier };
|
||||
use ::keyboard;
|
||||
use ::layout::{ Button, Layout };
|
||||
use ::layout::c::{ EekGtkKeyboard, Point };
|
||||
use ::layout::{ Button, Label, LatchedState, Layout };
|
||||
use ::layout::c::{ Bounds, 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_void;
|
||||
use std::os::raw::{ c_char, c_void };
|
||||
|
||||
// This is constructed only in C, no need for warnings
|
||||
#[allow(dead_code)]
|
||||
@ -24,18 +28,44 @@ mod c {
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct EekRenderer(*const c_void);
|
||||
|
||||
#[no_mangle]
|
||||
// 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);
|
||||
|
||||
|
||||
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_render_button(
|
||||
pub fn eek_renderer_get_scale_factor(
|
||||
renderer: EekRenderer,
|
||||
) -> u32;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn eek_render_button_in_context(
|
||||
scale_factor: u32,
|
||||
cr: *mut cairo_sys::cairo_t,
|
||||
button: *const Button,
|
||||
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,
|
||||
pressed: u64,
|
||||
locked: 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,
|
||||
);
|
||||
}
|
||||
|
||||
@ -55,13 +85,16 @@ mod c {
|
||||
|
||||
layout.foreach_visible_button(|offset, button| {
|
||||
let state = RefCell::borrow(&button.state).clone();
|
||||
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 {
|
||||
|
||||
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
|
||||
{
|
||||
render_button_at_position(
|
||||
renderer, &cr,
|
||||
offset,
|
||||
@ -87,20 +120,55 @@ mod c {
|
||||
renderer, &cr,
|
||||
offset,
|
||||
button.as_ref(),
|
||||
keyboard::PressType::Released, false,
|
||||
keyboard::PressType::Released,
|
||||
LockedStyle::Free,
|
||||
);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[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)
|
||||
pub fn render_button_at_position(
|
||||
fn render_button_at_position(
|
||||
renderer: c::EekRenderer,
|
||||
cr: &cairo::Context,
|
||||
position: Point,
|
||||
button: &Button,
|
||||
pressed: keyboard::PressType,
|
||||
locked: bool,
|
||||
locked: LockedStyle,
|
||||
) {
|
||||
cr.save();
|
||||
cr.translate(position.x, position.y);
|
||||
@ -109,19 +177,110 @@ pub fn render_button_at_position(
|
||||
button.size.width, button.size.height
|
||||
);
|
||||
cr.clip();
|
||||
unsafe {
|
||||
c::eek_render_button(
|
||||
|
||||
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,
|
||||
cairo::Context::to_raw_none(&cr),
|
||||
button as *const Button,
|
||||
button.name.as_ptr(),
|
||||
outline_name_c,
|
||||
locked_class_c,
|
||||
pressed as u64,
|
||||
locked as u64,
|
||||
)
|
||||
};
|
||||
cr.restore();
|
||||
|
||||
let r = operation(&ctx);
|
||||
|
||||
unsafe {
|
||||
c::eek_put_style_context_for_button(
|
||||
ctx,
|
||||
outline_name_c,
|
||||
locked_class_c,
|
||||
)
|
||||
};
|
||||
|
||||
r
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ 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;
|
||||
@ -35,7 +36,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);
|
||||
return submission_new(im, vk, state, vis_manager);
|
||||
}
|
||||
|
||||
/// Un-inlined
|
||||
|
||||
@ -23,7 +23,7 @@ pub mod c {
|
||||
|
||||
use std::os::raw::{c_char, c_void};
|
||||
|
||||
pub use ::submission::c::UIManager;
|
||||
pub use ::ui_manager::c::UIManager;
|
||||
pub use ::submission::c::StateManager;
|
||||
|
||||
// The following defined in C
|
||||
@ -32,17 +32,15 @@ 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
|
||||
@ -151,11 +149,11 @@ pub mod c {
|
||||
..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,
|
||||
@ -163,10 +161,6 @@ 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); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -184,9 +178,7 @@ pub mod c {
|
||||
// the keyboard is already decommissioned
|
||||
imservice.current.active = false;
|
||||
|
||||
if let Some(ui) = imservice.ui_manager {
|
||||
unsafe { server_context_service_hide_keyboard(ui); }
|
||||
}
|
||||
(imservice.active_callback)(imservice.current.active);
|
||||
}
|
||||
|
||||
// FIXME: destroy and deallocate
|
||||
@ -339,8 +331,7 @@ pub struct IMService {
|
||||
pub im: *mut c::InputMethod,
|
||||
/// Unowned reference. Be careful, it's shared with C at large
|
||||
state_manager: *const c::StateManager,
|
||||
/// Unowned reference. Be careful, it's shared with C at large
|
||||
pub ui_manager: Option<*const c::UIManager>,
|
||||
active_callback: Box<dyn Fn(bool)>,
|
||||
|
||||
pending: IMProtocolState,
|
||||
current: IMProtocolState, // turn current into an idiomatic representation?
|
||||
@ -357,12 +348,13 @@ 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,
|
||||
ui_manager: None,
|
||||
active_callback,
|
||||
state_manager,
|
||||
pending: IMProtocolState::default(),
|
||||
current: IMProtocolState::default(),
|
||||
@ -414,7 +406,6 @@ impl IMService {
|
||||
unsafe {
|
||||
c::eek_input_method_commit(self.im, self.serial.0)
|
||||
}
|
||||
self.serial += Wrapping(1u32);
|
||||
Ok(())
|
||||
},
|
||||
false => Err(SubmitError::NotActive),
|
||||
|
||||
250
src/keyboard.rs
250
src/keyboard.rs
@ -5,11 +5,13 @@ 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 ::logging;
|
||||
use ::util;
|
||||
|
||||
// Traits
|
||||
use std::io::Write;
|
||||
@ -21,7 +23,12 @@ pub enum PressType {
|
||||
Pressed = 1,
|
||||
}
|
||||
|
||||
pub type KeyCode = u32;
|
||||
/// The extended, unambiguous layout-keycode
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct KeyCode {
|
||||
pub code: u32,
|
||||
pub keymap_idx: usize,
|
||||
}
|
||||
|
||||
bitflags!{
|
||||
/// Map to `virtual_keyboard.modifiers` modifiers values
|
||||
@ -80,10 +87,10 @@ impl KeyState {
|
||||
}
|
||||
|
||||
/// Sorts an iterator by converting it to a Vector and back
|
||||
fn sorted<'a, I: Iterator<Item=&'a str>>(
|
||||
fn sorted<'a, I: Iterator<Item=String>>(
|
||||
iter: I
|
||||
) -> impl Iterator<Item=&'a str> {
|
||||
let mut v: Vec<&'a str> = iter.collect();
|
||||
) -> impl Iterator<Item=String> {
|
||||
let mut v: Vec<String> = iter.collect();
|
||||
v.sort();
|
||||
v.into_iter()
|
||||
}
|
||||
@ -91,15 +98,17 @@ fn sorted<'a, I: Iterator<Item=&'a str>>(
|
||||
/// 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=&'a str>>(
|
||||
key_names: C
|
||||
) -> HashMap<String, u32> {
|
||||
let special_keysyms = ["BackSpace", "Return"].iter().map(|&s| s);
|
||||
pub fn generate_keycodes<'a, C: IntoIterator<Item=String>>(
|
||||
key_names: C,
|
||||
) -> HashMap<String, KeyCode> {
|
||||
HashMap::from_iter(
|
||||
// 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..)
|
||||
// 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 },
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
@ -124,12 +133,54 @@ 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.
|
||||
// TODO: don't rely on keys and their order,
|
||||
// but rather on what keysyms and keycodes are in use.
|
||||
// Iterating actions makes it hard to deduplicate keysyms.
|
||||
pub fn generate_keymap(
|
||||
keystates: &HashMap::<String, KeyState>
|
||||
/// Key codes must not repeat and must remain between 9 and 255.
|
||||
fn generate_keymap(
|
||||
symbolmap: &SingleKeyMap,
|
||||
) -> Result<String, FormattingError> {
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
writeln!(
|
||||
@ -141,85 +192,79 @@ pub fn generate_keymap(
|
||||
maximum = 255;"
|
||||
)?;
|
||||
|
||||
for (name, state) in keystates.iter() {
|
||||
match &state.action {
|
||||
Action::Submit { text: _, keys } => {
|
||||
if let 0 = keys.len() {
|
||||
log_print!(
|
||||
logging::Level::Warning,
|
||||
"Key {} has no keysyms", name,
|
||||
);
|
||||
};
|
||||
for (named_keysym, keycode) in keys.iter().zip(&state.keycodes) {
|
||||
write!(
|
||||
buf,
|
||||
"
|
||||
<{}> = {};",
|
||||
named_keysym.0,
|
||||
keycode,
|
||||
)?;
|
||||
}
|
||||
},
|
||||
Action::Erase => {
|
||||
let mut keycodes = state.keycodes.iter();
|
||||
write!(
|
||||
buf,
|
||||
"
|
||||
<BackSpace> = {};",
|
||||
keycodes.next().expect("Erase key has no keycode"),
|
||||
)?;
|
||||
if let Some(_) = keycodes.next() {
|
||||
log_print!(
|
||||
logging::Level::Bug,
|
||||
"Erase key has multiple keycodes",
|
||||
);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
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 {
|
||||
write!(
|
||||
buf,
|
||||
"
|
||||
<I{}> = {0};",
|
||||
keycode,
|
||||
)?;
|
||||
}
|
||||
|
||||
writeln!(
|
||||
buf,
|
||||
"
|
||||
indicator 1 = \"Caps Lock\"; // Xwayland won't accept without it.
|
||||
}};
|
||||
|
||||
xkb_symbols \"squeekboard\" {{
|
||||
|
||||
name[Group1] = \"Letters\";
|
||||
name[Group2] = \"Numbers/Symbols\";
|
||||
|
||||
key <BackSpace> {{ [ BackSpace ] }};"
|
||||
"
|
||||
)?;
|
||||
|
||||
for (_name, state) in keystates.iter() {
|
||||
if let Action::Submit { text: _, keys } = &state.action {
|
||||
for keysym in keys.iter() {
|
||||
write!(
|
||||
buf,
|
||||
"
|
||||
key <{}> {{ [ {0} ] }};",
|
||||
keysym.0,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
for (name, keycode) in pairs {
|
||||
write!(
|
||||
buf,
|
||||
"
|
||||
key <I{}> {{ [ {} ] }};",
|
||||
keycode,
|
||||
name,
|
||||
)?;
|
||||
}
|
||||
|
||||
writeln!(
|
||||
buf,
|
||||
"
|
||||
}};
|
||||
|
||||
xkb_types \"squeekboard\" {{
|
||||
virtual_modifiers Squeekboard; // No modifiers! Needed for Xorg for some reason.
|
||||
|
||||
// Those names are needed for Xwayland.
|
||||
type \"ONE_LEVEL\" {{
|
||||
modifiers= none;
|
||||
level_name[Level1]= \"Any\";
|
||||
}};
|
||||
type \"TWO_LEVEL\" {{
|
||||
level_name[Level1]= \"Base\";
|
||||
}};
|
||||
type \"ALPHABETIC\" {{
|
||||
level_name[Level1]= \"Base\";
|
||||
}};
|
||||
type \"KEYPAD\" {{
|
||||
level_name[Level1]= \"Base\";
|
||||
}};
|
||||
type \"SHIFT+ALT\" {{
|
||||
level_name[Level1]= \"Base\";
|
||||
}};
|
||||
|
||||
type \"TWO_LEVEL\" {{
|
||||
modifiers = Shift;
|
||||
map[Shift] = Level2;
|
||||
level_name[Level1] = \"Base\";
|
||||
level_name[Level2] = \"Shift\";
|
||||
}};
|
||||
}};
|
||||
|
||||
xkb_compatibility \"squeekboard\" {{
|
||||
// Needed for Xwayland again.
|
||||
interpret Any+AnyOf(all) {{
|
||||
action= SetMods(modifiers=modMapMods,clearLocks);
|
||||
}};
|
||||
}};
|
||||
}};"
|
||||
)?;
|
||||
@ -234,22 +279,15 @@ mod tests {
|
||||
|
||||
use xkbcommon::xkb;
|
||||
|
||||
use ::action::KeySym;
|
||||
|
||||
#[test]
|
||||
fn test_keymap_multi() {
|
||||
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
|
||||
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(&hashmap!{
|
||||
"ac".into() => KeyState {
|
||||
action: Action::Submit {
|
||||
text: None,
|
||||
keys: vec!(KeySym("a".into()), KeySym("c".into())),
|
||||
},
|
||||
keycodes: vec!(9, 10),
|
||||
pressed: PressType::Released,
|
||||
},
|
||||
}).unwrap();
|
||||
let keymap_str = generate_keymap(&key_map).unwrap();
|
||||
|
||||
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
|
||||
|
||||
let keymap = xkb::Keymap::new_from_string(
|
||||
&context,
|
||||
@ -263,4 +301,36 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
10
src/layout.h
10
src/layout.h
@ -26,20 +26,12 @@ 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);
|
||||
const char *squeek_layout_get_keymap(const struct squeek_layout*);
|
||||
struct squeek_layout *squeek_load_layout(const char *name, uint32_t type, uint32_t variant_type, const char *overlay_name);
|
||||
enum squeek_arrangement_kind squeek_layout_get_kind(const struct squeek_layout *);
|
||||
void squeek_layout_free(struct squeek_layout*);
|
||||
|
||||
|
||||
802
src/layout.rs
802
src/layout.rs
File diff suppressed because it is too large
Load Diff
@ -24,7 +24,6 @@ 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;
|
||||
|
||||
@ -9,7 +9,6 @@ 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,
|
||||
|
||||
@ -14,6 +14,7 @@ sources = [
|
||||
config_h,
|
||||
'dbus.c',
|
||||
'imservice.c',
|
||||
'popover.c',
|
||||
'server-context-service.c',
|
||||
'wayland.c',
|
||||
'../eek/eek.c',
|
||||
@ -79,6 +80,7 @@ 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],
|
||||
|
||||
69
src/popover.c
Normal file
69
src/popover.c
Normal file
@ -0,0 +1,69 @@
|
||||
#include <gio/gio.h>
|
||||
|
||||
static void
|
||||
call_dbus_cb (GDBusProxy *proxy,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr (GError) err = NULL;
|
||||
g_autoptr (GVariant) output = NULL;
|
||||
|
||||
output = g_dbus_proxy_call_finish (proxy, res, &err);
|
||||
if (err) {
|
||||
g_warning ("Can't open panel %s", err->message);
|
||||
}
|
||||
g_object_unref (proxy);
|
||||
}
|
||||
|
||||
static void
|
||||
create_dbus_proxy_cb (GObject *source_object, GAsyncResult *res, char *panel)
|
||||
{
|
||||
GDBusProxy *proxy;
|
||||
g_autoptr (GError) err = NULL;
|
||||
GVariantBuilder builder;
|
||||
GVariant *params[3];
|
||||
GVariant *array[1];
|
||||
|
||||
proxy = g_dbus_proxy_new_for_bus_finish (res, &err);
|
||||
|
||||
if (err != NULL) {
|
||||
g_warning ("Can't open panel %s: %s", panel, err->message);
|
||||
g_free (panel);
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
|
||||
g_variant_builder_add (&builder, "v", g_variant_new_string (""));
|
||||
|
||||
array[0] = g_variant_new ("v", g_variant_new ("(sav)", panel, &builder));
|
||||
|
||||
params[0] = g_variant_new_string ("launch-panel");
|
||||
params[1] = g_variant_new_array (G_VARIANT_TYPE ("v"), array, 1);
|
||||
params[2] = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0);
|
||||
|
||||
g_dbus_proxy_call (proxy,
|
||||
"Activate",
|
||||
g_variant_new_tuple (params, 3),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) call_dbus_cb,
|
||||
NULL);
|
||||
|
||||
g_free (panel);
|
||||
}
|
||||
|
||||
void
|
||||
popover_open_settings_panel (char *panel)
|
||||
{
|
||||
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
NULL,
|
||||
"org.gnome.ControlCenter",
|
||||
"/org/gnome/ControlCenter",
|
||||
"org.gtk.Actions",
|
||||
NULL,
|
||||
(GAsyncReadyCallback) create_dbus_proxy_cb,
|
||||
g_strdup (panel));
|
||||
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
#ifndef POPOVER_H__
|
||||
#define POPOVER_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "eek/eek-keyboard.h"
|
||||
|
||||
void squeek_popover_show(GtkWidget*, struct button_place);
|
||||
|
||||
#endif
|
||||
@ -3,6 +3,7 @@
|
||||
use gio;
|
||||
use gtk;
|
||||
use std::ffi::CString;
|
||||
use std::cmp::Ordering;
|
||||
use ::layout::c::{ Bounds, EekGtkKeyboard };
|
||||
use ::locale;
|
||||
use ::locale::{ OwnedTranslation, Translation, compare_current_locale };
|
||||
@ -25,6 +26,14 @@ use gtk::WidgetExt;
|
||||
use std::io::Write;
|
||||
use ::logging::Warn;
|
||||
|
||||
mod c {
|
||||
use std::os::raw::c_char;
|
||||
|
||||
extern "C" {
|
||||
pub fn popover_open_settings_panel(panel: *const c_char);
|
||||
}
|
||||
}
|
||||
|
||||
mod variants {
|
||||
use glib;
|
||||
use glib::Variant;
|
||||
@ -128,6 +137,12 @@ fn make_menu_builder(inputs: Vec<(&str, OwnedTranslation)>) -> gtk::Builder {
|
||||
xml,
|
||||
"
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name=\"label\" translatable=\"yes\">Keyboard Settings</attribute>
|
||||
<attribute name=\"action\">settings</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
</interface>"
|
||||
).unwrap();
|
||||
@ -198,7 +213,16 @@ fn set_visible_layout(
|
||||
layout_id: LayoutId,
|
||||
) {
|
||||
match layout_id {
|
||||
LayoutId::System { kind, name } => set_layout(kind, name),
|
||||
LayoutId::System { kind, name } => {
|
||||
unsafe {
|
||||
use std::ptr;
|
||||
manager::c::eekboard_context_service_set_overlay(
|
||||
manager,
|
||||
ptr::null(),
|
||||
);
|
||||
}
|
||||
set_layout(kind, name);
|
||||
}
|
||||
LayoutId::Local(name) => {
|
||||
let name = CString::new(name.as_str()).unwrap();
|
||||
let name_ptr = name.as_ptr();
|
||||
@ -334,8 +358,13 @@ pub fn show(
|
||||
.zip(all_layouts.clone().into_iter())
|
||||
.collect();
|
||||
|
||||
human_names.sort_unstable_by(|(tr_a, _), (tr_b, _)| {
|
||||
compare_current_locale(&tr_a.0, &tr_b.0)
|
||||
human_names.sort_unstable_by(|(tr_a, layout_a), (tr_b, layout_b)| {
|
||||
// Sort first by layout then name
|
||||
match (layout_a, layout_b) {
|
||||
(LayoutId::Local(_), LayoutId::System { .. }) => Ordering::Greater,
|
||||
(LayoutId::System { .. }, LayoutId::Local(_)) => Ordering::Less,
|
||||
_ => compare_current_locale(&tr_a.0, &tr_b.0)
|
||||
}
|
||||
});
|
||||
|
||||
// GVariant doesn't natively support `enum`s,
|
||||
@ -372,6 +401,7 @@ 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()
|
||||
@ -414,8 +444,15 @@ pub fn show(
|
||||
menu_inner.popdown();
|
||||
});
|
||||
|
||||
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()) };
|
||||
});
|
||||
|
||||
let action_group = gio::SimpleActionGroup::new();
|
||||
action_group.add_action(&layout_action);
|
||||
action_group.add_action(&settings_action);
|
||||
|
||||
menu.insert_action_group("popup", Some(&action_group));
|
||||
};
|
||||
|
||||
104
src/resources.rs
104
src/resources.rs
@ -10,68 +10,108 @@ 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"
|
||||
const KEYBOARDS: &[(*const str, *const str)] = &[
|
||||
/// List of builtin layouts
|
||||
static KEYBOARDS: &[(&'static str, &'static str)] = &[
|
||||
// layouts: us must be left as first, as it is the,
|
||||
// fallback layout. The others should be alphabetical.
|
||||
// fallback layout.
|
||||
("us", include_str!("../data/keyboards/us.yaml")),
|
||||
("us_wide", include_str!("../data/keyboards/us_wide.yaml")),
|
||||
("br", include_str!("../data/keyboards/br.yaml")),
|
||||
("de", include_str!("../data/keyboards/de.yaml")),
|
||||
|
||||
// Language layouts: keep alphabetical.
|
||||
("be", include_str!("../data/keyboards/be.yaml")),
|
||||
("be_wide", include_str!("../data/keyboards/be_wide.yaml")),
|
||||
|
||||
("bg", include_str!("../data/keyboards/bg.yaml")),
|
||||
|
||||
("br", include_str!("../data/keyboards/br.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")),
|
||||
// layout+overlay
|
||||
("terminal", include_str!("../data/keyboards/terminal.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")),
|
||||
|
||||
// Overlays
|
||||
("emoji", include_str!("../data/keyboards/emoji.yaml")),
|
||||
("emoji/us", include_str!("../data/keyboards/emoji/us.yaml")),
|
||||
];
|
||||
|
||||
pub fn get_keyboard(needle: &str) -> Option<&'static str> {
|
||||
// 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 }
|
||||
})
|
||||
KEYBOARDS.iter().find(|(name, _)| *name == needle).map(|(_, layout)| *layout)
|
||||
}
|
||||
|
||||
const OVERLAY_NAMES: &[*const str] = &[
|
||||
static OVERLAY_NAMES: &[&'static str] = &[
|
||||
"emoji",
|
||||
"terminal",
|
||||
];
|
||||
|
||||
pub fn get_overlays() -> Vec<&'static str> {
|
||||
OVERLAY_NAMES.iter()
|
||||
.map(|name| {
|
||||
let name: *const str = *name;
|
||||
unsafe { &*name }
|
||||
}).collect()
|
||||
OVERLAY_NAMES.to_vec()
|
||||
}
|
||||
|
||||
/// Translations of the layout identifier strings
|
||||
const LAYOUT_NAMES: &[(*const str, *const str)] = &[
|
||||
static LAYOUT_NAMES: &[(&'static str, &'static 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")),
|
||||
@ -81,14 +121,8 @@ pub fn get_layout_names(lang: &str)
|
||||
-> Option<HashMap<&'static str, Translation<'static>>>
|
||||
{
|
||||
let translations = LAYOUT_NAMES.iter()
|
||||
.find(|(name, _data)| {
|
||||
let name: *const str = *name;
|
||||
(unsafe { &*name }) == lang
|
||||
})
|
||||
.map(|(_name, data)| {
|
||||
let data: *const str = *data;
|
||||
unsafe { &*data }
|
||||
});
|
||||
.find(|(name, _data)| *name == lang)
|
||||
.map(|(_name, data)| *data);
|
||||
translations.map(make_mapping)
|
||||
}
|
||||
|
||||
@ -118,7 +152,7 @@ mod test {
|
||||
#[test]
|
||||
fn check_overlays_present() {
|
||||
for name in get_overlays() {
|
||||
assert!(get_keyboard(name).is_some());
|
||||
assert!(get_keyboard(&format!("{}/us", name)).is_some());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
@ -85,13 +85,20 @@ on_notify_unmap (ServerContextService *self, GtkWidget *widget)
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
calculate_height(int32_t width)
|
||||
calculate_height(int32_t width, GdkRectangle *geometry)
|
||||
{
|
||||
uint32_t height = 180;
|
||||
if (width < 360 && width > 0) {
|
||||
height = ((unsigned)width * 7 / 12); // to match 360×210
|
||||
} else if (width < 540) {
|
||||
height = 180 + (540 - (unsigned)width) * 30 / 180; // smooth transition
|
||||
uint32_t height;
|
||||
if (geometry->width > geometry->height) {
|
||||
// 1:5 ratio works fine on lanscape mode, and makes sure there's
|
||||
// room left for the app window
|
||||
height = width / 5;
|
||||
} else {
|
||||
if (width < 540 && width > 0) {
|
||||
height = ((unsigned)width * 7 / 12); // to match 360×210
|
||||
} else {
|
||||
// Here we switch to wide layout, less height needed
|
||||
height = ((unsigned)width * 7 / 22);
|
||||
}
|
||||
}
|
||||
return height;
|
||||
}
|
||||
@ -99,6 +106,10 @@ calculate_height(int32_t width)
|
||||
static void
|
||||
on_surface_configure(ServerContextService *self, PhoshLayerSurface *surface)
|
||||
{
|
||||
GdkDisplay *display = NULL;
|
||||
GdkWindow *window = NULL;
|
||||
GdkMonitor *monitor = NULL;
|
||||
GdkRectangle geometry;
|
||||
gint width;
|
||||
gint height;
|
||||
|
||||
@ -110,11 +121,27 @@ on_surface_configure(ServerContextService *self, PhoshLayerSurface *surface)
|
||||
"configured-height", &height,
|
||||
NULL);
|
||||
|
||||
// When the geometry event comes after surface.configure,
|
||||
// this entire height calculation does nothing.
|
||||
// guint desired_height = squeek_uiman_get_perceptual_height(context->manager);
|
||||
// Temporarily use old method, until the size manager is complete.
|
||||
guint desired_height = calculate_height(width);
|
||||
// In order to improve height calculation, we need the monitor geometry so
|
||||
// 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) {
|
||||
window = gtk_widget_get_window (GTK_WIDGET (surface));
|
||||
}
|
||||
if (window) {
|
||||
monitor = gdk_display_get_monitor_at_window (display, window);
|
||||
}
|
||||
if (monitor) {
|
||||
gdk_monitor_get_geometry (monitor, &geometry);
|
||||
} else {
|
||||
geometry.width = geometry.height = 0;
|
||||
}
|
||||
|
||||
// When the geometry event comes after surface.configure,
|
||||
// this entire height calculation does nothing.
|
||||
// guint desired_height = squeek_uiman_get_perceptual_height(context->manager);
|
||||
// Temporarily use old method, until the size manager is complete.
|
||||
guint desired_height = calculate_height(width, &geometry);
|
||||
|
||||
guint configured_height = (guint)height;
|
||||
// if height was already requested once but a different one was given
|
||||
@ -135,8 +162,9 @@ 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);
|
||||
@ -198,52 +226,75 @@ 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)
|
||||
{
|
||||
gtk_widget_hide (GTK_WIDGET(self->window));
|
||||
server_context_service_real_hide_keyboard(self);
|
||||
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->visible) {
|
||||
server_context_service_real_show_keyboard (self);
|
||||
if (self->hiding) {
|
||||
g_source_remove (self->hiding);
|
||||
self->hiding = 0;
|
||||
}
|
||||
|
||||
if (!self->visible) {
|
||||
g_idle_add((GSourceFunc)show_keyboard_source_func, 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
|
||||
@ -252,10 +303,33 @@ server_context_service_hide_keyboard (ServerContextService *self)
|
||||
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE(self));
|
||||
|
||||
if (self->visible) {
|
||||
server_context_service_real_hide_keyboard (self);
|
||||
g_idle_add((GSourceFunc)hide_keyboard_source_func, 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,
|
||||
@ -269,7 +343,7 @@ server_context_service_set_property (GObject *object,
|
||||
self->visible = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_ENABLED:
|
||||
server_context_service_set_enabled (self, g_value_get_boolean (value));
|
||||
server_context_service_set_physical_keyboard_present (self, !g_value_get_boolean (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
@ -344,12 +418,14 @@ server_context_service_class_init (ServerContextServiceClass *klass)
|
||||
}
|
||||
|
||||
static void
|
||||
server_context_service_init (ServerContextService *self) {
|
||||
server_context_service_init (ServerContextService *self) {}
|
||||
|
||||
static void
|
||||
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;
|
||||
@ -366,27 +442,24 @@ server_context_service_init (ServerContextService *self) {
|
||||
}
|
||||
|
||||
ServerContextService *
|
||||
server_context_service_new (EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman)
|
||||
server_context_service_new (EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman, struct vis_manager *visman)
|
||||
{
|
||||
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_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);
|
||||
server_context_service_update_visible (ServerContextService *self, gboolean visible) {
|
||||
if (visible) {
|
||||
server_context_service_show_keyboard(self);
|
||||
} else {
|
||||
server_context_service_hide_keyboard(self);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -29,11 +29,10 @@ 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);
|
||||
ServerContextService *server_context_service_new(EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman, struct vis_manager *visman);
|
||||
enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *);
|
||||
void server_context_service_show_keyboard (ServerContextService *self);
|
||||
void server_context_service_force_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 */
|
||||
|
||||
|
||||
@ -50,9 +50,16 @@ 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
|
||||
@ -131,6 +138,67 @@ 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) {
|
||||
@ -151,7 +219,8 @@ session_register(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_dbus_proxy_call_sync(_proxy, "RegisterClient",
|
||||
g_autoptr (GVariant) res = NULL;
|
||||
res = 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) {
|
||||
@ -160,6 +229,22 @@ 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
|
||||
@ -213,12 +298,13 @@ 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;
|
||||
@ -276,8 +362,11 @@ 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);
|
||||
|
||||
@ -287,15 +376,15 @@ main (int argc, char **argv)
|
||||
instance.settings_context,
|
||||
instance.submission,
|
||||
&instance.layout_choice,
|
||||
instance.ui_manager);
|
||||
instance.ui_manager,
|
||||
vis_manager);
|
||||
if (!ui_context) {
|
||||
g_error("Could not initialize GUI");
|
||||
exit(1);
|
||||
}
|
||||
instance.ui_context = ui_context;
|
||||
if (instance.submission) {
|
||||
submission_set_ui(instance.submission, instance.ui_context);
|
||||
}
|
||||
squeek_visman_set_ui(vis_manager, instance.ui_context);
|
||||
|
||||
if (instance.dbus_handler) {
|
||||
dbus_handler_set_ui_context(instance.dbus_handler, instance.ui_context);
|
||||
}
|
||||
@ -303,8 +392,7 @@ main (int argc, char **argv)
|
||||
|
||||
session_register();
|
||||
|
||||
GMainLoop *loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
if (connection) {
|
||||
|
||||
@ -4,16 +4,20 @@
|
||||
#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 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);
|
||||
void submission_set_ui(struct submission *self, ServerContextService *ui_context);
|
||||
void submission_set_keyboard(struct submission *self, LevelKeyboard *keyboard, uint32_t time);
|
||||
void submission_use_layout(struct submission *self, struct squeek_layout *layout, uint32_t time);
|
||||
#endif
|
||||
|
||||
@ -23,8 +23,10 @@ use ::action::Modifier;
|
||||
use ::imservice;
|
||||
use ::imservice::IMService;
|
||||
use ::keyboard::{ KeyCode, KeyStateId, Modifiers, PressType };
|
||||
use ::layout::c::LevelKeyboard;
|
||||
use ::layout;
|
||||
use ::ui_manager::VisibilityManager;
|
||||
use ::util::vec_remove;
|
||||
use ::vkeyboard;
|
||||
use ::vkeyboard::VirtualKeyboard;
|
||||
|
||||
// traits
|
||||
@ -37,14 +39,11 @@ 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);
|
||||
@ -54,12 +53,18 @@ pub mod c {
|
||||
fn submission_new(
|
||||
im: *mut InputMethod,
|
||||
vk: ZwpVirtualKeyboardV1,
|
||||
state_manager: *const StateManager
|
||||
state_manager: *const StateManager,
|
||||
visibility_manager: Wrapped<VisibilityManager>,
|
||||
) -> *mut Submission {
|
||||
let imservice = if im.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(IMService::new(im, state_manager))
|
||||
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)),
|
||||
))
|
||||
};
|
||||
// TODO: add vkeyboard too
|
||||
Box::<Submission>::into_raw(Box::new(
|
||||
@ -68,39 +73,37 @@ 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_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(
|
||||
fn submission_use_layout(
|
||||
submission: *mut Submission,
|
||||
keyboard: LevelKeyboard,
|
||||
layout: *const layout::Layout,
|
||||
time: u32,
|
||||
) {
|
||||
if submission.is_null() {
|
||||
panic!("Null submission pointer");
|
||||
}
|
||||
let submission: &mut Submission = unsafe { &mut *submission };
|
||||
submission.update_keymap(keyboard, Timestamp(time));
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,6 +122,8 @@ 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> {
|
||||
@ -144,7 +149,7 @@ impl Submission {
|
||||
enum Outcome {
|
||||
Submitted(Result<(), imservice::SubmitError>),
|
||||
NotSubmitted,
|
||||
};
|
||||
}
|
||||
|
||||
let submit_outcome = match data {
|
||||
SubmitData::Text(text) => {
|
||||
@ -177,11 +182,34 @@ impl Submission {
|
||||
let submit_action = match was_committed_as_text {
|
||||
true => SubmittedAction::IMService,
|
||||
false => {
|
||||
self.virtual_keyboard.switch(
|
||||
keycodes,
|
||||
PressType::Pressed,
|
||||
time,
|
||||
);
|
||||
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,
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
SubmittedAction::VirtualKeyboard(keycodes.clone())
|
||||
},
|
||||
};
|
||||
@ -199,11 +227,21 @@ impl Submission {
|
||||
// no matter if the imservice got activated,
|
||||
// keys must be released
|
||||
SubmittedAction::VirtualKeyboard(keycodes) => {
|
||||
self.virtual_keyboard.switch(
|
||||
&keycodes,
|
||||
PressType::Released,
|
||||
time,
|
||||
)
|
||||
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.
|
||||
_ => {},
|
||||
};
|
||||
},
|
||||
}
|
||||
};
|
||||
@ -232,6 +270,7 @@ 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);
|
||||
@ -274,6 +313,7 @@ impl Submission {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Changes keymap and clears pressed keys and modifiers.
|
||||
///
|
||||
/// It's not obvious if clearing is the right thing to do,
|
||||
@ -283,9 +323,28 @@ 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.
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
103
src/tests.rs
103
src/tests.rs
@ -1,6 +1,6 @@
|
||||
/*! Testing functionality */
|
||||
|
||||
use ::data::Layout;
|
||||
use ::data::parsing::Layout;
|
||||
use ::logging;
|
||||
use xkbcommon::xkb;
|
||||
|
||||
@ -26,17 +26,53 @@ impl CountAndPrint {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_builtin_layout(name: &str) {
|
||||
check_layout(Layout::from_resource(name).expect("Invalid layout data"))
|
||||
pub fn check_builtin_layout(name: &str, missing_return: bool) {
|
||||
check_layout(
|
||||
Layout::from_resource(name).expect("Invalid layout data"),
|
||||
missing_return,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn check_layout_file(path: &str) {
|
||||
check_layout(Layout::from_file(path.into()).expect("Invalid layout file"))
|
||||
check_layout(
|
||||
Layout::from_file(path.into()).expect("Invalid layout file"),
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
fn check_layout(layout: Layout) {
|
||||
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],
|
||||
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 {
|
||||
handler.handle(
|
||||
logging::Level::Surprise,
|
||||
&format!("There's no way to input the keysym {} on this layout", sym_name),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_layout(layout: Layout, allow_missing_return: bool) {
|
||||
let handler = CountAndPrint::new();
|
||||
let (layout, handler) = layout.build(handler);
|
||||
let (layout, mut handler) = layout.build(handler);
|
||||
|
||||
if handler.0 > 0 {
|
||||
println!("{} problems while parsing layout", handler.0)
|
||||
@ -44,31 +80,50 @@ fn check_layout(layout: Layout) {
|
||||
|
||||
let layout = layout.expect("layout broken");
|
||||
|
||||
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
|
||||
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();
|
||||
|
||||
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(&xkb_states, "BackSpace", &mut handler);
|
||||
let mut printer = logging::Print;
|
||||
check_sym_presence(
|
||||
&xkb_states,
|
||||
"Return",
|
||||
if allow_missing_return { &mut printer }
|
||||
else { &mut handler },
|
||||
);
|
||||
|
||||
// "Press" each button with keysyms
|
||||
for (_pos, view) in layout.views.values() {
|
||||
for (_y, row) in &view.get_rows() {
|
||||
for (_x, button) in &row.buttons {
|
||||
for (_y, row) in view.get_rows() {
|
||||
for (_x, button) in row.get_buttons() {
|
||||
let keystate = button.state.borrow();
|
||||
for keycode in &keystate.keycodes {
|
||||
match state.key_get_one_sym(*keycode) {
|
||||
match xkb_states[keycode.keymap_idx].key_get_one_sym(keycode.code) {
|
||||
xkb::KEY_NoSymbol => {
|
||||
eprintln!("{}", keymap_str);
|
||||
panic!("Keysym {} on key {:?} can't be resolved", keycode, button.name);
|
||||
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,
|
||||
);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "eek/eek-types.h"
|
||||
#include "outputs.h"
|
||||
|
||||
struct ui_manager;
|
||||
@ -11,4 +12,9 @@ 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
|
||||
|
||||
@ -10,10 +10,49 @@
|
||||
use std::cmp::min;
|
||||
use ::outputs::c::OutputHandle;
|
||||
|
||||
mod c {
|
||||
pub 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"
|
||||
fn squeek_uiman_new() -> Wrapped<Manager> {
|
||||
@ -79,3 +118,131 @@ 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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
25
src/util.rs
25
src/util.rs
@ -203,6 +203,23 @@ 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::*;
|
||||
@ -217,4 +234,12 @@ 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)]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,20 +1,46 @@
|
||||
/*! Managing the events belonging to virtual-keyboard interface. */
|
||||
|
||||
use ::keyboard::{ KeyCode, Modifiers, PressType };
|
||||
use ::layout::c::LevelKeyboard;
|
||||
use ::keyboard::{ Modifiers, PressType };
|
||||
use ::submission::Timestamp;
|
||||
|
||||
/// Standard xkb keycode
|
||||
type KeyCode = u32;
|
||||
|
||||
/// Gathers stuff defined in C or called by C
|
||||
pub mod c {
|
||||
use super::*;
|
||||
use std::os::raw::c_void;
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::{ c_char, c_void };
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ZwpVirtualKeyboardV1(*const c_void);
|
||||
|
||||
#[no_mangle]
|
||||
#[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
@ -24,13 +50,15 @@ pub mod c {
|
||||
|
||||
pub fn eek_virtual_keyboard_update_keymap(
|
||||
virtual_keyboard: ZwpVirtualKeyboardV1,
|
||||
keyboard: LevelKeyboard,
|
||||
keymap: *const KeyMap,
|
||||
);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,35 +69,15 @@ impl VirtualKeyboard {
|
||||
// TODO: error out if keymap not set
|
||||
pub fn switch(
|
||||
&self,
|
||||
keycodes: &Vec<KeyCode>,
|
||||
keycode: KeyCode,
|
||||
action: PressType,
|
||||
timestamp: Timestamp,
|
||||
) {
|
||||
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, _) => {},
|
||||
}
|
||||
let keycode = keycode - 8;
|
||||
unsafe {
|
||||
c::eek_virtual_keyboard_v1_key(
|
||||
self.0, timestamp.0, keycode, action.clone() as u32
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,9 +88,12 @@ impl VirtualKeyboard {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_keymap(&self, keyboard: LevelKeyboard) {
|
||||
pub fn update_keymap(&self, keymap: &c::KeyMap) {
|
||||
unsafe {
|
||||
c::eek_virtual_keyboard_update_keymap(self.0, keyboard);
|
||||
c::eek_virtual_keyboard_update_keymap(
|
||||
self.0,
|
||||
keymap as *const c::KeyMap,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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, const LevelKeyboard *keyboard) {
|
||||
void eek_virtual_keyboard_update_keymap(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, struct keymap *keymap) {
|
||||
zwp_virtual_keyboard_v1_keymap(zwp_virtual_keyboard_v1,
|
||||
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
|
||||
keyboard->keymap_fd, keyboard->keymap_len);
|
||||
keymap->fd, keymap->fd_len);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
10
tests/layout_erase.yaml
Normal file
10
tests/layout_erase.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
# Erase only
|
||||
views:
|
||||
base:
|
||||
- "BackSpace"
|
||||
outlines:
|
||||
default: { width: 0, height: 0 }
|
||||
buttons:
|
||||
BackSpace:
|
||||
action: erase
|
||||
@ -46,34 +46,75 @@ endforeach
|
||||
|
||||
# The layout test is in the examples directory
|
||||
# due to the way Cargo builds executables
|
||||
# and the need to call it manually
|
||||
# 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.
|
||||
foreach layout : [
|
||||
# This is the fallback layout,
|
||||
# so stays first to make sure it never goes missing.
|
||||
'us', 'us_wide',
|
||||
|
||||
# Block: Languages
|
||||
'be', 'be_wide',
|
||||
'bg',
|
||||
'br',
|
||||
'be',
|
||||
'cz', 'cz_wide',
|
||||
'cz+qwerty', 'cz+qwerty_wide',
|
||||
'de', 'de_wide',
|
||||
'dk',
|
||||
'epo',
|
||||
'es',
|
||||
'es+cat',
|
||||
'fi',
|
||||
'fr',
|
||||
'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',
|
||||
'terminal',
|
||||
'us+colemak', 'us+colemak_wide',
|
||||
'us+dvorak', 'us+dvorak_wide',
|
||||
|
||||
'emoji',
|
||||
# Terminal keyboards
|
||||
'terminal/fr',
|
||||
'terminal/us',
|
||||
'terminal/us_wide',
|
||||
|
||||
# Block: Not languages.
|
||||
'emoji/us',
|
||||
'number/us',
|
||||
]
|
||||
extra = []
|
||||
if layout.startswith('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],
|
||||
+ ['--example', 'test_layout', '--', layout]
|
||||
+ extra,
|
||||
timeout: timeout,
|
||||
workdir: meson.build_root(),
|
||||
)
|
||||
endforeach
|
||||
|
||||
Reference in New Issue
Block a user