Compare commits

...

94 Commits

Author SHA1 Message Date
74af1336e8 input_method: Hide when input provided by application 2019-12-19 12:46:09 +00:00
88b0afa319 input_method: Add on_screen_input_provided hint 2019-12-19 12:25:32 +00:00
4d487ed872 input_method: Print misunderstood flags 2019-12-19 12:24:07 +00:00
e9d6631159 tools: Add GTK's INHIBIT_OSK flag to the entry tester 2019-12-18 19:56:02 +00:00
1237537005 Merge branch 'lockfile' into 'master'
Use clap in the lockfile

See merge request Librem5/squeekboard!284
2019-12-15 19:07:23 +00:00
927f088027 Use clap in the lockfile 2019-12-15 18:42:33 +00:00
8b3f7e0b11 Merge branch 'positioning' into 'master'
Positioning

See merge request Librem5/squeekboard!274
2019-12-15 16:51:35 +00:00
ae43d7ca47 Merge branch 'terminal_purpose' into 'master'
Entry test: Add Terminal input purpose

See merge request Librem5/squeekboard!278
2019-12-15 16:41:59 +00:00
432e4fe1e5 Merge branch 'drop_key' into 'master'
Simplify renderer

See merge request Librem5/squeekboard!272
2019-12-15 16:38:31 +00:00
6afa2133d0 Merge branch 'squeekboard-test-layout-args-check' into 'master'
squeekboard-test-layout: add argument parsing and some more output

See merge request Librem5/squeekboard!277
2019-12-14 10:55:37 +00:00
cfa66d8182 squeekboard-test-layout: add argument parsing and some more output 2019-12-14 10:55:37 +00:00
b6e67256c3 Merge branch 'dco' into 'master'
hacking: Add DCO and licensing requirement

See merge request Librem5/squeekboard!282
2019-12-11 17:37:55 +00:00
6f990f4528 hacking: Add DCO and licensing requirement 2019-12-11 15:44:26 +00:00
0b136468c8 Entry test: Add Terminal input purpose 2019-12-09 13:38:19 +00:00
fe4642e71e Merge branch 'japanese-kana-wide-keyboard-layout' into 'master'
layout: add Japanese Kana wide layout

See merge request Librem5/squeekboard!275
2019-12-09 11:12:48 +00:00
16289c6f82 layout: add Japanese Kana wide layout 2019-12-09 11:12:48 +00:00
b639c7f3f0 Fix old Rust woes 2019-12-08 07:04:22 +00:00
d80758fcd1 positioning: Clean up unused code 2019-12-07 21:33:38 +00:00
dd21bfed8d positioning: Calculate sizes instead of storing, move position out of widgets
Sizes of widgets can be derived, so storing them was only for C compatibility. Similar with storing position inside of widgets.

Some layout margin and scaling changes could be introduced, meaning a possibility of visual differences.
2019-12-07 21:20:21 +00:00
1f69787fac cleanup: Remove unused single frame draw 2019-12-07 17:19:49 +00:00
36362291ef cleanup: Unbox View and Row
They are no longer referenced anywhere in C, so it's safe to let Rust memory management deal with them.
2019-12-07 17:19:39 +00:00
1c4d027af5 cleanup: Remove references to squeek_view 2019-12-07 15:42:54 +00:00
51a77c41c3 renderer: Remove unused functions 2019-12-07 15:19:53 +00:00
8b4c643d3e Merge branch 'german-wide-keyboard-layout' into 'master'
layout: add German wide layout

See merge request Librem5/squeekboard!271
2019-12-07 14:39:43 +00:00
358b25c431 layout: add German wide layout 2019-12-07 14:39:43 +00:00
f77db1bb73 renderer: Render whole keyboard the same way as pressed buttons
Removed window size dependent surface.
2019-12-07 14:33:49 +00:00
581c86809a renderer: Simply cut off when painting outside bounds 2019-12-07 14:03:51 +00:00
804aa53351 renderer: Remove unused locked key render function 2019-12-07 14:01:03 +00:00
e6da2a3b5b rendering: Remove unneeded redraw after button release 2019-12-07 13:58:50 +00:00
f9fbd3fb2d rendering: Simplify Cairo context usage, remove unneeded calls.
Moved Cairo context usage to Rust, and rearranged ctx setup (position) to happen in one place.

Removed render calls that were overwritten on each draw call anyway.
2019-12-07 12:47:47 +00:00
2749fdb686 Merge branch 'click' into 'master'
Switch layout on click

Closes #157

See merge request Librem5/squeekboard!266
2019-12-05 23:49:37 +00:00
8e7909e877 Merge branch 'stable' into 'master'
keycodes: Sort to eliminate runtime indeterminism

See merge request Librem5/squeekboard!268
2019-12-05 22:20:43 +00:00
afaacd3f68 Merge branch '1.4' into 'master'
Release 1.4.0 "Nacelle"

See merge request Librem5/squeekboard!273
2019-12-02 19:53:20 +00:00
6a164d8119 Release 1.4.0 "Nacelle"
Major changes:

- "text" property for layouts
- adjusting to user's color scheme
2019-12-02 19:40:14 +00:00
6e32a2ef41 renderer: Simplify surface rendering 2019-12-01 16:00:40 +00:00
34fce7395d renderer: Drop unused params 2019-12-01 15:36:01 +00:00
d415ecf5d0 renderer: Drop row from button rendering 2019-12-01 15:31:16 +00:00
5266c621fd renderer: Simplified outline rendering 2019-12-01 15:27:14 +00:00
4ee832c594 renderer: Remove some unneeded vars 2019-12-01 15:22:00 +00:00
83fea8cd31 Drop squeek_key 2019-12-01 15:01:08 +00:00
3c45e3e53c switcher: Switch layout on menu item click 2019-11-30 15:14:45 +00:00
cdf263d984 Merge branch 'translation-and-minor-layout-fixes' into 'master'
translation: Japanese and minor layout fixes

See merge request Librem5/squeekboard!264
2019-11-30 12:22:45 +00:00
2ddfcfaff0 translation: Japanese and minor layout fixes 2019-11-30 12:22:45 +00:00
a901c85bcb Merge branch 'themes' into 'master'
Use appropriate styling for layouts

See merge request Librem5/squeekboard!253
2019-11-30 11:08:08 +00:00
fdbbe8f126 Merge branch 'settings' into 'master'
Implement the word-of-mouth layout selection

See merge request Librem5/squeekboard!260
2019-11-29 18:19:17 +00:00
f284627beb Merge branch 'release' into 'master'
Use Cargo release flag

See merge request Librem5/squeekboard!256
2019-11-29 15:33:00 +00:00
d45724c462 Merge branch 'leave' into 'master'
pointer: Release button when window is left

Closes #46

See merge request Librem5/squeekboard!262
2019-11-29 13:47:48 +00:00
93d0dcdc99 Merge branch 'text' into 'master'
Text property

Closes #153

See merge request Librem5/squeekboard!257
2019-11-28 09:19:30 +00:00
b252f7659b rust: Be compatible with older Rust 2019-11-27 16:52:50 +00:00
af6ad1fce6 buttons: Accept "text" and drop xkb keysym derivation 2019-11-27 16:52:50 +00:00
4ee8a91dfe build: Bring back squeekboard as a first class executable
With styles no longer being inconsistent, there's no need to override styles by default. The override script remains for PureOS packaging purposes.
2019-11-27 16:37:44 +00:00
6d5f793718 util: Include Result logger 2019-11-27 16:31:24 +00:00
59f6173282 theme: Use a matching layout theme for any widget theme
Dedicated styling is now possible for themes which have a corresponding style-theme.css file. Adwaita:dark gets one, whereas other themes use the new generic fallback theme.
2019-11-27 16:30:32 +00:00
3aec821f92 Merge branch 'errors' into 'master'
Better layout checking

Closes #131

See merge request Librem5/squeekboard!255
2019-11-27 16:22:08 +00:00
3ac4caa3b9 keycodes: Sort to eliminate runtime indeterminism 2019-11-27 16:18:36 +00:00
80ac591535 Merge branch 'deadkey' into 'master'
Bugfix release 1.3.2: work around sending keycode 0

See merge request Librem5/squeekboard!267
2019-11-26 15:55:10 +00:00
579ba8ab87 Release 1.3.2 2019-11-26 15:38:32 +00:00
5a262242a3 keymap: Work around sending keycode 0
If keycode 0 resolves to a letter, the the press is ignored by the compositor. This works around the bug.
2019-11-26 15:35:22 +00:00
034570bfa0 readme: Update language selection 2019-11-21 18:57:34 +00:00
1abca0a44e settings: Fetch current layout as the first item 2019-11-21 18:57:34 +00:00
23693521b7 popover: Don't change "current" field on language settings, change order
Also stops crashes when sources list is empty.
2019-11-21 18:57:09 +00:00
bb18e60754 Merge branch 'release1' into 'master'
Release 1.3.1

See merge request Librem5/squeekboard!265
2019-11-20 22:24:02 +00:00
35bc163107 Release 1.3.1
Fixing layout issues and building failures due to tests taking a long time.
2019-11-20 22:13:31 +00:00
0179507254 readme: Update cargo.sh usage 2019-11-20 14:32:42 +00:00
0c7e77a05f pointer: Release button when window is left 2019-11-20 13:17:47 +00:00
317d8a58dc Merge branch 'translations' into 'master'
translations: Updated pl and en with new layouts

See merge request Librem5/squeekboard!261
2019-11-20 12:26:39 +00:00
89b3ab9a81 translations: Updated pl and en with new layouts 2019-11-20 12:12:07 +00:00
8690808a29 layouts: Correct xkb symbols usage 2019-11-20 11:18:02 +00:00
be4ac32477 Merge branch '153-fix-German-layout-xkb-buttons-without-keycode-property' into 'master'
German layout: Correct xkb symbols usage

See merge request Librem5/squeekboard!251
2019-11-20 11:15:18 +00:00
5068f36d9d German layout: Correct xkb symbols usage 2019-11-20 11:15:18 +00:00
8c48e96f50 Merge branch 'codes' into 'master'
Language code fixes

See merge request Librem5/squeekboard!258
2019-11-20 11:12:47 +00:00
f15619287a Merge branch 'de' into 'master'
DE fixes

See merge request Librem5/squeekboard!259
2019-11-20 10:47:34 +00:00
eb5c28e77f translation: Use right codes in German 2019-11-20 10:25:56 +00:00
7fb34feaf8 translations: Use the correct code for Norwegian 2019-11-20 10:24:31 +00:00
20a6cf52ac layouts: Rename ja+kana to jp+kana 2019-11-20 10:23:05 +00:00
c566d8853e translations: Register Spanish 2019-11-20 10:21:41 +00:00
0beddc6856 Merge branch 'patch-8' into 'master'
translations: Spanish

See merge request Librem5/squeekboard!246
2019-11-20 10:11:48 +00:00
0adde1004f cargo: Use release mode for release builds 2019-11-19 13:50:36 +00:00
9b271a6919 devel: Package squeekboard-test-layout 2019-11-19 12:22:24 +00:00
1db561d33a build: Handle output files better 2019-11-19 12:15:08 +00:00
3170a0b615 Merge branch 'renderer' into 'master'
Renderer reworks

See merge request Librem5/squeekboard!238
2019-11-19 10:34:47 +00:00
9571adb107 tests: Executable for testing layouts 2019-11-19 09:47:32 +00:00
f834f174d8 cargo: Copy target with properties, find filename automatically 2019-11-19 09:35:32 +00:00
3c0b142c4f warnings: Print at runtime, crash at test time 2019-11-19 08:29:57 +00:00
4f28e3413a langs: add de-DE for switcher 2019-11-19 00:10:35 +01:00
291be9fa79 Update de-DE.txt 2019-11-18 22:58:27 +00:00
fd5d060eee langs: add de-DE for switcher 2019-11-18 22:56:47 +01:00
cffe07521e Merge branch 'prebuild_tests' into 'master'
Prebuild tests

See merge request Librem5/squeekboard!250
2019-11-17 15:14:50 +00:00
36af546362 tests: Bump timeout for the execution of all unit tests 2019-11-17 15:06:07 +00:00
0da848a5a0 tests: Use correct test compilation command 2019-11-17 14:56:25 +00:00
8c9ae98bda Merge branch 'release' into 'master'
Release 1.3.0

See merge request Librem5/squeekboard!247
2019-11-16 15:49:58 +00:00
ef025509ba translations: Spanish 2019-11-15 20:57:24 +00:00
c096698ec1 renderer: Remove unused ascii_font 2019-11-07 14:13:27 +00:00
3aaaed3bae renderer: Clean up EekColor & label 2019-11-07 14:10:20 +00:00
62 changed files with 2355 additions and 1867 deletions

65
Cargo.lock generated
View File

@ -8,6 +8,14 @@ dependencies = [
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atk-sys"
version = "0.7.0"
@ -19,6 +27,15 @@ dependencies = [
"pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "1.0.4"
@ -54,6 +71,20 @@ name = "cc"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dtoa"
version = "0.4.4"
@ -324,6 +355,10 @@ name = "rs"
version = "0.1.0"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-sys-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -365,6 +400,11 @@ dependencies = [
"yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "strsim"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "1.0.5"
@ -375,6 +415,14 @@ dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.3.6"
@ -383,6 +431,11 @@ dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-width"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.2.0"
@ -393,6 +446,11 @@ name = "utf8-ranges"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.8"
@ -431,11 +489,14 @@ dependencies = [
[metadata]
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atk-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7017e53393e713212aed7aea336b6553be4927f58c37070a56c2fe3d107e489"
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum cairo-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd940f0d609699e343ef71c4af5f66423afbf30d666f796dabd8fd15229cf5b6"
"checksum cairo-sys-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d25596627380be4381247dba06c69ad05ca21b3b065bd9827e416882ac41dcd2"
"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be"
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e"
"checksum fragile 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f8140122fa0d5dcb9fc8627cfce2b37cc1500f752636d46ea28bc26785c2f9"
"checksum gdk 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc52c7244046df9d959df87289f1fc5cca23f9f850bab0c967963e2ecb83a96"
@ -465,10 +526,14 @@ dependencies = [
"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
"checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"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 utf8-ranges 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"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"

View File

@ -4,12 +4,22 @@ version = "0.1.0"
[dependencies]
bitflags = "1.0.*"
clap = "2.32.*"
maplit = "1.0.*"
regex = "1.1.*"
serde = { version = "1.0.*", features = ["derive"] }
serde_yaml = "0.8.*"
xkbcommon = { version = "0.4.*", features = ["wayland"] }
[dependencies.cairo-rs]
version = "0.5.*"
[dependencies.cairo-sys-rs]
version = ""
[dependencies.gdk]
version = ""
[dependencies.gio]
version = ""
features = ["v2_44"]
@ -22,7 +32,6 @@ features = ["v2_44"]
version = ""
features = ["v2_44"]
[dependencies.gtk]
version = "0.5.*"
features = ["v3_22"]

View File

@ -3,6 +3,11 @@ Hacking
This document describes the standards for modifying and maintaining the *squeekboard* project.
Sending patches
---------------
By submitting a change to this project, you agree to license it under the [GPL license version 3](./COPYING), or any later version. You also certify that your contribution fulfills the [Developer's Certificate of Origin 1.1](./dco.txt).
Development environment
-----------------------
@ -30,7 +35,7 @@ Most common testing is done in CI. Occasionally, and for each release, do perfor
- the application draws correctly
- it shows when relevant
- it changes layouts
- it changes levels
- it changes views
Testing with an application:
@ -50,10 +55,8 @@ Testing layouts:
Layouts can be selected using the GNOME Settings application.
```
# define all available layouts
$ gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'us'), ('xkb', 'ua')]"
# choose the active layout
$ gsettings set org.gnome.desktop.input-sources current 1
# define all available layouts. First one is currently selected.
$ gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'us'), ('xkb', 'de')]"
```
Coding
@ -114,7 +117,7 @@ Use the `cargo.sh` script for maintaining the Cargo part of the build. The scrip
```
cd build_dir
sh /source_path/cargo.sh '' test
sh /source_path/cargo.sh test
```
### Cargo dependencies
@ -125,6 +128,6 @@ Dependencies must be specified in `Cargo.toml` with 2 numbers: "major.minor". Si
```
cd build_dir
sh /source_path/cargo.sh '' update
sh /source_path/cargo.sh update
ninja test
```

View File

@ -11,14 +11,7 @@ SOURCE_DIR="$(dirname "$SCRIPT_PATH")"
CARGO_TARGET_DIR="$(pwd)"
export CARGO_TARGET_DIR
if [ -n "${1}" ]; then
OUT_PATH="$(realpath "$1")"
fi
cd "$SOURCE_DIR"
shift
cargo "$@"
if [ -n "${OUT_PATH}" ]; then
cp "${CARGO_TARGET_DIR}"/debug/librs.a "${OUT_PATH}"
fi

34
cargo_build.sh Executable file
View File

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

View File

@ -1,7 +1,6 @@
# German layout by Mark Müller
# Version 2019101900
# Maintained by: Mark Müller <markmueller86@gmail.com>
---
bounds: { x: 0, y: 1, width: 360, height: 210 }
bounds: { x: 0, y: 1, width: 360, height: 208 }
outlines:
default:
@ -20,27 +19,27 @@ views:
- "q w e r t z u i o p"
- "a s d f g h j k l"
- "Shift_L y x c v b n m BackSpace"
- "show_numbers show_dechars preferences space , period Return"
- "show_numbers show_eschars preferences space , . Return"
upper:
- "Q W E R T Z U I O P"
- "A S D F G H J K L"
- "Shift_L Y X C V B N M BackSpace"
- "show_numbers show_dechars preferences space ! ? Return"
- "show_numbers show_eschars preferences space ! ? Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon = < > BackSpace"
- "show_letters show_dechars preferences space , period Return"
- "show_symbols , \" ' : = < > BackSpace"
- "show_letters show_eschars preferences space , . Return"
symbols:
- "~ ` ´ | · √ µ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers \\ / § π τ [ ] BackSpace"
- "show_letters show_dechars preferences space , period Return"
dechars:
- "show_letters show_eschars preferences space , . Return"
eschars:
- "ä è é ö ü Ä È É Ö Ü"
- "à â ê î ô À Â È Î Ô"
- "show_numbers « » ç Ç æ œ ß BackSpace"
- "show_letters show_dechars preferences space „ “ Return"
- "show_letters show_eschars preferences space „ “ Return"
buttons:
Shift_L:
@ -53,6 +52,7 @@ buttons:
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
keysym: "BackSpace"
preferences:
action: "show_prefs"
outline: "special"
@ -72,24 +72,18 @@ buttons:
set_view: "symbols"
outline: "altline"
label: "*/="
show_dechars:
show_eschars:
action:
locking:
lock_view: "dechars"
lock_view: "eschars"
unlock_view: "base"
outline: "altline"
label: "äÄ"
period:
outline: "default"
label: "."
space:
outline: "spaceline"
label: " "
text: " "
Return:
outline: "altline"
icon: "key-enter"
colon:
label: ":"
"\"":
keysym: "quotedbl"
keysym: "Return"

View File

@ -0,0 +1,88 @@
# Maintained by: Mark Müller <markmueller86@gmail.com>
---
bounds: { x: 0, y: 1, width: 540, height: 168 }
outlines:
default:
bounds: { x: 0, y: 0, width: 48, height: 42 }
altline:
bounds: { x: 0, y: 0, width: 81, height: 42 }
wide:
bounds: { x: 0, y: 0, width: 108, height: 42 }
spaceline:
bounds: { x: 0, y: 0, width: 216, height: 42 }
special:
bounds: { x: 0, y: 0, width: 48, 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 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 space ! ? Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # % & - _ + ( ) ß"
- "show_symbols , \" ' : = < > BackSpace"
- "show_letters preferences space , . Return"
symbols:
- "~ ` ´ · © ® ÷ × ¶"
- "€ £ $ ¥ ^ ° * { } |"
- "show_numbers \\ / § π τ [ ] BackSpace"
- "show_letters preferences space , . Return"
eschars:
- "ä è é ö ü Ä È É Ö Ü"
- "à â ê î ô À Â È Î Ô"
- "show_numbers « » ç Ç æ œ ß 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"
keysym: "BackSpace"
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"
text: " "
Return:
outline: "altline"
icon: "key-enter"
keysym: "Return"

View File

@ -53,6 +53,7 @@ buttons:
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
keysym: "BackSpace"
preferences:
action: "show_prefs"
outline: "altline"
@ -86,111 +87,112 @@ buttons:
label: "αι"
period:
outline: "altline"
label: "."
text: "."
space:
outline: spaceline
label: " "
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
aring:
label: "å"
text: "å"
Aring:
label: "Å"
text: "Å"
oslash:
label: "ø"
text: "ø"
Oslash:
label: "Ø"
text: "Ø"
ae:
label: "æ"
text: "æ"
AE:
label: "Æ"
text: "Æ"
asterisk:
label: "*"
text: "*"
asciitilde:
label: "~"
text: "~"
quoteleft:
label: "`"
text: "`"
bar:
label: "|"
text: "|"
U00B7:
label: "·"
text: "·"
squareroot:
label: "√"
text: "√"
Greek_pi:
label: "π"
text: "π"
division:
label: "÷"
text: "÷"
multiply:
label: "×"
text: "×"
paragraph:
label: "¶"
text: "¶"
Greek_tau:
label: "τ"
text: "τ"
copyright:
label: "©"
text: "©"
numbersign:
label: "#"
text: "#"
U00AE:
label: "®"
text: "®"
at:
label: "@"
text: "@"
dollar:
label: "$"
text: "$"
U00A3:
label: "£"
text: "£"
percent:
label: "%"
text: "%"
EuroSign:
label: "€"
text: "€"
ampersand:
label: "&"
text: "&"
U00A5:
label: "¥"
text: "¥"
minus:
label: "-"
text: "-"
asciicircum:
label: "^"
text: "^"
underscore:
label: "_"
text: "_"
degree:
label: "°"
text: "°"
plus:
label: "+"
text: "+"
equal:
label: "="
text: "="
parenleft:
label: "("
text: "("
parenright:
label: ")"
text: ")"
braceleft:
label: "{"
text: "{"
braceright:
label: "}"
text: "}"
comma:
label: ","
text: ","
backslash:
label: "\\"
text: "\\"
slash:
label: "/"
text: "/"
quotedbl:
label: "\""
text: "\""
quoteright:
label: "'"
text: "'"
less:
label: "<"
text: "<"
greater:
label: ">"
text: ">"
colon:
label: ":"
text: ":"
semicolon:
label: ";"
text: ";"
exclam:
label: "!"
text: "!"
question:
label: "?"
text: "?"
bracketleft:
label: "["
text: "["
bracketright:
label: "]"
text: "]"

View File

@ -51,6 +51,7 @@ buttons:
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
keysym: "BackSpace"
preferences:
action: "show_prefs"
outline: "default"
@ -80,14 +81,14 @@ buttons:
period:
outline: "default"
label: "."
text: "."
space:
outline: "spaceline"
label: " "
text: " "
Return:
outline: "altline"
icon: "key-enter"
keysym: "Return"
colon:
label: ":"
"\"":
keysym: "quotedbl"
text: ":"

View File

@ -46,6 +46,7 @@ buttons:
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
keysym: "BackSpace"
preferences:
action: "show_prefs"
outline: "altline"
@ -69,108 +70,109 @@ buttons:
outline: altline
space:
outline: spaceline
label: " "
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
aring:
label: "å"
text: "å"
Aring:
label: "Å"
text: "Å"
ouml:
label: "ö"
text: "ö"
Ouml:
label: "Ö"
text: "Ö"
auml:
label: "ä"
text: "ä"
Auml:
label: "Ä"
text: "Ä"
asterisk:
label: "*"
text: "*"
asciitilde:
label: "~"
text: "~"
quoteleft:
label: "`"
text: "`"
bar:
label: "|"
text: "|"
U00B7:
label: "·"
text: "·"
squareroot:
label: "√"
text: "√"
Greek_pi:
label: "π"
text: "π"
division:
label: "÷"
text: "÷"
multiply:
label: "×"
text: "×"
paragraph:
label: "¶"
text: "¶"
Greek_tau:
label: "τ"
text: "τ"
copyright:
label: "©"
text: "©"
numbersign:
label: "#"
text: "#"
U00AE:
label: "®"
text: "®"
at:
label: "@"
text: "@"
dollar:
label: "$"
text: "$"
U00A3:
label: "£"
text: "£"
percent:
label: "%"
text: "%"
EuroSign:
label: "€"
text: "€"
ampersand:
label: "&"
text: "&"
U00A5:
label: "¥"
text: "¥"
minus:
label: "-"
text: "-"
asciicircum:
label: "^"
text: "^"
underscore:
label: "_"
text: "_"
degree:
label: "°"
text: "°"
plus:
label: "+"
text: "+"
equal:
label: "="
text: "="
parenleft:
label: "("
text: "("
parenright:
label: ")"
text: ")"
braceleft:
label: "{"
text: "{"
braceright:
label: "}"
text: "}"
comma:
label: ","
text: ","
backslash:
label: "\\"
text: "\\"
slash:
label: "/"
text: "/"
quotedbl:
label: "\""
text: "\""
quoteright:
label: "'"
text: "'"
less:
label: "<"
text: "<"
greater:
label: ">"
text: ">"
colon:
label: ":"
text: ":"
semicolon:
label: ";"
text: ";"
exclam:
label: "!"
text: "!"
question:
label: "?"
text: "?"
bracketleft:
label: "["
text: "["
bracketright:
label: "]"
text: "]"

View File

@ -53,6 +53,7 @@ buttons:
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
keysym: "BackSpace"
preferences:
action: "show_prefs"
outline: "default"
@ -91,6 +92,7 @@ buttons:
Return:
outline: "altline"
icon: "key-enter"
keysym: "Return"
colon:
label: ":"
"\"":

View File

@ -1,7 +1,6 @@
# Japanese Kana layout by Mark Müller
# Version 2019101900
# Maintained by: Mark Müller <markmueller86@gmail.com>
---
bounds: { x: 0, y: 1, width: 360, height: 210 }
bounds: { x: 0, y: 1, width: 360, height: 208 }
outlines:
default:
@ -199,29 +198,33 @@ views:
- "\\ ´ ` · ¶"
buttons:
# following 4 buttons are keysyms from libxkbcommon
# following 4 buttons use the corresponding xkb name as keysym
BackSpace:
outline: "wide"
icon: "edit-clear-symbolic"
keysym: "BackSpace"
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
Left:
outline: "wide"
label: "←"
keysym: "Left"
Right:
outline: "wide"
label: "→"
keysym: "Right"
# special button "preferences" is handled in the code
preferences:
action: "show_prefs"
outline: "special"
icon: "keyboard-mode-symbolic"
# space button (unicode)
# space button using text tag for ideographic space
space:
outline: "default-wide"
label: "␣"
keysym: "U3000"
text: " "
# switch to number view
numbers:
action:

View File

@ -0,0 +1,532 @@
# Maintained by: Mark Müller <markmueller86@gmail.com>
---
bounds: { x: 0, y: 1, width: 540, height: 168 }
outlines:
default:
bounds: { x: 0, y: 0, width: 62, height: 42 }
default-wide:
bounds: { x: 0, y: 0, width: 62, height: 42 }
altline:
bounds: { x: 0, y: 0, width: 62, height: 42 }
wide:
bounds: { x: 0, y: 0, width: 62, height: 42 }
special:
bounds: { x: 0, y: 0, width: 62, height: 42 }
views:
base: # hiragana
- "preferences _a ka sa BackSpace"
- "Left ta na ha Right"
- "カタカナ ma ya ra space"
- "switch2roman symbols wa punct Return"
_a:
- "preferences dummykey _a dummykey BackSpace"
- "あ い う え お"
- "ぁ ぃ ぅ ぇ ぉ" # 2 code points each
- "dummykey dummykey ゔ dummykey dummykey"
ka:
- "preferences dummykey ka dummykey BackSpace"
- "か き く け こ"
- "が ぎ ぐ げ ご"
- "ゕ dummykey dummykey ゖ dummykey"
sa:
- "preferences dummykey sa dummykey BackSpace"
- "さ し す せ そ"
- "ざ じ ず ぜ ぞ"
ta:
- "preferences dummykey ta dummykey BackSpace"
- "た ち つ て と"
- "だ ぢ づ で ど"
- "dummykey dummykey っ dummykey dummykey"
na:
- "preferences dummykey na dummykey BackSpace"
- "な に ぬ ね の"
ha:
- "preferences dummykey ha dummykey BackSpace"
- "は ひ ふ へ ほ"
- "ば び ぶ べ ぼ"
- "ぱ ぴ ぷ ぺ ぽ"
ma:
- "preferences dummykey ma dummykey BackSpace"
- "ま み む め も"
ya:
- "preferences dummykey ya dummykey BackSpace"
- "や dummykey ゆ dummykey よ"
- "ゃ dummykey ゅ dummykey ょ"
ra:
- "preferences dummykey ra dummykey BackSpace"
- "ら り る れ ろ"
wa:
- "preferences dummykey wa dummykey BackSpace"
- "わ ゐ dummykey ゑ を"
- "ゎ dummykey ん dummykey dummykey"
symbols:
- "preferences dummykey symbols dummykey BackSpace"
- "「 」 §"
- "【 】 "
- " "
punct:
- "preferences dummykey punct dummykey BackSpace"
- "。 、 ー"
- " ・ 〜 …"
- "♪ ” ゙ ゚"
#a あア かカ さサ たタ なナ はハ まマ やヤ らラ わワ
#i いイ きキ しシ ちチ にニ ひヒ みミ ※ りリ ゐヰ
#u うウ くク すス つツ ぬヌ ふフ むム ゆユ るル ※
#e えエ けケ せセ てテ ねネ へヘ めメ ※ れレ ゑヱ
#o おオ こコ そソ とト のノ ほホ もモ よヨ ろロ をヲ
# g z d b p n
#a が ガ ざ ザ だ ダ ば バ ぱ パ ん ン
#i ぎ ギ じ ジ ぢ ヂ び ビ ぴ ピ
#u ぐ グ ず ズ づ ヅ ぶ ブ ぷ プ
#e げ ゲ ぜ ゼ で デ べ ベ ぺ ペ
#o ご ゴ ぞ ゾ ど ド ぼ ボ ぽ ポ
カタカナ: # katakana
- "preferences _A KA SA BackSpace"
- "Left TA NA HA Right"
- "ひらがな MA YA RA space"
- "switch2roman SYMBOLS WA PUNCT Return"
_A:
- "preferences DUMMYKEY _A DUMMYKEY BackSpace"
- "ア イ ウ エ オ"
- "ァ ィ ゥ ェ ォ"
- "DUMMYKEY DUMMYKEY ヴ DUMMYKEY DUMMYKEY"
KA:
- "preferences DUMMYKEY KA DUMMYKEY BackSpace"
- "カ キ ク ケ コ"
- "ガ ギ グ ゲ ゴ"
- "ヵ DUMMYKEY ㇰ ヶ DUMMYKEY"
SA:
- "preferences DUMMYKEY SA DUMMYKEY BackSpace"
- "サ シ ス セ ソ"
- "ザ ジ ズ ゼ ゾ"
- "DUMMYKEY ㇱ ㇲ DUMMYKEY DUMMYKEY"
TA:
- "preferences DUMMYKEY TA DUMMYKEY BackSpace"
- "タ チ ツ テ ト"
- "ダ ヂ ヅ デ ド"
- "DUMMYKEY DUMMYKEY ッ DUMMYKEY ㇳ"
NA:
- "preferences DUMMYKEY NA DUMMYKEY BackSpace"
- "ナ ニ ヌ ネ "
- "DUMMYKEY DUMMYKEY ㇴ DUMMYKEY DUMMYKEY"
HA:
- "preferences DUMMYKEY HA DUMMYKEY BackSpace"
- "ハ ヒ フ ヘ ホ"
- "バ ビ ブ ベ ボ"
- "パ ピ プ ペ ポ"
MA:
- "preferences DUMMYKEY MA DUMMYKEY BackSpace"
- "マ ミ ム メ モ"
- "DUMMYKEY DUMMYKEY ㇺ DUMMYKEY DUMMYKEY"
YA:
- "preferences DUMMYKEY YA DUMMYKEY BackSpace"
- "ヤ DUMMYKEY ユ DUMMYKEY ヨ"
- "ャ DUMMYKEY ュ DUMMYKEY ョ"
RA:
- "preferences DUMMYKEY RA DUMMYKEY BackSpace"
- "ラ リ ル レ ロ"
- "ㇻ ㇼ ㇽ ㇾ ㇿ"
WA:
- "preferences DUMMYKEY WA DUMMYKEY BackSpace"
- "ワ ヰ DUMMYKEY ヱ ヲ"
- "ヮ ヸ ン ヹ ヺ"
# numbers view
numbers:
- "preferences 1 2 3 BackSpace"
- "Left 4 5 6 Right"
- "roman 7 8 9 space"
- "switch2kana * 0 # Return"
# Roman alphabet view
roman:
- "preferences RSYM1 ABC DEF BackSpace"
- "Left GHI JKL MNO Right"
- "ひらがな PQRS TUV WXYZ space"
- "switch2num RSYM2 RSYM3 RSYM4 Return"
RSYM1:
- "preferences dummykey RSYM1 dummykey BackSpace"
- "@ # $ § :"
- "| € ¥ £ 1"
ABC:
- "preferences dummykey ABC dummykey BackSpace"
- "A B C Ä ç"
- "a b c ä 2"
DEF:
- "preferences dummykey DEF dummykey BackSpace"
- "D E F dummykey"
- "d e f 3"
GHI:
- "preferences dummykey GHI dummykey BackSpace"
- "G H I dummykey"
- "g h i 4"
JKL:
- "preferences dummykey JKL dummykey BackSpace"
- "J K L dummykey"
- "j k l 5"
MNO:
- "preferences dummykey MNO dummykey BackSpace"
- "M N O Ö dummykey"
- "m n o ö 6"
PQRS:
- "preferences dummykey PQRS dummykey BackSpace"
- "P Q R S ß"
- "p q r s 7"
TUV:
- "preferences dummykey TUV dummykey BackSpace"
- "T U V Ü dummykey"
- "t u v ü 8"
WXYZ:
- "preferences dummykey WXYZ dummykey BackSpace"
- "W X Y Z dummykey"
- "w x y z 9"
RSYM2:
- "preferences dummykey RSYM2 dummykey BackSpace"
- "( ) ' \" ~"
- "[ ] { } _"
RSYM3:
- "preferences dummykey RSYM3 dummykey BackSpace"
- "+ - * / ="
- "< > ^ ° 0"
RSYM4:
- "preferences dummykey RSYM4 dummykey BackSpace"
- ", . ? ! ;"
- "\\ ´ ` · ¶"
buttons:
# following 4 buttons use the corresponding xkb name as keysym
BackSpace:
outline: "wide"
icon: "edit-clear-symbolic"
keysym: "BackSpace"
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
Left:
outline: "wide"
label: "←"
keysym: "Left"
Right:
outline: "wide"
label: "→"
keysym: "Right"
# special button "preferences" is handled in the code
preferences:
action: "show_prefs"
outline: "special"
icon: "keyboard-mode-symbolic"
# space button using text tag for ideographic space
space:
outline: "default-wide"
label: "␣"
text: " "
# switch to number view
numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
# switch to latin characters
roman:
action:
set_view: "roman"
outline: "wide"
label: "ᴀʙᴄ"
# toggle button with 3 different states
switch2roman: # switch from kana to latin characters view
action:
set_view: "roman"
outline: "wide"
label: "あᴀ₁"
switch2num: # switch from latin characters to numbers view
action:
set_view: "numbers"
outline: "wide"
label: "ぁA₁"
switch2kana: # switch from numbers to hiragana view
action:
set_view: "base"
outline: "wide"
label: "ぁᴀ1"
# Buttons for katakana and symbols
ひらがな:
action:
set_view: "base"
outline: "wide"
label: "あさ"
_a:
action:
locking:
lock_view: "_a"
unlock_view: "base"
outline: "altline"
label: "あ"
ka:
action:
locking:
lock_view: "ka"
unlock_view: "base"
outline: "altline"
label: "か"
sa:
action:
locking:
lock_view: "sa"
unlock_view: "base"
outline: "altline"
label: "さ"
ta:
action:
locking:
lock_view: "ta"
unlock_view: "base"
outline: "altline"
label: "た"
na:
action:
locking:
lock_view: "na"
unlock_view: "base"
outline: "altline"
label: "な"
ha:
action:
locking:
lock_view: "ha"
unlock_view: "base"
outline: "altline"
label: "は"
ma:
action:
locking:
lock_view: "ma"
unlock_view: "base"
outline: "altline"
label: "ま"
ya:
action:
locking:
lock_view: "ya"
unlock_view: "base"
outline: "altline"
label: "や"
ra:
action:
locking:
lock_view: "ra"
unlock_view: "base"
outline: "altline"
label: "ら"
wa:
action:
locking:
lock_view: "wa"
unlock_view: "base"
outline: "altline"
label: "わ"
dummykey:
action:
set_view: "base"
outline: "altline"
label: ""
# buttons available on different views like symbols and punct should go
# back to their corresponding view
symbols:
action:
locking:
lock_view: "symbols"
unlock_view: "base"
outline: "altline"
label: ""
punct:
action:
locking:
lock_view: "punct"
unlock_view: "base"
outline: "altline"
label: "。"
# Buttons for katakana and symbols
カタカナ:
action:
set_view: "カタカナ"
outline: "wide"
label: "アサ"
_A:
action:
locking:
lock_view: "_A"
unlock_view: "カタカナ"
outline: "altline"
label: "ア"
KA:
action:
locking:
lock_view: "KA"
unlock_view: "カタカナ"
outline: "altline"
label: "カ"
SA:
action:
locking:
lock_view: "SA"
unlock_view: "カタカナ"
outline: "altline"
label: "サ"
TA:
action:
locking:
lock_view: "TA"
unlock_view: "カタカナ"
outline: "altline"
label: "タ"
NA:
action:
locking:
lock_view: "NA"
unlock_view: "カタカナ"
outline: "altline"
label: "ナ"
HA:
action:
locking:
lock_view: "HA"
unlock_view: "カタカナ"
outline: "altline"
label: "ハ"
MA:
action:
locking:
lock_view: "MA"
unlock_view: "カタカナ"
outline: "altline"
label: "マ"
YA:
action:
locking:
lock_view: "YA"
unlock_view: "カタカナ"
outline: "altline"
label: "ヤ"
RA:
action:
locking:
lock_view: "RA"
unlock_view: "カタカナ"
outline: "altline"
label: "ラ"
WA:
action:
locking:
lock_view: "WA"
unlock_view: "カタカナ"
outline: "altline"
label: "ワ"
DUMMYKEY:
action:
set_view: "カタカナ"
outline: "altline"
label: ""
SYMBOLS:
action:
locking:
lock_view: "symbols"
unlock_view: "カタカナ"
outline: "altline"
label: ""
PUNCT:
action:
locking:
lock_view: "punct"
unlock_view: "カタカナ"
outline: "altline"
label: "。"
# Buttons for Latin charachters
RSYM1:
action:
locking:
lock_view: "RSYM1"
unlock_view: "roman"
outline: "altline"
label: "@#"
ABC:
action:
locking:
lock_view: "ABC"
unlock_view: "roman"
outline: "altline"
label: "ᴀʙᴄ"
DEF:
action:
locking:
lock_view: "DEF"
unlock_view: "roman"
outline: "altline"
label: "ᴅᴇꜰ"
GHI:
action:
locking:
lock_view: "GHI"
unlock_view: "roman"
outline: "altline"
label: "ɢʜɪ"
JKL:
action:
locking:
lock_view: "JKL"
unlock_view: "roman"
outline: "altline"
label: "ᴊᴋʟ"
MNO:
action:
locking:
lock_view: "MNO"
unlock_view: "roman"
outline: "altline"
label: "ᴍɴᴏ"
PQRS:
action:
locking:
lock_view: "PQRS"
unlock_view: "roman"
outline: "altline"
label: "ᴘǫʀs"
TUV:
action:
locking:
lock_view: "TUV"
unlock_view: "roman"
outline: "altline"
label: "ᴛᴜᴠ"
WXYZ:
action:
locking:
lock_view: "WXYZ"
unlock_view: "roman"
outline: "altline"
label: "xʏ"
RSYM2:
action:
locking:
lock_view: "RSYM2"
unlock_view: "roman"
outline: "altline"
label: "()"
RSYM3:
action:
locking:
lock_view: "RSYM3"
unlock_view: "roman"
outline: "altline"
label: "+-"
RSYM4:
action:
locking:
lock_view: "RSYM4"
unlock_view: "roman"
outline: "altline"
label: ",.?"

View File

@ -26,13 +26,13 @@ views:
- "show_numbers preferences space . Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "at numbersign dollar percent ampersand minus underscore plus parenleft parenright"
- "show_symbols comma quotedbl quoteright colon semicolon exclam question BackSpace"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' : ; ! ? BackSpace"
- "show_letters preferences space . Return"
symbols:
- "asciitilde quoteleft bar U00B7 squareroot Greek_pi Greek_tau division multiply paragraph"
- "copyright U00AE U00A3 EuroSign U00A5 asciicircum degree asterisk braceleft braceright"
- "show_numbers backslash slash less greater equal bracketleft bracketright BackSpace"
- "~ ` | U00B7 squareroot Greek_pi Greek_tau division multiply paragraph"
- "copyright U00AE U00A3 EuroSign U00A5 asciicircum degree * { }"
- "show_numbers \\ / < > = [ ] BackSpace"
- "show_letters preferences space . Return"
buttons:
@ -46,6 +46,7 @@ buttons:
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
keysym: "BackSpace"
preferences:
action: "show_prefs"
outline: "altline"
@ -69,108 +70,37 @@ buttons:
outline: altline
space:
outline: spaceline
label: " "
text: " "
Return:
outline: "wide"
icon: "key-enter"
aring:
label: "å"
Aring:
label: "Å"
oslash:
label: "ø"
Oslash:
label: "Ø"
ae:
label: "æ"
AE:
label: "Æ"
asterisk:
label: "*"
asciitilde:
label: "~"
quoteleft:
label: "`"
bar:
label: "|"
keysym: "Return"
U00B7:
label: "·"
text: "·"
squareroot:
label: "√"
text: "√"
Greek_pi:
label: "π"
text: "π"
division:
label: "÷"
text: "÷"
multiply:
label: "×"
text: "×"
paragraph:
label: "¶"
text: "¶"
Greek_tau:
label: "τ"
text: "τ"
copyright:
label: "©"
numbersign:
label: "#"
text: "©"
U00AE:
label: "®"
at:
label: "@"
dollar:
label: "$"
text: "®"
U00A3:
label: "£"
percent:
label: "%"
text: "£"
EuroSign:
label: "€"
ampersand:
label: "&"
text: "€"
U00A5:
label: "¥"
minus:
label: "-"
text: "¥"
asciicircum:
label: "^"
underscore:
label: "_"
text: "^"
degree:
label: "°"
plus:
label: "+"
equal:
label: "="
parenleft:
label: "("
parenright:
label: ")"
braceleft:
label: "{"
braceright:
label: "}"
comma:
label: ","
backslash:
label: "\\"
slash:
label: "/"
quotedbl:
label: "\""
quoteright:
label: "'"
less:
label: "<"
greater:
label: ">"
colon:
label: ":"
semicolon:
label: ";"
exclam:
label: "!"
question:
label: "?"
bracketleft:
label: "["
bracketright:
label: "]"
text: "°"

View File

@ -22,22 +22,24 @@ buttons:
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
keysym: "BackSpace"
space:
outline: spaceline
label: " "
text: " "
Return:
outline: outline7
icon: "key-enter"
keysym: "BackSpace"
asterisk:
label: "*"
text: "*"
numbersign:
label: "#"
text: "#"
minus:
label: "-"
text: "-"
plus:
label: "+"
text: "+"
parenleft:
label: "("
text: "("
parenright:
label: ")"
text: ")"

View File

@ -46,6 +46,7 @@ buttons:
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
keysym: "BackSpace"
preferences:
action: "show_prefs"
outline: "altline"
@ -69,96 +70,97 @@ buttons:
outline: altline
space:
outline: spaceline
label: " "
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
asterisk:
label: "*"
text: "*"
asciitilde:
label: "~"
text: "~"
quoteleft:
label: "`"
text: "`"
bar:
label: "|"
text: "|"
U00B7:
label: "·"
text: "·"
squareroot:
label: "√"
text: "√"
Greek_pi:
label: "π"
text: "π"
division:
label: "÷"
text: "÷"
multiply:
label: "×"
text: "×"
paragraph:
label: "¶"
text: "¶"
Greek_tau:
label: "τ"
text: "τ"
copyright:
label: "©"
text: "©"
numbersign:
label: "#"
text: "#"
U00AE:
label: "®"
text: "®"
at:
label: "@"
text: "@"
dollar:
label: "$"
text: "$"
U00A3:
label: "£"
text: "£"
percent:
label: "%"
text: "%"
EuroSign:
label: "€"
text: "€"
ampersand:
label: "&"
text: "&"
U00A5:
label: "¥"
text: "¥"
minus:
label: "-"
text: "-"
asciicircum:
label: "^"
text: "^"
underscore:
label: "_"
text: "_"
degree:
label: "°"
text: "°"
plus:
label: "+"
text: "+"
equal:
label: "="
text: "="
parenleft:
label: "("
text: "("
parenright:
label: ")"
text: ")"
braceleft:
label: "{"
text: "{"
braceright:
label: "}"
text: "}"
comma:
label: ","
text: ","
backslash:
label: "\\"
text: "\\"
slash:
label: "/"
text: "/"
quotedbl:
label: "\""
text: "\""
quoteright:
label: "'"
text: "'"
less:
label: "<"
text: "<"
greater:
label: ">"
text: ">"
colon:
label: ":"
text: ":"
semicolon:
label: ";"
text: ";"
exclam:
label: "!"
text: "!"
question:
label: "?"
text: "?"
bracketleft:
label: "["
text: "["
bracketright:
label: "]"
text: "]"

View File

@ -46,6 +46,7 @@ buttons:
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
keysym: "BackSpace"
preferences:
action: "show_prefs"
outline: "special"
@ -72,14 +73,13 @@ buttons:
label: "*/="
period:
outline: "special"
label: "."
text: "."
space:
outline: "spaceline"
label: " "
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
label: ":"
"\"":
keysym: "quotedbl"
text: ":"

View File

@ -18,22 +18,22 @@ views:
- "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 period Return"
- "show_numbers 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 preferences space period Return"
- "show_numbers preferences space . Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space period Return"
- "show_letters preferences space . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space period Return"
- "show_letters preferences space . Return"
buttons:
Shift_L:
@ -46,6 +46,7 @@ buttons:
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
keysym: "BackSpace"
preferences:
action: "show_prefs"
outline: "special"
@ -70,16 +71,15 @@ buttons:
set_view: "symbols"
outline: "altline"
label: "*/="
period:
".":
outline: "special"
label: "."
text: "."
space:
outline: "spaceline"
label: " "
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
label: ":"
"\"":
keysym: "quotedbl"
text: ":"

8
data/langs/de-DE.txt Normal file
View File

@ -0,0 +1,8 @@
us Englisch (US)
de Deutsch
el Griechisch
es Spanisch
it Italienisch
jp+kana Japanisch (Kana)
no Norwegisch

View File

@ -2,7 +2,9 @@ us English (US)
de German
el Greek
es Spanish
fi Finnish
it Italian
jp+kana Japanese (kana)
nb Norwegian
no Norwegian
se Swedish

7
data/langs/es-ES.txt Normal file
View File

@ -0,0 +1,7 @@
us Inglés (EE.UU.)
de Alemán
el Griego
es Español
it Italiano
jp+kana Japonés (Kana)
no Noruego

8
data/langs/ja-JP.txt Normal file
View File

@ -0,0 +1,8 @@
us 英語 (US)
de ドイツ語
el ギリシャ語
es スペイン語
it イタリア語
jp+kana 日本語 (かな)
nb ノルウェー語

View File

@ -2,7 +2,8 @@ us angielski (USA)
de niemiecki
el grecki
es hiszpański
fi fiński
it włoski
jp+kana japoński (kana)
nb norweski
no norweski
se szwedzki

View File

@ -2,6 +2,7 @@
<gresources>
<gresource prefix="/sm/puri/squeekboard">
<file compressed="true">style.css</file>
<file compressed="true">style-Adwaita:dark.css</file>
<file compressed="true" preprocess="xml-stripblanks">popup.ui</file>
<file>icons/key-enter.svg</file>
<file>icons/key-shift.svg</file>

View File

@ -0,0 +1,46 @@
sq_view {
background-color: rgba(0, 0, 0, 255);
color: #ffffff;
font-family: cantarell, sans-serif;
}
sq_view sq_button {
color: #deddda;
background: #464448;
border-style: solid;
border-width: 1px;
border-color: #5e5c64;
border-radius: 3px;
margin: 4px 2px 4px 2px;
}
sq_view.wide sq_button {
margin: 1px 1px 1px 1px;
}
sq_button:active {
background: #747077;
border-color: #96949d;
}
sq_button.altline,
sq_button.special,
sq_button.wide {
background: #2b292f;
border-color: #3e3a44;
}
sq_button.locked {
background: #ffffff;
color: #2b292f;
}
#Return {
background: #1c71d8;
border-color: #1a5fb4;
}
#Return:active {
background: #1c71d8;
border-color: #3584e4;
}

View File

@ -1,15 +1,15 @@
sq_view {
background-color: rgba(0, 0, 0, 255);
color: #ffffff;
background-color: @theme_base_color; /*rgba(0, 0, 0, 255);*/
color: @theme_text_color; /*#ffffff;*/
font-family: cantarell, sans-serif;
}
sq_view sq_button {
color: #deddda;
background: #464448;
color: @theme_fg_color; /*#deddda;*/
background: mix(@theme_bg_color, @theme_base_color, -0.5); /* #464448; */
border-style: solid;
border-width: 1px;
border-color: #5e5c64;
border-color: @borders; /* #5e5c64;*/
border-radius: 3px;
margin: 4px 2px 4px 2px;
}
@ -18,29 +18,32 @@ sq_view.wide sq_button {
margin: 1px 1px 1px 1px;
}
sq_button:active {
background: #747077;
border-color: #96949d;
sq_button:active,
sq_button.altline:active,
sq_button.special:active,
sq_button.wide:active {
background: mix(@theme_bg_color, @theme_selected_bg_color, 0.4);/* #747077; */
border-color: mix(@borders, @theme_selected_fg_color, 0.5);/* #96949d; */
}
sq_button.altline,
sq_button.special,
sq_button.wide {
background: #2b292f;
border-color: #3e3a44;
background: mix(@theme_bg_color, @theme_base_color, 0.5); /*#2b292f;*/
border-color: @borders; /* #3e3a44; */
}
sq_button.locked {
background: #ffffff;
color: #2b292f;
background: @theme_fg_color; /*#ffffff;*/
color: @theme_bg_color; /*#2b292f;*/
}
#Return {
background: #1c71d8;
border-color: #1a5fb4;
background: @theme_selected_bg_color; /* #1c71d8; */
border-color: @borders; /*#1a5fb4;*/
}
#Return:active {
background: #1c71d8;
border-color: #3584e4;
background: mix(@theme_selected_bg_color, @theme_bg_color, 0.4); /*#1c71d8;*/
border-color: @borders; /*#3584e4;*/
}

39
dco.txt Normal file
View File

@ -0,0 +1,39 @@
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.

20
debian/changelog vendored
View File

@ -1,3 +1,23 @@
squeekboard (1.4.0) amber-phone; urgency=medium
* "text" property in layouts
* Adjusts to user's color scheme
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Mon, 02 Dec 2019 19:37:01 +0000
squeekboard (1.3.2) amber-phone; urgency=medium
* Make sure all key presses get accepted by the compositor
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Tue, 26 Nov 2019 15:36:27 +0000
squeekboard (1.3.1) amber-phone; urgency=medium
* Update and fix layouts and languages
* Make tests less likely to fail
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Wed, 20 Nov 2019 22:10:48 +0000
squeekboard (1.3.0) amber-phone; urgency=medium
* Language selection popup

11
debian/control vendored
View File

@ -12,6 +12,7 @@ Build-Depends:
libgtk-3-dev,
libcroco3-dev,
librust-bitflags-1-dev (>= 1.0),
librust-clap-2+default-dev (>= 2.32),
librust-gio+v2-44-dev,
librust-glib+v2-44-dev,
librust-glib-sys-dev,
@ -40,3 +41,13 @@ Depends:
${misc:Depends}
Description: On-screen keyboard for Wayland
Virtual keyboard supporting Wayland, built primarily for the Librem 5 phone.
Package: squeekboard-devel
Architecture: linux-any
Depends:
${shlibs:Depends}
${misc:Depends}
Description: Resources for making Squeekboard layouts
Tools for creating Squeekboard layouts:
.
* squeekboard-test-layout

1
debian/squeekboard-devel.install vendored Normal file
View File

@ -0,0 +1 @@
usr/bin/squeekboard-test-layout /usr/bin

2
debian/squeekboard.install vendored Normal file
View File

@ -0,0 +1,2 @@
tools/squeekboard-restyled usr/bin
usr/bin/squeekboard /usr/bin

View File

@ -1,2 +1,2 @@
# yaml-rust 0.4.3 shares some roots with libyaml, including the string which lintian checks, creating a false positive
squeekboard binary: embedded-library usr/bin/squeekboard-real: libyaml
squeekboard binary: embedded-library usr/bin/squeekboard: libyaml

View File

@ -61,10 +61,6 @@ typedef struct _EekGtkKeyboardPrivate
G_DEFINE_TYPE_WITH_PRIVATE (EekGtkKeyboard, eek_gtk_keyboard, GTK_TYPE_DRAWING_AREA)
static void render_pressed_button (GtkWidget *widget, struct button_place *place);
static void render_released_button (GtkWidget *widget,
const struct squeek_button *button);
static void
eek_gtk_keyboard_real_realize (GtkWidget *self)
{
@ -85,7 +81,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
cairo_t *cr)
{
EekGtkKeyboardPrivate *priv =
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
GtkAllocation allocation;
gtk_widget_get_allocation (self, &allocation);
@ -101,10 +97,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
gtk_widget_get_scale_factor (self));
}
// render the keyboard without any key activity (TODO: from a cached buffer)
eek_renderer_render_keyboard (priv->renderer, cr);
// render only a few remaining changes
squeek_layout_draw_all_changed(priv->keyboard->layout, EEK_GTK_KEYBOARD(self));
return FALSE;
}
@ -113,7 +106,7 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
GtkAllocation *allocation)
{
EekGtkKeyboardPrivate *priv =
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
if (priv->renderer)
eek_renderer_set_allocation_size (priv->renderer,
@ -170,6 +163,18 @@ eek_gtk_keyboard_real_button_release_event (GtkWidget *self,
return TRUE;
}
static gboolean
eek_gtk_keyboard_leave_event (GtkWidget *self,
GdkEventCrossing *event)
{
if (event->type == GDK_LEAVE_NOTIFY) {
// TODO: can the event have different coords than the previous move event?
release(EEK_GTK_KEYBOARD(self), event->time);
}
return TRUE;
}
static gboolean
eek_gtk_keyboard_real_motion_notify_event (GtkWidget *self,
GdkEventMotion *event)
@ -217,7 +222,7 @@ static void
eek_gtk_keyboard_real_unmap (GtkWidget *self)
{
EekGtkKeyboardPrivate *priv =
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
if (priv->keyboard) {
squeek_layout_release_all_only(
@ -234,6 +239,7 @@ eek_gtk_keyboard_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
(void)value;
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -279,6 +285,9 @@ eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass)
eek_gtk_keyboard_real_button_release_event;
widget_class->motion_notify_event =
eek_gtk_keyboard_real_motion_notify_event;
widget_class->leave_notify_event =
eek_gtk_keyboard_leave_event;
widget_class->touch_event = handle_touch_event;
gobject_class->set_property = eek_gtk_keyboard_set_property;
@ -287,7 +296,9 @@ eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass)
static void
eek_gtk_keyboard_init (EekGtkKeyboard *self)
{}
{
(void)self;
}
/**
* eek_gtk_keyboard_new:
@ -305,110 +316,7 @@ eek_gtk_keyboard_new (LevelKeyboard *keyboard)
return GTK_WIDGET(ret);
}
static void
render_pressed_button (GtkWidget *widget,
struct button_place *place)
{
EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget);
EekRenderer *eek_gtk_keyboard_get_renderer(EekGtkKeyboard *self) {
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
GdkWindow *window = gtk_widget_get_window (widget);
cairo_region_t *region = gdk_window_get_clip_region (window);
GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region);
cairo_t *cr = gdk_drawing_context_get_cairo_context (context);
eek_renderer_render_button (priv->renderer, cr, place, 1.0, TRUE);
/*
eek_renderer_render_key (priv->renderer, cr, key, 1.5, TRUE);
*/
gdk_window_end_draw_frame (window, context);
cairo_region_destroy (region);
}
void
eek_gtk_render_locked_button (EekGtkKeyboard *self, struct button_place place)
{
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
GdkWindow *window = gtk_widget_get_window (GTK_WIDGET(self));
cairo_region_t *region = gdk_window_get_clip_region (window);
GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region);
cairo_t *cr = gdk_drawing_context_get_cairo_context (context);
eek_renderer_render_button (priv->renderer, cr, &place, 1.0, TRUE);
gdk_window_end_draw_frame (window, context);
cairo_region_destroy (region);
}
// TODO: does it really redraw the entire keyboard?
static void
render_released_button (GtkWidget *widget,
const struct squeek_button *button)
{
(void)button;
EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget);
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
GdkWindow *window = gtk_widget_get_window (widget);
cairo_region_t *region = gdk_window_get_clip_region (window);
GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region);
cairo_t *cr = gdk_drawing_context_get_cairo_context (context);
eek_renderer_render_keyboard (priv->renderer, cr);
gdk_window_end_draw_frame (window, context);
cairo_region_destroy (region);
}
void
eek_gtk_on_button_pressed (struct button_place place,
EekGtkKeyboard *self)
{
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
/* renderer may have not been set yet if the widget is a popup */
if (!priv->renderer)
return;
if (!place.row) {
return;
}
render_pressed_button (GTK_WIDGET(self), &place);
gtk_widget_queue_draw (GTK_WIDGET(self));
#if HAVE_LIBCANBERRA
ca_gtk_play_for_widget (widget, 0,
CA_PROP_EVENT_ID, "button-pressed",
CA_PROP_EVENT_DESCRIPTION, "virtual key pressed",
CA_PROP_APPLICATION_ID, "org.fedorahosted.Eekboard",
NULL);
#endif
}
void
eek_gtk_on_button_released (const struct squeek_button *button,
struct squeek_view *view,
EekGtkKeyboard *self)
{
(void)view;
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
/* renderer may have not been set yet if the widget is a popup */
if (!priv->renderer)
return;
render_released_button (GTK_WIDGET(self), button);
gtk_widget_queue_draw (GTK_WIDGET(self));
#if HAVE_LIBCANBERRA
ca_gtk_play_for_widget (widget, 0,
CA_PROP_EVENT_ID, "button-released",
CA_PROP_EVENT_DESCRIPTION, "virtual key pressed",
CA_PROP_APPLICATION_ID, "org.fedorahosted.Eekboard",
NULL);
#endif
return priv->renderer;
}

View File

@ -34,8 +34,6 @@
#include "eekboard/eekboard-context-service.h"
#include "eekboard/key-emitter.h"
#include "keymap.h"
#include "src/keyboard.h"
#include "eek-keyboard.h"
void level_keyboard_deinit(LevelKeyboard *self) {
@ -59,8 +57,3 @@ LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek
keyboard->manager = manager;
return keyboard;
}
struct squeek_view *level_keyboard_current(LevelKeyboard *keyboard)
{
return squeek_layout_get_current_view(keyboard->layout);
}

View File

@ -49,7 +49,6 @@ typedef struct _LevelKeyboard LevelKeyboard;
gchar * eek_keyboard_get_keymap
(LevelKeyboard *keyboard);
struct squeek_view *level_keyboard_current(LevelKeyboard *keyboard);
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_layout *layout);
void level_keyboard_deinit(LevelKeyboard *self);
void level_keyboard_free(LevelKeyboard *self);

View File

@ -26,6 +26,7 @@
#include "eek-keyboard.h"
#include "eek-renderer.h"
#include "src/style.h"
enum {
PROP_0,
@ -41,131 +42,27 @@ typedef struct _EekRendererPrivate
GtkStyleContext *view_context; // owned
GtkStyleContext *button_context; // TODO: maybe move a copy to each button
gdouble border_width;
gdouble border_width; // FIXME: border of what?
gdouble allocation_width;
gdouble allocation_height;
gdouble scale;
gint scale_factor; /* the outputs scale factor */
gint origin_x;
gint origin_y;
struct transformation widget_to_layout;
PangoFontDescription *ascii_font;
PangoFontDescription *font;
cairo_surface_t *keyboard_surface;
PangoFontDescription *font; // owned reference
} EekRendererPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (EekRenderer, eek_renderer, G_TYPE_OBJECT)
/* eek-keyboard-drawing.c */
static void eek_renderer_real_render_button_label (EekRenderer *self,
PangoLayout *layout,
static void eek_renderer_render_button_label (EekRenderer *self, cairo_t *cr, GtkStyleContext *ctx,
const struct squeek_button *button);
static void invalidate (EekRenderer *renderer);
static void render_button (EekRenderer *self,
cairo_t *cr, EekBounds view_bounds, struct button_place *place,
void eek_render_button (EekRenderer *self,
cairo_t *cr, const struct squeek_button *button,
gboolean pressed, gboolean locked);
struct _CreateKeyboardSurfaceCallbackData {
cairo_t *cr;
EekRenderer *renderer;
struct squeek_view *view;
struct squeek_row *row;
};
typedef struct _CreateKeyboardSurfaceCallbackData CreateKeyboardSurfaceCallbackData;
static void
create_keyboard_surface_button_callback (struct squeek_button *button,
gpointer user_data)
{
CreateKeyboardSurfaceCallbackData *data = user_data;
EekBounds bounds = squeek_button_get_bounds(button);
cairo_save (data->cr);
cairo_translate (data->cr, bounds.x, bounds.y);
cairo_rectangle (data->cr,
0.0,
0.0,
bounds.width + 100,
bounds.height + 100);
cairo_clip (data->cr);
struct button_place place = {
.row = data->row,
.button = button,
};
render_button (data->renderer, data->cr, squeek_view_get_bounds(data->view), &place, FALSE, FALSE);
cairo_restore (data->cr);
}
static void
create_keyboard_surface_row_callback (struct squeek_row *row,
gpointer user_data)
{
CreateKeyboardSurfaceCallbackData *data = user_data;
EekBounds bounds = squeek_row_get_bounds(row);
cairo_save (data->cr);
cairo_translate (data->cr, bounds.x, bounds.y);
gint angle = squeek_row_get_angle (row);
cairo_rotate (data->cr, angle * G_PI / 180);
data->row = row;
squeek_row_foreach(row, create_keyboard_surface_button_callback, data);
cairo_restore (data->cr);
}
static void
render_keyboard_surface (EekRenderer *renderer, struct squeek_view *view)
{
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
EekColor foreground;
eek_renderer_get_foreground_color (priv->view_context, &foreground);
EekBounds bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard));
CreateKeyboardSurfaceCallbackData data = {
.cr = cairo_create (priv->keyboard_surface),
.renderer = renderer,
.view = view,
};
/* Paint the background covering the entire widget area */
gtk_render_background (priv->view_context,
data.cr,
0, 0,
priv->allocation_width, priv->allocation_height);
gtk_render_frame (priv->view_context,
data.cr,
0, 0,
priv->allocation_width, priv->allocation_height);
cairo_save (data.cr);
cairo_scale (data.cr, priv->scale, priv->scale);
cairo_translate (data.cr, bounds.x, bounds.y);
cairo_set_source_rgba (data.cr,
foreground.red,
foreground.green,
foreground.blue,
foreground.alpha);
/* draw rows */
squeek_view_foreach(level_keyboard_current(priv->keyboard),
create_keyboard_surface_row_callback,
&data);
cairo_restore (data.cr);
cairo_destroy (data.cr);
}
static void
render_outline (cairo_t *cr,
GtkStyleContext *ctx,
@ -190,50 +87,20 @@ render_outline (cairo_t *cr,
}
static void render_button_in_context(EekRenderer *self,
gdouble scale,
gint scale_factor,
cairo_t *cr,
GtkStyleContext *ctx,
EekBounds view_bounds,
struct button_place *place,
gboolean active) {
cairo_surface_t *outline_surface = NULL;
PangoLayout *layout;
PangoRectangle extents = { 0, };
EekColor foreground;
/* render outline */
EekBounds bounds = squeek_button_get_bounds(place->button);
{
cairo_t *cr;
// Outline will be drawn on the outside of the button, so the
// surface needs to be bigger than the button
outline_surface =
cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
(int)ceil(bounds.width) + 10,
(int)ceil(bounds.height) + 10);
cr = cairo_create (outline_surface);
/* blank background */
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
cairo_paint (cr);
cairo_save (cr);
eek_renderer_apply_transformation_for_button (cr, view_bounds, place, 1.0, FALSE);
render_outline (cr, ctx, bounds);
cairo_restore (cr);
cairo_destroy (cr);
}
cairo_set_source_surface (cr, outline_surface, 0.0, 0.0);
cairo_surface_destroy(outline_surface);
const struct squeek_button *button) {
/* blank background */
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
cairo_paint (cr);
EekBounds bounds = squeek_button_get_bounds(button);
render_outline (cr, ctx, bounds);
cairo_paint (cr);
eek_renderer_get_foreground_color (ctx, &foreground);
/* render icon (if any) */
const char *icon_name = squeek_button_get_icon_name(place->button);
const char *icon_name = squeek_button_get_icon_name(button);
if (icon_name) {
cairo_surface_t *icon_surface =
@ -249,10 +116,13 @@ static void render_button_in_context(EekRenderer *self,
cairo_rectangle (cr, 0, 0, width, height);
cairo_clip (cr);
/* Draw the shape of the icon using the foreground color */
cairo_set_source_rgba (cr, foreground.red,
foreground.green,
foreground.blue,
foreground.alpha);
GdkRGBA color = {0};
gtk_style_context_get_color (ctx, GTK_STATE_FLAG_NORMAL, &color);
cairo_set_source_rgba (cr, color.red,
color.green,
color.blue,
color.alpha);
cairo_mask_surface (cr, icon_surface, 0.0, 0.0);
cairo_surface_destroy(icon_surface);
cairo_fill (cr);
@ -260,32 +130,13 @@ static void render_button_in_context(EekRenderer *self,
return;
}
}
/* render label */
layout = pango_cairo_create_layout (cr);
eek_renderer_real_render_button_label (self, layout, place->button);
pango_layout_get_extents (layout, NULL, &extents);
cairo_save (cr);
cairo_move_to
(cr,
(bounds.width - (double)extents.width / PANGO_SCALE) / 2,
(bounds.height - (double)extents.height / PANGO_SCALE) / 2);
cairo_set_source_rgba (cr,
foreground.red,
foreground.green,
foreground.blue,
foreground.alpha);
pango_cairo_show_layout (cr, layout);
cairo_restore (cr);
g_object_unref (layout);
eek_renderer_render_button_label (self, cr, ctx, button);
}
static void
render_button (EekRenderer *self,
void
eek_render_button (EekRenderer *self,
cairo_t *cr,
EekBounds view_bounds,
struct button_place *place,
const struct squeek_button *button,
gboolean pressed,
gboolean locked)
{
@ -296,7 +147,7 @@ render_button (EekRenderer *self,
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(place->button);
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. */
@ -305,13 +156,13 @@ 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(place->button);
const char *outline_name = squeek_button_get_outline_name(button);
if (locked) {
gtk_style_context_add_class(ctx, "locked");
}
gtk_style_context_add_class(ctx, outline_name);
render_button_in_context(self, priv->scale, priv->scale_factor, cr, ctx, view_bounds, place, pressed);
render_button_in_context(self, priv->scale_factor, cr, ctx, button);
// Save and restore functions don't work if gtk_render_* was used in between
gtk_style_context_set_state(ctx, GTK_STATE_FLAG_NORMAL);
@ -321,51 +172,11 @@ render_button (EekRenderer *self,
}
}
/**
* eek_renderer_apply_transformation_for_key:
* @self: The renderer used to render the key
* @cr: The Cairo rendering context used for rendering
* @key: The key to be transformed
* @scale: The factor used to scale the key bounds before rendering
* @rotate: Whether to rotate the key by the angle defined for the key's
* in its section definition
*
* Applies a transformation, consisting of scaling and rotation, to the
* current rendering context using the bounds for the given key. The scale
* factor is separate to the normal scale factor for the keyboard as a whole
* and is applied cumulatively. It is typically used to render larger than
* normal keys for popups.
*/
void
eek_renderer_apply_transformation_for_button (cairo_t *cr,
EekBounds view_bounds,
struct button_place *place,
gdouble scale,
gboolean rotate)
{
EekBounds bounds, rotated_bounds;
gdouble s;
eek_renderer_get_button_bounds (view_bounds, place, &bounds, FALSE);
eek_renderer_get_button_bounds (view_bounds, place, &rotated_bounds, TRUE);
gint angle = squeek_row_get_angle (place->row);
cairo_scale (cr, scale, scale);
if (rotate) {
s = sin (angle * G_PI / 180);
if (s < 0)
cairo_translate (cr, 0, - bounds.width * s);
else
cairo_translate (cr, bounds.height * s, 0);
cairo_rotate (cr, angle * G_PI / 180);
}
}
static void
eek_renderer_real_render_button_label (EekRenderer *self,
PangoLayout *layout,
const struct squeek_button *button)
eek_renderer_render_button_label (EekRenderer *self,
cairo_t *cr,
GtkStyleContext *ctx,
const struct squeek_button *button)
{
EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
@ -381,16 +192,11 @@ eek_renderer_real_render_button_label (EekRenderer *self,
if (!priv->font) {
const PangoFontDescription *base_font;
gdouble ascii_size, size;
gdouble size;
base_font = pango_context_get_font_description (priv->pcontext);
// FIXME: Base font size on the same size unit used for button sizing,
// and make the default about 1/3 of the current row height
ascii_size = 30000.0;
priv->ascii_font = pango_font_description_copy (base_font);
pango_font_description_set_size (priv->ascii_font,
(gint)round(ascii_size));
size = 30000.0;
priv->font = pango_font_description_copy (base_font);
pango_font_description_set_size (priv->font, (gint)round(size * 0.6));
@ -403,6 +209,8 @@ eek_renderer_real_render_button_label (EekRenderer *self,
font = pango_font_description_copy (priv->font);
pango_font_description_set_size (font,
(gint)round(pango_font_description_get_size (font) * scale));
PangoLayout *layout = pango_cairo_create_layout (cr);
pango_layout_set_font_description (layout, font);
pango_font_description_free (font);
@ -413,78 +221,51 @@ eek_renderer_real_render_button_label (EekRenderer *self,
}
pango_layout_set_width (layout,
PANGO_SCALE * bounds.width * scale);
}
/*
* eek_renderer_real_render_key:
* @self: The renderer used to render the key
* @cr: The Cairo rendering context used for rendering
* @key: The key to be transformed
* @scale: The factor used to scale the key bounds before rendering
* @rotate: Whether to rotate the key by the angle defined for the key's
* in its section definition
*
* Renders a key separately from the normal keyboard rendering.
*/
static void
eek_renderer_real_render_button (EekRenderer *self,
cairo_t *cr,
struct button_place *place,
gdouble scale,
gboolean rotate)
{
EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
EekBounds bounds;
EekBounds view_bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard));
eek_renderer_get_button_bounds (view_bounds, place, &bounds, rotate);
PangoRectangle extents = { 0, };
pango_layout_get_extents (layout, NULL, &extents);
cairo_save (cr);
/* Because this function is called separately from the keyboard rendering
function, the transformation for the context needs to be set up */
cairo_translate (cr, priv->origin_x, priv->origin_y);
cairo_scale (cr, priv->scale, priv->scale);
cairo_translate (cr, bounds.x, bounds.y);
cairo_move_to
(cr,
(bounds.width - (double)extents.width / PANGO_SCALE) / 2,
(bounds.height - (double)extents.height / PANGO_SCALE) / 2);
eek_renderer_apply_transformation_for_button (cr, view_bounds, place, scale, rotate);
struct squeek_key *key = squeek_button_get_key(place->button);
render_button (
self, cr, view_bounds, place,
squeek_key_is_pressed(key) != 0,
squeek_key_is_locked (key) != 0
);
GdkRGBA color = {0};
gtk_style_context_get_color (ctx, GTK_STATE_FLAG_NORMAL, &color);
cairo_set_source_rgba (cr,
color.red,
color.green,
color.blue,
color.alpha);
pango_cairo_show_layout (cr, layout);
cairo_restore (cr);
g_object_unref (layout);
}
static void
eek_renderer_real_render_keyboard (EekRenderer *self,
void
eek_renderer_render_keyboard (EekRenderer *self,
cairo_t *cr)
{
EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
cairo_pattern_t *source;
g_return_if_fail (priv->keyboard);
g_return_if_fail (priv->allocation_width > 0.0);
g_return_if_fail (priv->allocation_height > 0.0);
cairo_save (cr);
/* Paint the background covering the entire widget area */
gtk_render_background (priv->view_context,
cr,
0, 0,
priv->allocation_width, priv->allocation_height);
cairo_translate (cr, priv->origin_x, priv->origin_y);
if (priv->keyboard_surface)
cairo_surface_destroy (priv->keyboard_surface);
priv->keyboard_surface = cairo_surface_create_for_rectangle (
cairo_get_target (cr), 0, 0,
priv->allocation_width, priv->allocation_height);
render_keyboard_surface (self, squeek_layout_get_current_view(priv->keyboard->layout));
cairo_set_source_surface (cr, priv->keyboard_surface, 0.0, 0.0);
source = cairo_get_source (cr);
cairo_pattern_set_extend (source, CAIRO_EXTEND_PAD);
cairo_paint (cr);
cairo_save(cr);
cairo_translate (cr, priv->widget_to_layout.origin_x, priv->widget_to_layout.origin_y);
cairo_scale (cr, priv->widget_to_layout.scale, priv->widget_to_layout.scale);
squeek_draw_layout_base_view(priv->keyboard->layout, self, cr);
squeek_layout_draw_all_changed(priv->keyboard->layout, self, cr);
cairo_restore (cr);
}
@ -514,6 +295,7 @@ eek_renderer_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
(void)value;
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -535,8 +317,7 @@ eek_renderer_dispose (GObject *object)
priv->pcontext = NULL;
}
/* this will release all allocated surfaces and font if any */
invalidate (EEK_RENDERER(object));
// this is where renderer-specific surfaces would be released
G_OBJECT_CLASS (eek_renderer_parent_class)->dispose (object);
}
@ -550,7 +331,6 @@ eek_renderer_finalize (GObject *object)
g_object_unref(priv->css_provider);
g_object_unref(priv->view_context);
g_object_unref(priv->button_context);
pango_font_description_free (priv->ascii_font);
pango_font_description_free (priv->font);
G_OBJECT_CLASS (eek_renderer_parent_class)->finalize (object);
}
@ -561,9 +341,6 @@ eek_renderer_class_init (EekRendererClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
klass->render_button = eek_renderer_real_render_button;
klass->render_keyboard = eek_renderer_real_render_keyboard;
gobject_class->set_property = eek_renderer_set_property;
gobject_class->get_property = eek_renderer_get_property;
gobject_class->dispose = eek_renderer_dispose;
@ -616,30 +393,14 @@ eek_renderer_init (EekRenderer *self)
priv->border_width = 1.0;
priv->allocation_width = 0.0;
priv->allocation_height = 0.0;
priv->scale = 1.0;
priv->scale_factor = 1;
priv->font = NULL;
priv->keyboard_surface = NULL;
GtkIconTheme *theme = gtk_icon_theme_get_default ();
gtk_icon_theme_add_resource_path (theme, "/sm/puri/squeekboard/icons");
/* Create a default CSS provider and load a style sheet */
priv->css_provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (priv->css_provider,
"/sm/puri/squeekboard/style.css");
}
static void
invalidate (EekRenderer *renderer)
{
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
if (priv->keyboard_surface) {
cairo_surface_destroy (priv->keyboard_surface);
priv->keyboard_surface = NULL;
}
priv->css_provider = squeek_load_style();
}
EekRenderer *
@ -689,8 +450,6 @@ eek_renderer_set_allocation_size (EekRenderer *renderer,
gdouble width,
gdouble height)
{
gdouble scale;
g_return_if_fail (EEK_IS_RENDERER(renderer));
g_return_if_fail (width > 0.0 && height > 0.0);
@ -699,99 +458,11 @@ eek_renderer_set_allocation_size (EekRenderer *renderer,
priv->allocation_width = width;
priv->allocation_height = height;
/* Calculate a scale factor to use when rendering the keyboard into the
available space. */
EekBounds bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard));
priv->widget_to_layout = squeek_layout_calculate_transformation(
priv->keyboard->layout,
priv->allocation_width, priv->allocation_height);
gdouble w = (bounds.x * 2) + bounds.width;
gdouble h = (bounds.y * 2) + bounds.height;
scale = MIN(width / w, height / h);
priv->scale = scale;
/* Set the rendering offset in widget coordinates to center the keyboard */
priv->origin_x = (gint)floor((width - (scale * w)) / 2);
priv->origin_y = (gint)floor((height - (scale * h)) / 2);
invalidate (renderer);
}
void
eek_renderer_get_size (EekRenderer *renderer,
gdouble *width,
gdouble *height)
{
g_return_if_fail (EEK_IS_RENDERER(renderer));
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
EekBounds bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard));
if (width)
*width = bounds.width;
if (height)
*height = bounds.height;
}
void
eek_renderer_get_button_bounds (EekBounds view_bounds,
struct button_place *place,
EekBounds *bounds,
gboolean rotate)
{
gint angle = 0;
EekPoint points[4], min, max;
g_return_if_fail (place);
g_return_if_fail (bounds != NULL);
EekBounds button_bounds = squeek_button_get_bounds(place->button);
EekBounds row_bounds = squeek_row_get_bounds (place->row);
if (!rotate) {
button_bounds.x += view_bounds.x + row_bounds.x;
button_bounds.y += view_bounds.y + row_bounds.y;
*bounds = button_bounds;
return;
}
points[0].x = button_bounds.x;
points[0].y = button_bounds.y;
points[1].x = points[0].x + button_bounds.width;
points[1].y = points[0].y;
points[2].x = points[1].x;
points[2].y = points[1].y + button_bounds.height;
points[3].x = points[0].x;
points[3].y = points[2].y;
if (rotate) {
angle = squeek_row_get_angle (place->row);
}
min = points[2];
max = points[0];
for (unsigned i = 0; i < G_N_ELEMENTS(points); i++) {
eek_point_rotate (&points[i], angle);
if (points[i].x < min.x)
min.x = points[i].x;
if (points[i].x > max.x)
max.x = points[i].x;
if (points[i].y < min.y)
min.y = points[i].y;
if (points[i].y > max.y)
max.y = points[i].y;
}
bounds->x = view_bounds.x + row_bounds.x + min.x;
bounds->y = view_bounds.y + row_bounds.y + min.y;
bounds->width = (max.x - min.x);
bounds->height = (max.y - min.y);
}
gdouble
eek_renderer_get_scale (EekRenderer *renderer)
{
g_return_val_if_fail (EEK_IS_RENDERER(renderer), 0);
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
return priv->scale;
// This is where size-dependent surfaces would be released
}
void
@ -827,102 +498,11 @@ eek_renderer_get_icon_surface (const gchar *icon_name,
return surface;
}
void
eek_renderer_render_button (EekRenderer *renderer,
cairo_t *cr,
struct button_place *place,
gdouble scale,
gboolean rotate)
{
g_return_if_fail (EEK_IS_RENDERER(renderer));
g_return_if_fail (place);
g_return_if_fail (scale >= 0.0);
EEK_RENDERER_GET_CLASS(renderer)->
render_button (renderer, cr, place, scale, rotate);
}
void
eek_renderer_render_keyboard (EekRenderer *renderer,
cairo_t *cr)
{
g_return_if_fail (EEK_IS_RENDERER(renderer));
EEK_RENDERER_GET_CLASS(renderer)->render_keyboard (renderer, cr);
}
void
eek_renderer_get_foreground_color (GtkStyleContext *context,
EekColor *color)
{
g_return_if_fail (color);
GtkStateFlags flags = GTK_STATE_FLAG_NORMAL;
GdkRGBA gcolor;
gtk_style_context_get_color (context, flags, &gcolor);
color->red = gcolor.red;
color->green = gcolor.green;
color->blue = gcolor.blue;
color->alpha = gcolor.alpha;
}
static gboolean
sign (EekPoint *p1, EekPoint *p2, EekPoint *p3)
{
// FIXME: what is this actually checking?
return (p1->x - p3->x) * (p2->y - p3->y) -
(p2->x - p3->x) * (p1->y - p3->y);
}
uint32_t
eek_are_bounds_inside (EekBounds bounds, EekPoint point, EekPoint origin, int32_t angle)
{
EekPoint points[4];
gboolean b1, b2, b3;
points[0].x = bounds.x;
points[0].y = bounds.y;
points[1].x = points[0].x + bounds.width;
points[1].y = points[0].y;
points[2].x = points[1].x;
points[2].y = points[1].y + bounds.height;
points[3].x = points[0].x;
points[3].y = points[2].y;
for (unsigned i = 0; i < G_N_ELEMENTS(points); i++) {
eek_point_rotate (&points[i], angle);
points[i].x += origin.x;
points[i].y += origin.y;
}
b1 = sign (&point, &points[0], &points[1]) < 0.0;
b2 = sign (&point, &points[1], &points[2]) < 0.0;
b3 = sign (&point, &points[2], &points[0]) < 0.0;
if (b1 == b2 && b2 == b3) {
return 1;
}
b1 = sign (&point, &points[2], &points[3]) < 0.0;
b2 = sign (&point, &points[3], &points[0]) < 0.0;
b3 = sign (&point, &points[0], &points[2]) < 0.0;
if (b1 == b2 && b2 == b3) {
return 1;
}
return 0;
}
struct transformation
eek_renderer_get_transformation (EekRenderer *renderer) {
struct transformation failed = {0};
g_return_val_if_fail (EEK_IS_RENDERER(renderer), failed);
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
struct transformation ret = {
.origin_x = priv->origin_x,
.origin_y = priv->origin_y,
.scale = priv->scale,
};
return ret;
return priv->widget_to_layout;
}

View File

@ -25,7 +25,6 @@
#include <pango/pangocairo.h>
#include "eek-types.h"
#include "src/layout.h"
G_BEGIN_DECLS
@ -36,15 +35,6 @@ struct _EekRendererClass
{
GObjectClass parent_class;
void (* render_button) (EekRenderer *self,
cairo_t *cr,
struct button_place *place,
gdouble scale,
gboolean rotate);
void (* render_keyboard) (EekRenderer *self,
cairo_t *cr);
cairo_surface_t *(* get_icon_surface) (EekRenderer *self,
const gchar *icon_name,
gint size,
@ -62,24 +52,9 @@ void eek_renderer_set_allocation_size
(EekRenderer *renderer,
gdouble width,
gdouble height);
void eek_renderer_get_size (EekRenderer *renderer,
gdouble *width,
gdouble *height);
void eek_renderer_get_button_bounds (EekBounds view_bounds,
struct button_place *button,
EekBounds *bounds,
gboolean rotate);
gdouble eek_renderer_get_scale (EekRenderer *renderer);
void eek_renderer_set_scale_factor (EekRenderer *renderer,
gint scale);
void eek_renderer_render_button (EekRenderer *renderer,
cairo_t *cr,
struct button_place *place,
gdouble scale,
gboolean rotate);
cairo_surface_t *eek_renderer_get_icon_surface(const gchar *icon_name,
gint size,
gint scale);
@ -87,24 +62,6 @@ cairo_surface_t *eek_renderer_get_icon_surface(const gchar *icon_name,
void eek_renderer_render_keyboard (EekRenderer *renderer,
cairo_t *cr);
void eek_renderer_set_default_foreground_color
(EekRenderer *renderer,
const EekColor *color);
void eek_renderer_set_default_background_color
(EekRenderer *renderer,
const EekColor *color);
void eek_renderer_get_foreground_color
(GtkStyleContext *context,
EekColor *color);
void eek_renderer_set_border_width (EekRenderer *renderer,
gdouble border_width);
void eek_renderer_apply_transformation_for_button
(cairo_t *cr,
EekBounds view_bounds,
struct button_place *place,
gdouble scale,
gboolean rotate);
struct transformation
eek_renderer_get_transformation (EekRenderer *renderer);

View File

@ -72,35 +72,3 @@ eek_bounds_free (EekBounds *bounds)
{
g_slice_free (EekBounds, bounds);
}
/* EekColor */
G_DEFINE_BOXED_TYPE(EekColor, eek_color, eek_color_copy, eek_color_free);
EekColor *
eek_color_copy (const EekColor *color)
{
return g_slice_dup (EekColor, color);
}
void
eek_color_free (EekColor *color)
{
g_slice_free (EekColor, color);
}
EekColor *
eek_color_new (gdouble red,
gdouble green,
gdouble blue,
gdouble alpha)
{
EekColor *color;
color = g_slice_new (EekColor);
color->red = red;
color->green = green;
color->blue = blue;
color->alpha = alpha;
return color;
}

View File

@ -34,10 +34,8 @@ G_BEGIN_DECLS
#define EEK_TYPE_POINT (eek_point_get_type ())
#define EEK_TYPE_BOUNDS (eek_bounds_get_type ())
#define EEK_TYPE_COLOR (eek_color_get_type ())
typedef struct _EekBounds EekBounds;
typedef struct _EekColor EekColor;
typedef struct _EekboardContextService EekboardContextService;
typedef struct _LevelKeyboard LevelKeyboard;
@ -85,37 +83,19 @@ GType eek_bounds_get_type (void) G_GNUC_CONST;
EekBounds *eek_bounds_copy (const EekBounds *bounds);
void eek_bounds_free (EekBounds *bounds);
/**
* EekColor:
* @red: red component of color, between 0.0 and 1.0
* @green: green component of color, between 0.0 and 1.0
* @blue: blue component of color, between 0.0 and 1.0
* @alpha: alpha component of color, between 0.0 and 1.0
*
* Color used for drawing.
*/
struct _EekColor
{
/*< public >*/
gdouble red;
gdouble green;
gdouble blue;
gdouble alpha;
};
GType eek_color_get_type (void) G_GNUC_CONST;
EekColor *eek_color_new (gdouble red,
gdouble green,
gdouble blue,
gdouble alpha);
EekColor *eek_color_copy (const EekColor *color);
void eek_color_free (EekColor *color);
struct transformation {
gdouble origin_x;
gdouble origin_y;
gdouble scale;
};
struct squeek_button;
struct squeek_row;
/// Represents the path to the button within a view
struct button_place {
const struct squeek_row *row;
const struct squeek_button *button;
};
G_END_DECLS
#endif /* EEK_TYPES_H */

View File

@ -24,7 +24,6 @@
#include "config.h"
#include "eek-keyboard.h"
#include "src/keyboard.h"
#include "src/layout.h"
#include "eek-xml-layout.h"
@ -35,6 +34,5 @@ eek_xml_layout_real_create_keyboard (const char *keyboard_type,
enum squeek_arrangement_kind t)
{
struct squeek_layout *layout = squeek_load_layout(keyboard_type, t);
squeek_layout_place_contents(layout);
return level_keyboard_new(manager, layout);
}

View File

@ -207,22 +207,8 @@ static void
settings_get_layout(GSettings *settings, char **type, char **layout)
{
GVariant *inputs = g_settings_get_value(settings, "sources");
guint32 index;
g_settings_get(settings, "current", "u", &index);
GVariantIter *iter;
g_variant_get(inputs, "a(ss)", &iter);
for (unsigned i = 0;
g_variant_iter_loop(iter, "(ss)", type, layout);
i++) {
if (i == index) {
//printf("Found layout %s %s\n", *type, *layout);
break;
}
}
g_variant_iter_free(iter);
g_variant_unref(inputs);
// current layout is always first
g_variant_get_child(inputs, 0, "(ss)", type, layout);
}
void

View File

@ -1,52 +1,10 @@
extern crate rs;
extern crate xkbcommon;
use rs::tests::check_builtin_layout;
use std::env;
use rs::data::{ Layout, LoadError };
use xkbcommon::xkb;
fn check_layout(name: &str) {
let layout = Layout::from_resource(name)
.and_then(|layout| layout.build().map_err(LoadError::BadKeyMap))
.expect("layout broken");
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let keymap_str = layout.keymap_str
.clone()
.into_string().expect("Failed to decode keymap string");
let keymap = xkb::Keymap::new_from_string(
&context,
keymap_str.clone(),
xkb::KEYMAP_FORMAT_TEXT_V1,
xkb::KEYMAP_COMPILE_NO_FLAGS,
).expect("Failed to create keymap");
let state = xkb::State::new(&keymap);
// "Press" each button with keysyms
for view in layout.views.values() {
for row in &view.rows {
for button in &row.buttons {
let keystate = button.state.borrow();
for keycode in &keystate.keycodes {
match state.key_get_one_sym(*keycode) {
xkb::KEY_NoSymbol => {
eprintln!("{}", keymap_str);
panic!("Keysym {} on key {:?} can't be resolved", keycode, button.name);
},
_ => {},
}
}
}
}
}
}
fn main() -> () {
check_layout(env::args().nth(1).expect("No argument given").as_str());
check_builtin_layout(
env::args().nth(1).expect("No argument given").as_str()
);
}

View File

@ -1,7 +1,7 @@
project(
'squeekboard',
'c', 'rust',
version: '1.3.0',
version: '1.4.0',
license: 'GPLv3',
meson_version: '>=0.51.0',
default_options: [
@ -33,6 +33,11 @@ endif
if get_option('buildtype') != 'plain'
add_project_arguments('-fstack-protector-strong', language: 'c')
endif
if get_option('buildtype') == 'release'
cargo_build_flags = ['--release'] # for artifacts
else
cargo_build_flags = []
endif
prefix = get_option('prefix')
datadir = join_paths(prefix, get_option('datadir'))
@ -54,8 +59,9 @@ summary = [
]
message('\n'.join(summary))
cargo = find_program('cargo')
dep_cargo = find_program('cargo')
cargo_script = find_program('cargo.sh')
cargo_build = find_program('cargo_build.sh')
subdir('data')
subdir('protocols')

16
src/bin/test_layout.rs Normal file
View File

@ -0,0 +1,16 @@
#[macro_use]
extern crate clap;
extern crate rs;
use rs::tests::check_layout_file;
fn main() -> () {
let matches = clap_app!(test_layout =>
(name: "squeekboard-test-layout")
(about: "Test keyboard layout for errors. Returns OK or an error message containing further information.")
(@arg INPUT: +required "Yaml keyboard layout file to test")
).get_matches();
if check_layout_file(matches.value_of("INPUT").unwrap()) == () {
println!("Test result: OK");
}
}

View File

@ -17,6 +17,7 @@ use ::keyboard::{
KeyState, PressType,
generate_keymap, generate_keycodes, FormattingError
};
use ::layout;
use ::layout::ArrangementKind;
use ::resources;
use ::util::c::as_str;
@ -26,8 +27,8 @@ use ::xdg;
// traits, derives
use std::io::BufReader;
use std::iter::FromIterator;
use serde::Deserialize;
use util::WarningHandler;
/// Gathers stuff defined in C or called by C
@ -151,21 +152,30 @@ fn list_layout_sources(
ret
}
struct PrintWarnings;
impl WarningHandler for PrintWarnings {
fn handle(&mut self, warning: &str) {
println!("{}", warning);
}
}
fn load_layout_data(source: DataSource)
-> Result<::layout::LayoutData, LoadError>
{
let handler = PrintWarnings{};
match source {
DataSource::File(path) => {
Layout::from_file(path.clone())
.map_err(LoadError::BadData)
.and_then(|layout|
layout.build().map_err(LoadError::BadKeyMap)
layout.build(handler).0.map_err(LoadError::BadKeyMap)
)
},
DataSource::Resource(name) => {
Layout::from_resource(&name)
.and_then(|layout|
layout.build().map_err(LoadError::BadKeyMap)
layout.build(handler).0.map_err(LoadError::BadKeyMap)
)
},
}
@ -206,6 +216,7 @@ fn load_layout_data_with_fallback(
#[derive(Debug, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Layout {
/// FIXME: deprecate in favor of margins
bounds: Bounds,
views: HashMap<String, Vec<ButtonIds>>,
#[serde(default)]
@ -225,22 +236,28 @@ struct Bounds {
/// Buttons are embedded in a single string
type ButtonIds = String;
/// All info about a single button
/// Buttons can have multiple instances though.
#[derive(Debug, Default, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
struct ButtonMeta {
/// Action other than keysym (conflicts with keysym)
/// Special action to perform on activation. Conflicts with keysym, text.
action: Option<Action>,
/// The name of the outline. If not present, will be "default"
outline: Option<String>,
/// FIXME: start using it
/// The name of the XKB keysym to emit on activation.
/// Conflicts with action, text
keysym: Option<String>,
/// If not present, will be derived from the button ID
/// The text to submit on activation. Will be derived from ID if not present
/// Conflicts with action, keysym
text: Option<String>,
/// If not present, will be derived from text or the button ID
label: Option<String>,
/// Conflicts with label
icon: Option<String>,
/// The name of the outline. If not present, will be "default"
outline: Option<String>,
}
#[derive(Debug, Deserialize, PartialEq)]
#[derive(Debug, Deserialize, PartialEq, Clone)]
#[serde(deny_unknown_fields)]
enum Action {
#[serde(rename="locking")]
@ -254,6 +271,7 @@ enum Action {
#[derive(Debug, Clone, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
struct Outline {
/// FIXME: replace with Size
bounds: Bounds,
}
@ -288,6 +306,20 @@ impl From<io::Error> for Error {
}
}
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>,
F: Fn(&T) -> f64,
{
let mut offset = 0.0;
iterator.map(move |item| {
let size = get_size(&item);
let value = (offset, item);
offset += size;
value
})
}
impl Layout {
pub fn from_resource(name: &str) -> Result<Layout, LoadError> {
let data = resources::get_keyboard(name)
@ -296,7 +328,7 @@ impl Layout {
.map_err(LoadError::BadResource)
}
fn from_file(path: PathBuf) -> Result<Layout, Error> {
pub fn from_file(path: PathBuf) -> Result<Layout, Error> {
let infile = BufReader::new(
fs::OpenOptions::new()
.read(true)
@ -305,8 +337,8 @@ impl Layout {
serde_yaml::from_reader(infile).map_err(Error::Yaml)
}
pub fn build(self)
-> Result<::layout::LayoutData, FormattingError>
pub fn build<H: WarningHandler>(self, mut warning_handler: H)
-> (Result<::layout::LayoutData, FormattingError>, H)
{
let button_names = self.views.values()
.flat_map(|rows| {
@ -323,7 +355,8 @@ impl Layout {
create_action(
&self.buttons,
name,
self.views.keys().collect()
self.views.keys().collect(),
&mut warning_handler,
)
)}).collect();
@ -368,13 +401,15 @@ impl Layout {
)
});
let button_states
= HashMap::<String, KeyState>::from_iter(
button_states
);
let button_states = HashMap::<String, KeyState>::from_iter(
button_states
);
// TODO: generate from symbols
let keymap_str = generate_keymap(&button_states)?;
let keymap_str = match generate_keymap(&button_states) {
Err(e) => { return (Err(e), warning_handler) },
Ok(v) => v,
};
let button_states_cache = hash_map_map(
button_states,
@ -385,145 +420,186 @@ impl Layout {
);
let views = HashMap::from_iter(
self.views.iter().map(|(name, view)| {(
name.clone(),
Box::new(::layout::View {
bounds: ::layout::c::Bounds {
x: self.bounds.x,
y: self.bounds.y,
width: self.bounds.width,
height: self.bounds.height,
},
rows: view.iter().map(|row| {
Box::new(::layout::Row {
angle: 0,
bounds: None,
buttons: row.split_ascii_whitespace().map(|name| {
Box::new(create_button(
&self.buttons,
&self.outlines,
name,
button_states_cache.get(name.into())
.expect("Button state not created")
.clone()
))
}).collect(),
})
}).collect(),
})
)})
self.views.iter().map(|(name, view)| {
let rows = view.iter().map(|row| {
let buttons = row.split_ascii_whitespace()
.map(|name| {
Box::new(create_button(
&self.buttons,
&self.outlines,
name,
button_states_cache.get(name.into())
.expect("Button state not created")
.clone(),
&mut warning_handler,
))
});
::layout::Row {
angle: 0,
buttons: add_offsets(
buttons,
|button| button.size.width,
).collect()
}
});
let rows = add_offsets(rows, |row| row.get_height())
.collect();
(
name.clone(),
layout::View::new(rows)
)
})
);
Ok(::layout::LayoutData {
views: views,
keymap_str: {
CString::new(keymap_str)
.expect("Invalid keymap string generated")
},
})
(
Ok(::layout::LayoutData {
views: views,
keymap_str: {
CString::new(keymap_str)
.expect("Invalid keymap string generated")
},
// FIXME: use a dedicated field
margins: layout::Margins {
top: self.bounds.x,
left: self.bounds.y,
bottom: 0.0,
right: self.bounds.y,
},
}),
warning_handler,
)
}
}
fn create_action(
fn create_action<H: WarningHandler>(
button_info: &HashMap<String, ButtonMeta>,
name: &str,
view_names: Vec<&String>,
warning_handler: &mut H,
) -> ::action::Action {
let default_meta = ButtonMeta::default();
let symbol_meta = button_info.get(name)
.unwrap_or(&default_meta);
fn filter_view_name(
button_name: &str,
view_name: String,
view_names: &Vec<&String>
) -> String {
if view_names.contains(&&view_name) {
view_name
} else {
eprintln!(
"Button {} switches to missing view {}",
button_name,
view_name
);
"base".into()
}
}
fn keysym_valid(name: &str) -> bool {
xkb::keysym_from_name(name, xkb::KEYSYM_NO_FLAGS) != xkb::KEY_NoSymbol
}
let keysyms = match &symbol_meta.action {
// Non-submit action
Some(_) => Vec::new(),
// Submit action
None => match &symbol_meta.keysym {
// Keysym given explicitly
Some(keysym) => vec!(match keysym_valid(keysym.as_str()) {
true => keysym.clone(),
false => {
eprintln!("Keysym name invalid: {}", keysym);
"space".into() // placeholder
},
}),
// Keysyms left open to derive
// TODO: when button name is meant diretly as xkb keysym name,
// mark it so, e.g. with a "#"
None => match keysym_valid(name) {
// Button name is actually a valid xkb name
true => vec!(String::from(name)),
// Button name is not a valid xkb name,
// so assume it's a literal string to be submitted
false => {
if name.chars().count() == 0 {
// A name read from yaml with no valid Unicode.
// Highly improbable, but let's be safe.
eprintln!("Key {} doesn't have any characters", name);
vec!("space".into()) // placeholder
} else {
name.chars().map(|codepoint| {
let codepoint_string = codepoint.to_string();
match keysym_valid(codepoint_string.as_str()) {
true => codepoint_string,
false => format!("U{:04X}", codepoint as u32),
}
}).collect()
}
},
},
},
enum SubmitData {
Action(Action),
Text(String),
Keysym(String),
};
match &symbol_meta.action {
Some(Action::SetView(view_name)) => ::action::Action::SetLevel(
filter_view_name(name, view_name.clone(), &view_names)
let submission = match (
&symbol_meta.action,
&symbol_meta.keysym,
&symbol_meta.text
) {
(Some(action), None, None) => SubmitData::Action(action.clone()),
(None, Some(keysym), None) => SubmitData::Keysym(keysym.clone()),
(None, None, Some(text)) => SubmitData::Text(text.clone()),
(None, None, None) => SubmitData::Text(name.into()),
_ => {
warning_handler.handle(&format!(
"Button {} has more than one of (action, keysym, text)",
name
));
SubmitData::Text("".into())
},
};
fn filter_view_name<H: WarningHandler>(
button_name: &str,
view_name: String,
view_names: &Vec<&String>,
warning_handler: &mut H,
) -> String {
if view_names.contains(&&view_name) {
view_name
} else {
warning_handler.handle(&format!("Button {} switches to missing view {}",
button_name,
view_name,
));
"base".into()
}
}
match submission {
SubmitData::Action(
Action::SetView(view_name)
) => ::action::Action::SetLevel(
filter_view_name(
name, view_name.clone(), &view_names,
warning_handler,
)
),
Some(Action::Locking {
SubmitData::Action(Action::Locking {
lock_view, unlock_view
}) => ::action::Action::LockLevel {
lock: filter_view_name(name, lock_view.clone(), &view_names),
lock: filter_view_name(
name,
lock_view.clone(),
&view_names,
warning_handler,
),
unlock: filter_view_name(
name,
unlock_view.clone(),
&view_names
&view_names,
warning_handler,
),
},
Some(Action::ShowPrefs) => ::action::Action::ShowPreferences,
None => ::action::Action::Submit {
SubmitData::Action(
Action::ShowPrefs
) => ::action::Action::ShowPreferences,
SubmitData::Keysym(keysym) => ::action::Action::Submit {
text: None,
keys: keysyms.into_iter().map(::action::KeySym).collect(),
keys: vec!(::action::KeySym(
match keysym_valid(keysym.as_str()) {
true => keysym.clone(),
false => {
warning_handler.handle(&format!(
"Keysym name invalid: {}",
keysym,
));
"space".into() // placeholder
},
}
)),
},
SubmitData::Text(text) => ::action::Action::Submit {
text: {
CString::new(text.clone())
.map_err(|e| {
warning_handler.handle(&format!(
"Text {} contains problems: {:?}",
text,
e
));
e
}).ok()
},
keys: text.chars().map(|codepoint| {
let codepoint_string = codepoint.to_string();
::action::KeySym(match keysym_valid(codepoint_string.as_str()) {
true => codepoint_string,
false => format!("U{:04X}", codepoint as u32),
})
}).collect(),
}
}
}
/// TODO: Since this will receive user-provided data,
/// all .expect() on them should be turned into soft fails
fn create_button(
fn create_button<H: WarningHandler>(
button_info: &HashMap<String, ButtonMeta>,
outlines: &HashMap<String, Outline>,
name: &str,
state: Rc<RefCell<KeyState>>,
warning_handler: &mut H,
) -> ::layout::Button {
let cname = CString::new(name.clone())
.expect("Bad name");
@ -539,6 +615,18 @@ fn create_button(
} else if let Some(icon) = &button_meta.icon {
::layout::Label::IconName(CString::new(icon.as_str())
.expect("Bad icon"))
} else if let Some(text) = &button_meta.text {
::layout::Label::Text(
CString::new(text.as_str())
.unwrap_or_else(|e| {
warning_handler.handle(&format!(
"Text {} is invalid: {}",
text,
e,
));
CString::new("").unwrap()
})
)
} else {
::layout::Label::Text(cname.clone())
};
@ -548,7 +636,7 @@ fn create_button(
if outlines.contains_key(outline) {
outline.clone()
} else {
eprintln!("Outline named {} does not exist! Using default for button {}", outline, name);
warning_handler.handle(&format!("Outline named {} does not exist! Using default for button {}", outline, name));
"default".into()
}
}
@ -558,19 +646,19 @@ fn create_button(
let outline = outlines.get(&outline_name)
.map(|outline| (*outline).clone())
.unwrap_or_else(|| {
eprintln!("No default outline defied Using 1x1!");
warning_handler.handle(
&format!("No default outline defined! Using 1x1!")
);
Outline {
bounds: Bounds { x: 0f64, y: 0f64, width: 1f64, height: 1f64 },
}
});
::layout::Button {
layout::Button {
name: cname,
outline_name: CString::new(outline_name).expect("Bad outline"),
// TODO: do layout before creating buttons
bounds: ::layout::c::Bounds {
x: outline.bounds.x,
y: outline.bounds.y,
size: layout::Size {
width: outline.bounds.width,
height: outline.bounds.height,
},
@ -585,6 +673,14 @@ mod tests {
use std::error::Error as ErrorTrait;
struct PanicWarn;
impl WarningHandler for PanicWarn {
fn handle(&mut self, warning: &str) {
panic!("{}", warning);
}
}
#[test]
fn test_parse_path() {
assert_eq!(
@ -599,6 +695,7 @@ mod tests {
icon: None,
keysym: None,
action: None,
text: None,
label: Some("test".into()),
outline: None,
}
@ -656,12 +753,12 @@ mod tests {
fn test_layout_punctuation() {
let out = Layout::from_file(PathBuf::from("tests/layout_key1.yaml"))
.unwrap()
.build()
.build(PanicWarn).0
.unwrap();
assert_eq!(
out.views["base"]
.rows[0]
.buttons[0]
.get_rows()[0].1
.buttons[0].1
.label,
::layout::Label::Text(CString::new("test").unwrap())
);
@ -671,12 +768,12 @@ mod tests {
fn test_layout_unicode() {
let out = Layout::from_file(PathBuf::from("tests/layout_key2.yaml"))
.unwrap()
.build()
.build(PanicWarn).0
.unwrap();
assert_eq!(
out.views["base"]
.rows[0]
.buttons[0]
.get_rows()[0].1
.buttons[0].1
.label,
::layout::Label::Text(CString::new("test").unwrap())
);
@ -687,12 +784,12 @@ mod tests {
fn test_layout_unicode_multi() {
let out = Layout::from_file(PathBuf::from("tests/layout_key3.yaml"))
.unwrap()
.build()
.build(PanicWarn).0
.unwrap();
assert_eq!(
out.views["base"]
.rows[0]
.buttons[0]
.get_rows()[0].1
.buttons[0].1
.state.borrow()
.keycodes.len(),
2
@ -702,7 +799,7 @@ mod tests {
#[test]
fn parsing_fallback() {
assert!(Layout::from_resource(FALLBACK_LAYOUT_NAME)
.and_then(|layout| layout.build().map_err(LoadError::BadKeyMap))
.map(|layout| layout.build(PanicWarn).0.unwrap())
.is_ok()
);
}
@ -742,18 +839,20 @@ mod tests {
".".into() => ButtonMeta {
icon: None,
keysym: None,
text: None,
action: None,
label: Some("test".into()),
outline: None,
}
},
".",
Vec::new()
Vec::new(),
&mut PanicWarn,
),
::action::Action::Submit {
text: None,
text: Some(CString::new(".").unwrap()),
keys: vec!(::action::KeySym("U002E".into())),
}
},
);
}
}

120
src/drawing.rs Normal file
View File

@ -0,0 +1,120 @@
/*! Drawing the UI */
use cairo;
use std::cell::RefCell;
use ::keyboard;
use ::layout::{ Button, Layout };
use ::layout::c::{ EekGtkKeyboard, Point };
use glib::translate::FromGlibPtrNone;
use gtk::WidgetExt;
mod c {
use super::*;
use cairo_sys;
use std::os::raw::c_void;
// This is constructed only in C, no need for warnings
#[allow(dead_code)]
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct EekRenderer(*const c_void);
#[no_mangle]
extern "C" {
// Button and View inside CButtonPlace are safe to pass to C
// as long as they don't outlive the call
// and nothing dereferences them
#[allow(improper_ctypes)]
pub fn eek_render_button(
renderer: EekRenderer,
cr: *mut cairo_sys::cairo_t,
button: *const Button,
pressed: u64,
locked: u64,
);
}
#[no_mangle]
pub extern "C"
fn squeek_layout_draw_all_changed(
layout: *mut Layout,
renderer: EekRenderer,
cr: *mut cairo_sys::cairo_t,
) {
let layout = unsafe { &mut *layout };
let cr = unsafe { cairo::Context::from_raw_none(cr) };
let view = layout.get_current_view();
for (row_offset, row) in &view.get_rows() {
for (x_offset, button) in &row.buttons {
let state = RefCell::borrow(&button.state).clone();
if state.pressed == keyboard::PressType::Pressed || state.locked {
render_button_at_position(
renderer, &cr,
row_offset + Point { x: *x_offset, y: 0.0 },
button.as_ref(),
state.pressed, state.locked,
);
}
}
}
}
#[no_mangle]
pub extern "C"
fn squeek_draw_layout_base_view(
layout: *mut Layout,
renderer: EekRenderer,
cr: *mut cairo_sys::cairo_t,
) {
let layout = unsafe { &mut *layout };
let cr = unsafe { cairo::Context::from_raw_none(cr) };
let view = layout.get_current_view();
for (row_offset, row) in &view.get_rows() {
for (x_offset, button) in &row.buttons {
render_button_at_position(
renderer, &cr,
row_offset + Point { x: *x_offset, y: 0.0 },
button.as_ref(),
keyboard::PressType::Released, false,
);
}
}
}
}
/// Renders a button at a position (button's own bounds ignored)
pub fn render_button_at_position(
renderer: c::EekRenderer,
cr: &cairo::Context,
position: Point,
button: &Button,
pressed: keyboard::PressType,
locked: bool,
) {
cr.save();
cr.translate(position.x, position.y);
cr.rectangle(
0.0, 0.0,
button.size.width, button.size.height
);
cr.clip();
unsafe {
c::eek_render_button(
renderer,
cairo::Context::to_raw_none(&cr),
button as *const Button,
pressed as u64,
locked as u64,
)
};
cr.restore();
}
pub fn queue_redraw(keyboard: EekGtkKeyboard) {
let widget = unsafe { gtk::Widget::from_glib_none(keyboard.0) };
widget.queue_draw();
}

View File

@ -102,8 +102,12 @@ pub mod c {
imservice.pending = IMProtocolState {
content_hint: {
ContentHint::from_bits(hint).unwrap_or_else(|| {
eprintln!("Warning: received invalid hint flags");
ContentHint::NONE
let out = ContentHint::from_bits_truncate(hint);
eprintln!(
"Warning: received hint flags with unknown bits set: 0x{:x}",
hint ^ out.bits(),
);
out
})
},
content_purpose: {
@ -141,6 +145,16 @@ pub mod c {
{
let imservice = check_imservice(imservice, im).unwrap();
let active_changed = imservice.current.active ^ imservice.pending.active;
fn is_visible(state: &IMProtocolState) -> bool {
state.active
&& !state.content_hint.contains(
ContentHint::ON_SCREEN_INPUT_PROVIDED
)
}
let visible_changed = is_visible(&imservice.current)
^ is_visible(&imservice.pending);
imservice.serial += Wrapping(1u32);
imservice.current = imservice.pending.clone();
@ -148,13 +162,18 @@ pub mod c {
active: imservice.current.active,
..IMProtocolState::default()
};
if active_changed {
if imservice.current.active {
if active_changed && imservice.current.active {
eekboard_context_service_set_hint_purpose(
imservice.ui_manager,
imservice.current.content_hint.bits(),
imservice.current.content_purpose.clone() as u32,
);
}
if visible_changed {
if is_visible(&imservice.current) {
eekboard_context_service_show_keyboard(imservice.ui_manager);
eekboard_context_service_set_hint_purpose(
imservice.ui_manager,
imservice.current.content_hint.bits(),
imservice.current.content_purpose.clone() as u32);
} else {
eekboard_context_service_hide_keyboard(imservice.ui_manager);
}
@ -219,6 +238,7 @@ bitflags!{
const SENSITIVE_DATA = 0x80;
const LATIN = 0x100;
const MULTILINE = 0x200;
const ON_SCREEN_INPUT_PROVIDED = 0x400;
}
}

View File

@ -1,12 +0,0 @@
#ifndef __KEYBOARD_H
#define __KEYBOARD_H
#include "inttypes.h"
#include "stdbool.h"
#include "virtual-keyboard-unstable-v1-client-protocol.h"
struct squeek_key;
uint32_t squeek_key_is_pressed(struct squeek_key *key);
uint32_t squeek_key_is_locked(struct squeek_key *key);
#endif

View File

@ -10,32 +10,8 @@ use ::action::Action;
use std::io::Write;
use std::iter::{ FromIterator, IntoIterator };
use ::util::CloneOwned;
/// Gathers stuff defined in C or called by C
pub mod c {
use super::*;
use ::util::c;
pub type CKeyState = c::Wrapped<KeyState>;
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
#[no_mangle]
pub extern "C"
fn squeek_key_is_pressed(key: CKeyState) -> u32 {
//let key = unsafe { Rc::from_raw(key.0) };
return key.clone_owned().pressed as u32;
}
#[no_mangle]
pub extern "C"
fn squeek_key_is_locked(key: CKeyState) -> u32 {
return key.clone_owned().locked as u32;
}
}
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PressType {
Released = 0,
Pressed = 1,
@ -51,14 +27,26 @@ pub struct KeyState {
pub action: Action,
}
/// Generates a mapping where each key gets a keycode, starting from 8
/// Sorts an iterator by converting it to a Vector and back
fn sorted<'a, I: Iterator<Item=&'a str>>(
iter: I
) -> impl Iterator<Item=&'a str> {
let mut v: Vec<&'a str> = iter.collect();
v.sort();
v.into_iter()
}
/// 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> {
HashMap::from_iter(
key_names.into_iter()
// sort to remove a source of indeterminism in keycode assignment
sorted(key_names.into_iter())
.map(|name| String::from(name))
.zip(8..)
.zip(9..)
)
}

View File

@ -5,8 +5,8 @@
#include <glib.h>
#include "eek/eek-element.h"
#include "eek/eek-gtk-keyboard.h"
#include "eek/eek-renderer.h"
#include "eek/eek-types.h"
#include "src/keyboard.h"
#include "virtual-keyboard-unstable-v1-client-protocol.h"
enum squeek_arrangement_kind {
@ -14,48 +14,19 @@ enum squeek_arrangement_kind {
ARRANGEMENT_KIND_WIDE = 1,
};
struct squeek_button;
struct squeek_row;
struct squeek_view;
struct squeek_layout;
/// Represents the path to the button within a view
struct button_place {
const struct squeek_row *row;
const struct squeek_button *button;
};
int32_t squeek_row_get_angle(const struct squeek_row*);
EekBounds squeek_row_get_bounds(const struct squeek_row*);
typedef void (*ButtonCallback) (struct squeek_button *button, gpointer user_data);
void squeek_row_foreach(struct squeek_row*,
ButtonCallback callback,
gpointer user_data);
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*);
struct squeek_key *squeek_button_get_key(const struct squeek_button*);
uint32_t *squeek_button_has_key(const struct squeek_button* button,
const struct squeek_key *key);
void squeek_button_print(const struct squeek_button* button);
EekBounds squeek_view_get_bounds(const struct squeek_view*);
typedef void (*RowCallback) (struct squeek_row *row, gpointer user_data);
void squeek_view_foreach(struct squeek_view*,
RowCallback callback,
gpointer user_data);
void
squeek_layout_place_contents(struct squeek_layout*);
struct squeek_view *squeek_layout_get_current_view(struct squeek_layout*);
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*);
@ -75,5 +46,6 @@ void squeek_layout_drag(struct squeek_layout *layout, struct zwp_virtual_keyboar
double x_widget, double y_widget,
struct transformation widget_to_layout,
uint32_t timestamp, EekGtkKeyboard *ui_keyboard);
void squeek_layout_draw_all_changed(struct squeek_layout *layout, EekGtkKeyboard *ui_keyboard);
void squeek_layout_draw_all_changed(struct squeek_layout *layout, EekRenderer* renderer, cairo_t *cr);
void squeek_draw_layout_base_view(struct squeek_layout *layout, EekRenderer* renderer, cairo_t *cr);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,8 @@
#[macro_use]
extern crate bitflags;
extern crate cairo;
extern crate cairo_sys;
extern crate gdk;
extern crate gio;
extern crate glib;
extern crate glib_sys;
@ -14,6 +17,7 @@ extern crate xkbcommon;
mod action;
pub mod data;
mod drawing;
pub mod float_ord;
pub mod imservice;
mod keyboard;
@ -24,5 +28,7 @@ mod outputs;
mod popover;
mod resources;
mod submission;
mod util;
mod style;
pub mod tests;
pub mod util;
mod xdg;

View File

@ -58,7 +58,7 @@ rslibs = custom_target(
output: ['librs.a'],
install: false,
console: true,
command: [cargo_script, '@OUTPUT@', 'build']
command: [cargo_build] + cargo_build_flags + ['@OUTPUT@', '--lib']
)
build_rstests = custom_target(
@ -72,14 +72,16 @@ build_rstests = custom_target(
output: ['src'],
install: false,
console: true,
command: [cargo_script, '', 'build', '--tests'],
command: [cargo_script, 'test', '--no-run'],
depends: rslibs, # no point building tests if the code itself fails
)
test(
'rstest',
cargo_script,
args: ['', 'test'],
args: ['test'],
# this is a whole Carg-based test suite, let it run for a while
timeout: 900,
depends: build_rstests,
)
@ -95,20 +97,7 @@ libsqueekboard = static_library('libsqueekboard',
'-DEEK_COMPILATION=1'],
)
# the straight binary needs to be demoted in favor of the wrapper script
# due to styling being inconsistent
bindir = join_paths(prefix, get_option('bindir'))
wrapper_conf = configuration_data()
wrapper_conf.set('bindir', bindir)
configure_file(
input: '../tools/squeekboard.in',
output: 'squeekboard',
install_dir: bindir,
configuration: wrapper_conf,
install: true,
)
squeekboard = executable('squeekboard-real',
squeekboard = executable('squeekboard',
'server-main.c',
wl_proto_sources,
squeekboard_resources,
@ -122,3 +111,17 @@ squeekboard = executable('squeekboard-real',
'-DEEKBOARD_COMPILATION=1',
'-DEEK_COMPILATION=1'],
)
bindir = join_paths(prefix, get_option('bindir'))
test_layout = custom_target('squeekboard-test-layout',
build_by_default: true,
# meson doesn't track all inputs, cargo does
build_always_stale: true,
output: ['squeekboard-test-layout'],
console: true,
command: [cargo_build] + cargo_build_flags
+ ['--rename', 'test_layout', '@OUTPUT@', '--bin', 'test_layout'],
install: true,
install_dir: bindir,
)

View File

@ -7,9 +7,9 @@ use ::locale::compare_current_locale;
use ::locale_config::system_locale;
use ::resources;
use gio::ActionExt;
use gio::ActionMapExt;
use gio::SettingsExt;
use gio::SimpleActionExt;
use glib::translate::FromGlibPtrNone;
use glib::variant::ToVariant;
use gtk::PopoverExt;
@ -18,8 +18,11 @@ use std::io::Write;
mod variants {
use glib;
use glib::Variant;
use glib_sys;
use std::os::raw::c_char;
use glib::ToVariant;
use glib::translate::FromGlibPtrFull;
use glib::translate::ToGlibPtr;
@ -49,6 +52,44 @@ mod variants {
})
.collect()
}
/// "a(ss)" variant
/// Rust doesn't allow implementing existing traits for existing types
pub struct ArrayPairString(pub Vec<(String, String)>);
impl ToVariant for ArrayPairString {
fn to_variant(&self) -> Variant {
let tspec = "a(ss)".to_glib_none();
let builder = unsafe {
let vtype = glib_sys::g_variant_type_checked_(tspec.0);
glib_sys::g_variant_builder_new(vtype)
};
let ispec = "(ss)".to_glib_none();
for (a, b) in &self.0 {
let a = a.to_glib_none();
let b = b.to_glib_none();
// string pointers are weak references
// and will get silently invalidated
// as soon as the source is out of scope
{
let a: *const c_char = a.0;
let b: *const c_char = b.0;
unsafe {
glib_sys::g_variant_builder_add(
builder,
ispec.0,
a, b
);
}
}
}
unsafe {
let ret = glib_sys::g_variant_builder_end(builder);
glib_sys::g_variant_builder_unref(builder);
glib::Variant::from_glib_full(ret)
}
}
}
}
fn make_menu_builder(inputs: Vec<(&str, &str)>) -> gtk::Builder {
@ -88,12 +129,15 @@ fn make_menu_builder(inputs: Vec<(&str, &str)>) -> gtk::Builder {
fn set_layout(kind: String, name: String) {
let settings = gio::Settings::new("org.gnome.desktop.input-sources");
let inputs = settings.get_value("sources").unwrap();
let inputs = variants::get_tuples(inputs).into_iter();
for (index, (ikind, iname)) in inputs.enumerate() {
if (&ikind, &iname) == (&kind, &name) {
settings.set_uint("current", index as u32);
}
}
let current = (kind.clone(), name.clone());
let inputs = variants::get_tuples(inputs).into_iter()
.filter(|t| t != &current);
let inputs = vec![(kind, name)].into_iter()
.chain(inputs).collect();
settings.set_value(
"sources",
&variants::ArrayPairString(inputs).to_variant()
);
settings.apply();
}
@ -103,7 +147,6 @@ pub fn show(window: EekGtkKeyboard, position: ::layout::c::Bounds) {
let settings = gio::Settings::new("org.gnome.desktop.input-sources");
let inputs = settings.get_value("sources").unwrap();
let current = settings.get_uint("current") as usize;
let inputs = variants::get_tuples(inputs);
let input_names: Vec<&str> = inputs.iter()
@ -152,39 +195,35 @@ pub fn show(window: EekGtkKeyboard, position: ::layout::c::Bounds) {
height: position.width.floor() as i32,
});
let initial_state = input_names[current].to_variant();
if let Some(current_name) = input_names.get(0) {
let current_name = current_name.to_variant();
let layout_action = gio::SimpleAction::new_stateful(
"layout",
Some(initial_state.type_()),
&initial_state,
);
let layout_action = gio::SimpleAction::new_stateful(
"layout",
Some(current_name.type_()),
&current_name,
);
let action_group = gio::SimpleActionGroup::new();
action_group.add_action(&layout_action);
layout_action.connect_change_state(|_action, state| {
match state {
Some(v) => {
v.get::<String>()
.or_else(|| {
eprintln!("Variant is not string: {:?}", v);
None
})
.map(|state| set_layout("xkb".into(), state));
},
None => eprintln!("No variant selected"),
};
});
let action_group = gio::SimpleActionGroup::new();
action_group.add_action(&layout_action);
menu.insert_action_group("popup", Some(&action_group));
};
menu.insert_action_group("popup", Some(&action_group));
menu.bind_model(Some(&model), Some("popup"));
menu.connect_closed(move |_menu| {
let state = match layout_action.get_state() {
Some(v) => {
let s = v.get::<String>().or_else(|| {
eprintln!("Variant is not string: {:?}", v);
None
});
// FIXME: the `get_state` docs call for unrefing,
// but the function is nowhere to be found
// glib::Variant::unref(v);
s
},
None => {
eprintln!("No variant selected");
None
},
};
set_layout("xkb".into(), state.unwrap_or("us".into()));
});
menu.popup();
}

View File

@ -13,11 +13,13 @@ const KEYBOARDS: &[(*const str, *const str)] = &[
("us", include_str!("../data/keyboards/us.yaml")),
("us_wide", include_str!("../data/keyboards/us_wide.yaml")),
("de", include_str!("../data/keyboards/de.yaml")),
("de_wide", include_str!("../data/keyboards/de_wide.yaml")),
("el", include_str!("../data/keyboards/el.yaml")),
("es", include_str!("../data/keyboards/es.yaml")),
("fi", include_str!("../data/keyboards/fi.yaml")),
("it", include_str!("../data/keyboards/it.yaml")),
("ja+kana", include_str!("../data/keyboards/ja+kana.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")),
("se", include_str!("../data/keyboards/se.yaml")),
@ -39,7 +41,10 @@ pub fn get_keyboard(needle: &str) -> Option<&'static str> {
/// Translations of the layout identifier strings
const LAYOUT_NAMES: &[(*const str, *const str)] = &[
("de-DE", include_str!("../data/langs/de-DE.txt")),
("en-US", include_str!("../data/langs/en-US.txt")),
("es-ES", include_str!("../data/langs/es-ES.txt")),
("ja-JP", include_str!("../data/langs/ja-JP.txt")),
("pl-PL", include_str!("../data/langs/pl-PL.txt")),
];

7
src/style.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef __STYLE_H
#define __STYLE_H
#include "gtk/gtk.h"
GtkCssProvider *squeek_load_style();
#endif

124
src/style.rs Normal file
View File

@ -0,0 +1,124 @@
/*
* Copyright (C) 2000 Red Hat, Inc.
* Copyright (C) 2019 Purism, SPC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.Free
*/
/*! CSS data loading */
use std::env;
use glib::object::ObjectExt;
use util::Warn;
/// Gathers stuff defined in C or called by C
pub mod c {
use super::*;
use gio;
use gtk;
use gtk_sys;
use gtk::CssProviderExt;
use glib::translate::ToGlibPtr;
/// Loads the layout style based on current theme
/// without having to worry about string allocation
#[no_mangle]
pub extern "C"
fn squeek_load_style() -> *const gtk_sys::GtkCssProvider {
unsafe { gtk::set_initialized() };
let theme = gtk::Settings::get_default()
.map(|settings| get_theme_name(&settings));
let css_name = path_from_theme(theme);
let resource_name = if gio::resources_get_info(
&css_name,
gio::ResourceLookupFlags::NONE
).is_ok() {
css_name
} else { // use default if this path doesn't exist
path_from_theme(None)
};
let provider = gtk::CssProvider::new();
provider.load_from_resource(&resource_name);
provider.to_glib_full()
}
}
// not Adwaita, but rather fall back to default
const DEFAULT_THEME_NAME: &str = "";
struct GtkTheme {
name: String,
variant: Option<String>,
}
/// Gets theme as determined by the toolkit
/// Ported from GTK's gtksettings.c
fn get_theme_name(settings: &gtk::Settings) -> GtkTheme {
let env_theme = env::var("GTK_THEME")
.map(|theme| {
let mut parts = theme.splitn(2, ":");
GtkTheme {
// guaranteed at least empty string
// as the first result from splitting a string
name: parts.next().unwrap().into(),
variant: parts.next().map(String::from)
}
})
.map_err(|e| {
match &e {
env::VarError::NotPresent => {},
e => eprintln!("GTK_THEME variable invalid: {}", e),
};
e
}).ok();
match env_theme {
Some(theme) => theme,
None => GtkTheme {
name: {
settings.get_property("gtk-theme-name")
.ok_warn("No theme name")
.and_then(|value| value.get::<String>())
.unwrap_or(DEFAULT_THEME_NAME.into())
},
variant: {
settings.get_property("gtk-application-prefer-dark-theme")
.ok_warn("No settings key")
.and_then(|value| value.get::<bool>())
.and_then(|dark_preferred| match dark_preferred {
true => Some("dark".into()),
false => None,
})
},
},
}
}
fn path_from_theme(theme: Option<GtkTheme>) -> String {
format!(
"/sm/puri/squeekboard/style{}.css",
match theme {
Some(GtkTheme { name, variant: Some(variant) }) => {
format!("-{}:{}", name, variant)
},
Some(GtkTheme { name, variant: None }) => format!("-{}", name),
None => "".into(),
}
)
}

78
src/tests.rs Normal file
View File

@ -0,0 +1,78 @@
/*! Testing functionality */
use ::data::Layout;
use xkbcommon::xkb;
use ::util::WarningHandler;
pub struct CountAndPrint(u32);
impl WarningHandler for CountAndPrint {
fn handle(&mut self, warning: &str) {
self.0 = self.0 + 1;
println!("{}", warning);
}
}
impl CountAndPrint {
fn new() -> CountAndPrint {
CountAndPrint(0)
}
}
pub fn check_builtin_layout(name: &str) {
check_layout(Layout::from_resource(name).expect("Invalid layout data"))
}
pub fn check_layout_file(path: &str) {
check_layout(Layout::from_file(path.into()).expect("Invalid layout file"))
}
fn check_layout(layout: Layout) {
let handler = CountAndPrint::new();
let (layout, handler) = layout.build(handler);
if handler.0 > 0 {
println!("{} mistakes in layout", handler.0)
}
let layout = layout.expect("layout broken");
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let keymap_str = layout.keymap_str
.clone()
.into_string().expect("Failed to decode keymap string");
let keymap = xkb::Keymap::new_from_string(
&context,
keymap_str.clone(),
xkb::KEYMAP_FORMAT_TEXT_V1,
xkb::KEYMAP_COMPILE_NO_FLAGS,
).expect("Failed to create keymap");
let state = xkb::State::new(&keymap);
// "Press" each button with keysyms
for view in layout.views.values() {
for (_y, row) in &view.get_rows() {
for (_x, button) in &row.buttons {
let keystate = button.state.borrow();
for keycode in &keystate.keycodes {
match state.key_get_one_sym(*keycode) {
xkb::KEY_NoSymbol => {
eprintln!("{}", keymap_str);
panic!("Keysym {} on key {:?} can't be resolved", keycode, button.name);
},
_ => {},
}
}
}
}
}
if handler.0 > 0 {
panic!("Layout contains mistakes");
}
}

View File

@ -2,6 +2,8 @@
use std::collections::HashMap;
use std::rc::Rc;
use ::float_ord::FloatOrd;
use std::borrow::Borrow;
use std::hash::{ Hash, Hasher };
use std::iter::FromIterator;
@ -142,6 +144,16 @@ pub fn hash_map_map<K, V, F, K1, V1>(map: HashMap<K, V>, mut f: F)
)
}
pub fn find_max_double<T, I, F>(iterator: I, get: F)
-> f64
where I: Iterator<Item=T>,
F: Fn(&T) -> f64
{
iterator.map(|value| FloatOrd(get(&value)))
.max().unwrap_or(FloatOrd(0f64))
.0
}
/// Compares pointers but not internal values of Rc
pub struct Pointer<T>(pub Rc<T>);
@ -177,6 +189,27 @@ impl<T> Borrow<Rc<T>> for Pointer<T> {
}
}
/// Sugar for logging errors in results
pub trait Warn {
type Value;
fn ok_warn(self, msg: &str) -> Option<Self::Value>;
}
impl<T, E: std::error::Error> Warn for Result<T, E> {
type Value = T;
fn ok_warn(self, msg: &str) -> Option<T> {
self.map_err(|e| {
eprintln!("{}: {}", msg, e);
e
}).ok()
}
}
pub trait WarningHandler {
/// Handle a warning
fn handle(&mut self, warning: &str);
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -6,6 +6,25 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
try:
terminal = [("Terminal", Gtk.InputPurpose.TERMINAL)]
except AttributeError:
print("Terminal purpose not available on this GTK version", file=sys.stderr)
terminal = []
def new_grid(items, set_type):
grid = Gtk.Grid(orientation='vertical', column_spacing=8, row_spacing=8)
i = 0
for text, value in items:
l = Gtk.Label(label=text)
e = Gtk.Entry(hexpand=True)
set_type(e, value)
grid.attach(l, 0, i, 1, 1)
grid.attach(e, 1, i, 1, 1)
i += 1
return grid
class App(Gtk.Application):
purposes = [
@ -18,23 +37,26 @@ class App(Gtk.Application):
("E-mail", Gtk.InputPurpose.EMAIL),
("Name", Gtk.InputPurpose.NAME),
("Password", Gtk.InputPurpose.PASSWORD),
("PIN", Gtk.InputPurpose.PIN)
("PIN", Gtk.InputPurpose.PIN),
] + terminal
hints = [
("OSK provided", Gtk.InputHints.INHIBIT_OSK)
]
def do_activate(self):
w = Gtk.ApplicationWindow(application=self)
grid = Gtk.Grid(orientation='vertical', column_spacing=8, row_spacing=8)
i = 0
for text, purpose in self.purposes:
notebook = Gtk.Notebook()
def add_purpose(entry, purpose):
entry.set_input_purpose(purpose)
def add_hint(entry, hint):
entry.set_input_hints(hint)
purpose_grid = new_grid(self.purposes, add_purpose)
hint_grid = new_grid(self.hints, add_hint)
l = Gtk.Label(label=text)
e = Gtk.Entry(hexpand=True)
e.set_input_purpose(purpose)
grid.attach(l, 0, i, 1, 1)
grid.attach(e, 1, i, 1, 1)
i += 1
w.add(grid)
notebook.append_page(purpose_grid, Gtk.Label(label="Purposes"))
notebook.append_page(hint_grid, Gtk.Label(label="Hints"))
w.add(notebook)
w.show_all()
app = App()

View File

@ -49,12 +49,12 @@ endforeach
# and the need to call it manually
foreach layout : [
'us', 'us_wide',
'de',
'de', 'de_wide',
'el',
'es',
'fi',
'it',
'ja+kana',
'jp+kana','jp+kana_wide',
'no',
'number',
'se',
@ -62,7 +62,7 @@ foreach layout : [
test(
'test_layout_' + layout,
cargo_script,
args: ['', 'run', '--example', 'test_layout', layout]
args: ['run', '--example', 'test_layout', layout]
)
endforeach

View File

@ -12,4 +12,4 @@ for DIR in ${DIRS}; do
fi;
done;
exec @bindir@/squeekboard-real
exec $(which squeekboard)