Compare commits

..

40 Commits

Author SHA1 Message Date
930f5be0c8 Release 1.9.0 "Fractal dimension"
Highlights:

- Fixed glib critical when switching layouts
- Fixed minor memory leaks when switching layouts
- Whenever the client supports it, text is sent as text instread of key presses
- New Polish language layout
- Fixed greek layout
- Better key locking
- Less leaks
- Tweaks in terminal layout
- Better emoji layout
2020-02-19 14:47:04 +00:00
7266f539d4 cargo: Update deps 2020-02-19 14:44:35 +00:00
da1f480f7a Merge branch 'emoji' into 'master'
Emoji: More choices

See merge request Librem5/squeekboard!324
2020-02-19 14:43:58 +00:00
3c3f00ede8 Merge branch 'bad_delete' into 'master'
text input: Disable erasing

See merge request Librem5/squeekboard!332
2020-02-18 20:38:33 +00:00
85be855032 text input: Disable erasing
Erasing with zwp_text_input_v3 version 1 requires bytes, and bytes require get_surrounding_text. That, however, is optional. That's a mistake in protocol design.

Easiest to drop this until the mess is solved on the protocol side.
2020-02-12 10:56:07 +00:00
3e642fdac7 Merge branch 'termi' into 'master'
layouts: terminal: Use altline outline for dot key

See merge request Librem5/squeekboard!331
2020-02-12 10:44:28 +00:00
ea288ca62e layouts: terminal: Use altline outline for dot key
This prevents the buttons from jumping around when switching between views.
2020-02-11 23:16:09 +01:00
a57a78aa2e Merge branch 'center' into 'master'
Center views relative to layout space

See merge request Librem5/squeekboard!326
2020-02-09 20:34:31 +00:00
b441103674 Merge branch 'slash' into 'master'
terminal: Make */ easier to reach

See merge request Librem5/squeekboard!325
2020-02-06 09:31:58 +00:00
1c3516d6bf terminal: Make */ easier to reach
They exchanged positions with @%
2020-02-05 19:46:59 +00:00
41be2747d5 Merge branch 'fix' into 'master'
layout: Improve scoping of locked variable

See merge request Librem5/squeekboard!329
2020-02-05 13:19:19 +00:00
c766fae686 layout: Improve scoping of locked variable 2020-02-05 12:55:31 +00:00
a0a2e40fa0 Merge branch 'pl' into 'master'
Better accents in PL

See merge request Librem5/squeekboard!323
2020-02-05 11:13:20 +00:00
aadcdbf276 Merge branch 'langs' into 'master'
Update translations & greek

See merge request Librem5/squeekboard!315
2020-02-05 11:05:42 +00:00
10178d204b Merge remote-tracking branch 'upstream/master' into center 2020-02-05 10:32:07 +00:00
0ac8c620fd Merge branch 'lock' into 'master'
Turn locking stateless

See merge request Librem5/squeekboard!322
2020-02-05 09:25:49 +00:00
80e83781bb Merge branch 'leaks' into 'master'
Allocation problems

See merge request Librem5/squeekboard!327
2020-02-05 09:24:46 +00:00
37e1ed93a6 Merge branch 'text_input_enable' into 'master'
Submit and delete strings via text_input

See merge request Librem5/squeekboard!304
2020-02-03 15:06:25 +00:00
b770511422 keyboard_layout: Fix leak 2020-02-03 14:59:14 +00:00
2e9b8581e7 variant: Fix leak 2020-02-03 14:53:27 +00:00
1cbc21ad11 variant: Fix double-free
gio::Settings::set_value takes over ownership of the Variant sometimes, but in other cases it doesn't. To prevent this being a problem, the custom Variant is made of the type that will never have its ownership taken.

This is not necessarily consistent with what gtk-rs authors intended.

In practice, the ownership is shared by refcounting, and after the Rust reference is dropped, one taken by Settings survives.
2020-02-03 14:53:24 +00:00
416bc6163e drawing: Generalized foreach_visible_button 2020-02-02 18:29:29 +00:00
40b79f6209 layout: Center views relative to each other and the layout bounds 2020-02-02 18:07:28 +00:00
782d80a007 row: Eliminate angle 2020-02-02 17:11:25 +00:00
a51d91eb53 emoji: Add more choices 2020-02-02 16:32:45 +00:00
687a512e5e layouts: Better accented uppercase in PL 2020-02-02 15:54:59 +00:00
500c23beec locking: Lock keys statelessly
Locking is not determined by button state any more, but rather based on the view active at the moment. If pressing/locking a key results in the current view being active, the key is active. If locking a key results in the current view, the unlock view is activated.
2020-02-02 15:41:47 +00:00
97d8dfe4cb locks: Draw based on current view 2020-02-02 14:45:33 +00:00
11213ba13a Merge branch '1.8.1' into 'master'
Release 1.8.1

See merge request Librem5/squeekboard!321
2020-01-31 14:23:03 +00:00
3d6c656c78 Merge branch 'pl' into 'master'
layouts: Add Polish layouts

See merge request Librem5/squeekboard!318
2020-01-31 10:40:06 +00:00
258dd9b926 Release 1.8.1 "Corona"
- Landscape layout doesn't crash
- CSS font is actually taken into account
- Failed start due to dbus is now communicated
- Better log messages
- Fixed Enter in numbers layout
- More consistent terminal layout
- Proper font sizes in terminal layout
2020-01-31 10:16:32 +00:00
b9db00c00c layouts: Add Polish layouts 2020-01-30 21:19:13 +01:00
7f32c5cf23 greek: Rename to gr which is used by gnome settings 2020-01-28 19:17:47 +00:00
a61019c4b7 translations: Translate builtin layouts 2020-01-28 19:15:39 +00:00
f4f11e5051 translations: Remove redundant ones
Language translations are all handled by gnome-desktop
2020-01-28 19:15:05 +00:00
cd252634bd logging: Use in merged functions 2020-01-28 12:45:45 +00:00
de8aaa1a47 Merge remote-tracking branch 'upstream/master' into text_input_enable 2020-01-28 12:39:42 +00:00
585ed5e97d input_method: Use for erasing 2020-01-23 15:39:40 +00:00
42cb73cd8c submission: Handle submitting strings 2020-01-14 18:33:47 +00:00
d1bc23e9d8 imservice: Add commit_string method 2020-01-14 18:17:12 +00:00
36 changed files with 743 additions and 198 deletions

14
Cargo.lock generated
View File

@ -2,10 +2,10 @@
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.7" version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -254,7 +254,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.3.0" version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -317,8 +317,8 @@ name = "regex"
version = "1.1.9" version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"aho-corasick 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", "aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -457,7 +457,7 @@ dependencies = [
] ]
[metadata] [metadata]
"checksum aho-corasick 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5f56c476256dc249def911d6f7580b5fc7e875895b5d7ee88f5d602208035744" "checksum aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811"
"checksum atk-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7017e53393e713212aed7aea336b6553be4927f58c37070a56c2fe3d107e489" "checksum atk-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7017e53393e713212aed7aea336b6553be4927f58c37070a56c2fe3d107e489"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "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-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd940f0d609699e343ef71c4af5f66423afbf30d666f796dabd8fd15229cf5b6"
@ -481,7 +481,7 @@ dependencies = [
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" "checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
"checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" "checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" "checksum memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53445de381a1f436797497c61d851644d0e8e88e6140f22872ad33a704933978"
"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
"checksum pango 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4c2cb169402a3eb1ba034a7cc7d95b8b1c106e9be5ba4be79a5a93dc1a2795f4" "checksum pango 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4c2cb169402a3eb1ba034a7cc7d95b8b1c106e9be5ba4be79a5a93dc1a2795f4"
"checksum pango-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6eb49268e69dd0c1da5d3001a61aac08e2e9d2bfbe4ae4b19b9963c998f6453" "checksum pango-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6eb49268e69dd0c1da5d3001a61aac08e2e9d2bfbe4ae4b19b9963c998f6453"

View File

@ -45,7 +45,7 @@ buttons:
BackSpace: BackSpace:
outline: "altline" outline: "altline"
icon: "edit-clear-symbolic" icon: "edit-clear-symbolic"
keysym: "BackSpace" action: "erase"
preferences: preferences:
action: "show_prefs" action: "show_prefs"
outline: "special" outline: "special"

View File

@ -45,7 +45,7 @@ buttons:
BackSpace: BackSpace:
outline: "altline" outline: "altline"
icon: "edit-clear-symbolic" icon: "edit-clear-symbolic"
keysym: "BackSpace" action: "erase"
preferences: preferences:
action: "show_prefs" action: "show_prefs"
outline: "special" outline: "special"

View File

@ -1,16 +1,80 @@
--- ---
outlines: outlines:
default: { width: 52, height: 52 } default: { width: 52, height: 52 }
altline: { width: 52, height: 52 } altline: { width: 40, height: 52 }
narrow: { width: 22, height: 52 }
views: views:
base: base:
- "😀 😁 😅 😂 😊 😇 🙃" - "😀 😁 😅 😂 😊 😇 🙃"
- "😍 😘 😋 😜 😎 🥳 😔" - "😍 😘 😋 😜 😎 🥳 😔"
- "😢 😭 😡 😱 🤔 😬 🙄" - "😢 😭 😡 😱 🤔 😬 🙄"
- "preferences 🤨 🤓 😴 🤢 🤮 😈" - "preferences blank 1 2 3 4 5 6 blank BackSpace"
two:
- "🤩 🤨 🤓 😴 🤢 🤮 😈"
- "💩 🙌 👏 👍 👎 👌 👋"
- "💪 🖕 🙏 💋 🤦‍♀️ 🤷‍♀️ 💃"
- "preferences blank 1 2 3 4 5 6 blank BackSpace"
three:
- "🐶 🐱 🐯 🙈 🐴 🦄 🌳"
- "🍀 🌹 💫 ⭐️ ✨ 💥 🔥"
- "🌈 ☀️ 🌤 🌧 ⛄️ ☂️ 🌊"
- "preferences blank 1 2 3 4 5 6 blank BackSpace"
four:
- "🍎 🍓 🍑 🍍 🍆 🥑 🥦"
- "🍕 🎂 🍫 🍿 🍻 🍾 🍽"
- "⚽️ 🏀 🏓 🏆 🎹 🎸 🎯"
- "preferences blank 1 2 3 4 5 6 blank BackSpace"
five:
- "🚗 🚌 🚲 🚄 🚂 ✈️ 🛰"
- "🚀 🛸 🚁 🚦 🏝 🏔 ⛺️"
- "🏠 🏢 🏥 🏛 🛤 🌅 🎇"
- "preferences blank 1 2 3 4 5 6 blank BackSpace"
six:
- "⌚️ 📱 💻 🖥 🖨 🕹 ✉️"
- "📞 ☎️ ⏰ ⏳ 📈 📉 📌"
- "🎁 ❤️ 💕 💯 ✅ ❎ 📢"
- "preferences blank 1 2 3 4 5 6 blank BackSpace"
buttons: buttons:
1:
action:
set_view: "base"
outline: "altline"
label: "1"
2:
action:
set_view: "two"
outline: "altline"
label: "2"
3:
action:
set_view: "three"
outline: "altline"
label: "3"
4:
action:
set_view: "four"
outline: "altline"
label: "4"
5:
action:
set_view: "five"
outline: "altline"
label: "5"
6:
action:
set_view: "six"
outline: "altline"
label: "6"
preferences: preferences:
action: "show_prefs" action: "show_prefs"
outline: "altline" outline: "altline"
icon: "keyboard-mode-symbolic" icon: "keyboard-mode-symbolic"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
keysym: BackSpace
blank:
outline: "narrow"
text: ""

View File

@ -44,7 +44,7 @@ buttons:
BackSpace: BackSpace:
outline: "altline" outline: "altline"
icon: "edit-clear-symbolic" icon: "edit-clear-symbolic"
keysym: "BackSpace" action: "erase"
preferences: preferences:
action: "show_prefs" action: "show_prefs"
outline: "default" outline: "default"

View File

@ -39,7 +39,7 @@ buttons:
BackSpace: BackSpace:
outline: "altline" outline: "altline"
icon: "edit-clear-symbolic" icon: "edit-clear-symbolic"
keysym: "BackSpace" action: "erase"
preferences: preferences:
action: "show_prefs" action: "show_prefs"
outline: "altline" outline: "altline"

View File

@ -46,7 +46,7 @@ buttons:
BackSpace: BackSpace:
outline: "altline" outline: "altline"
icon: "edit-clear-symbolic" icon: "edit-clear-symbolic"
keysym: "BackSpace" action: "erase"
preferences: preferences:
action: "show_prefs" action: "show_prefs"
outline: "altline" outline: "altline"

View File

@ -46,7 +46,7 @@ buttons:
BackSpace: BackSpace:
outline: "altline" outline: "altline"
icon: "edit-clear-symbolic" icon: "edit-clear-symbolic"
keysym: "BackSpace" action: "erase"
preferences: preferences:
action: "show_prefs" action: "show_prefs"
outline: "default" outline: "default"

View File

@ -195,7 +195,7 @@ buttons:
BackSpace: BackSpace:
outline: "wide" outline: "wide"
icon: "edit-clear-symbolic" icon: "edit-clear-symbolic"
keysym: "BackSpace" action: erase
Return: Return:
outline: "wide" outline: "wide"
icon: "key-enter" icon: "key-enter"

View File

@ -195,7 +195,7 @@ buttons:
BackSpace: BackSpace:
outline: "wide" outline: "wide"
icon: "edit-clear-symbolic" icon: "edit-clear-symbolic"
keysym: "BackSpace" action: erase
Return: Return:
outline: "wide" outline: "wide"
icon: "key-enter" icon: "key-enter"

View File

@ -39,7 +39,7 @@ buttons:
BackSpace: BackSpace:
outline: "altline" outline: "altline"
icon: "edit-clear-symbolic" icon: "edit-clear-symbolic"
keysym: "BackSpace" action: erase
preferences: preferences:
action: "show_prefs" action: "show_prefs"
outline: "altline" outline: "altline"

View File

@ -16,7 +16,7 @@ buttons:
BackSpace: BackSpace:
outline: "altline" outline: "altline"
icon: "edit-clear-symbolic" icon: "edit-clear-symbolic"
keysym: "BackSpace" action: erase
space: space:
outline: spaceline outline: spaceline
text: " " text: " "

110
data/keyboards/pl.yaml Normal file
View File

@ -0,0 +1,110 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 59, height: 52 }
spaceline: { width: 140, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers preferences space show_accents 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 show_upper_accents Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space period Return"
accents:
- "q w ę r t y u i ó p"
- "ą ś d f g h j k ł"
- "accents_show_upper ż ź ć v b ń m BackSpace"
- "show_numbers preferences space show_accents Return"
upper_accents:
- "Q W Ę R T Y U I Ó P"
- "Ą Ś D F G H J K Ł"
- "accents_show_upper Ż Ź Ć V B Ń M BackSpace"
- "show_numbers preferences space show_upper_accents Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
accents_show_upper:
action:
locking:
lock_view: "upper_accents"
unlock_view: "accents"
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: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "ABC"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_accents:
action:
locking:
lock_view: "accents"
unlock_view: "base"
outline: "altline"
label: "ąę"
show_upper_accents:
action:
locking:
lock_view: "upper_accents"
unlock_view: "upper"
outline: "altline"
label: "ĄĘ"
period:
outline: "altline"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

102
data/keyboards/pl_wide.yaml Normal file
View File

@ -0,0 +1,102 @@
---
outlines:
default: { width: 54, height: 42 }
altline: { width: 81, height: 42 }
wide: { width: 100, height: 42 }
spaceline: { width: 206, height: 42 }
special: { width: 54, height: 42 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers preferences space show_accents 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 show_upper_accents Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space period Return"
accents:
- "q w ę r t y u i ó p"
- "ą ś d f g h j k ł"
- "Shift_L ż ź ć v b ń m BackSpace"
- "show_numbers preferences space show_accents Return"
upper_accents:
- "Q W Ę R T Y U I Ó P"
- "Ą Ś D F G H J K Ł"
- "Shift_L Ż Ź Ć V B Ń M BackSpace"
- "show_numbers preferences space show_upper_accents 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: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "ABC"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_accents:
action:
locking:
lock_view: "accents"
unlock_view: "base"
outline: "altline"
label: "ąę"
show_upper_accents:
action:
locking:
lock_view: "upper_accents"
unlock_view: "upper"
outline: "altline"
label: "ĄĘ"
period:
outline: "altline"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -39,7 +39,7 @@ buttons:
BackSpace: BackSpace:
outline: "altline" outline: "altline"
icon: "edit-clear-symbolic" icon: "edit-clear-symbolic"
keysym: "BackSpace" action: erase
preferences: preferences:
action: "show_prefs" action: "show_prefs"
outline: "altline" outline: "altline"

View File

@ -20,13 +20,13 @@ views:
- "show_numbers preferences space show_actions Return" - "show_numbers preferences space show_actions Return"
numbers: numbers:
- "1 2 3 4 5 6 7 8 9 0" - "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )" - "* # $ / & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace" - "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space period Return" - "show_letters preferences space period Return"
symbols: symbols:
- "~ ` | · √ π τ ÷ × ¶" - "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }" - "© ® £ € ¥ ^ ° @ { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace" - "show_numbers_from_symbols \\ % < > = [ ] BackSpace"
- "show_letters preferences space period Return" - "show_letters preferences space period Return"
actions: actions:
- "F1 F2 F3 F4 F5 F6" - "F1 F2 F3 F4 F5 F6"
@ -45,7 +45,7 @@ buttons:
BackSpace: BackSpace:
outline: "altline" outline: "altline"
icon: "edit-clear-symbolic" icon: "edit-clear-symbolic"
keysym: "BackSpace" action: erase
preferences: preferences:
action: "show_prefs" action: "show_prefs"
outline: "special" outline: "special"
@ -69,14 +69,14 @@ buttons:
action: action:
set_view: "symbols" set_view: "symbols"
outline: "altline" outline: "altline"
label: "*/=" label: "τ=\\"
show_actions: show_actions:
action: action:
set_view: "actions" set_view: "actions"
outline: "altline" outline: "altline"
label: ">_" label: ">_"
period: period:
outline: "special" outline: "altline"
text: "." text: "."
space: space:
outline: "spaceline" outline: "spaceline"

View File

@ -39,9 +39,9 @@ buttons:
BackSpace: BackSpace:
outline: "altline" outline: "altline"
icon: "edit-clear-symbolic" icon: "edit-clear-symbolic"
keysym: "BackSpace" action: erase
preferences: preferences:
action: "show_prefs" action: show_prefs
outline: "special" outline: "special"
icon: "keyboard-mode-symbolic" icon: "keyboard-mode-symbolic"
show_numbers: show_numbers:

View File

@ -39,7 +39,7 @@ buttons:
BackSpace: BackSpace:
outline: "altline" outline: "altline"
icon: "edit-clear-symbolic" icon: "edit-clear-symbolic"
keysym: "BackSpace" action: "erase"
preferences: preferences:
action: "show_prefs" action: "show_prefs"
outline: "special" outline: "special"

View File

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

View File

@ -1,10 +1,2 @@
us English (US) emoji Emoji
de German terminal Terminal
el Greek
es Spanish
fi Finnish
it Italian
jp+kana Japanese (kana)
no Norwegian
se Swedish

View File

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

View File

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

37
debian/changelog vendored
View File

@ -1,3 +1,40 @@
squeekboard (1.9.0) amber-phone; urgency=medium
[ Dorota Czaplejewicz ]
* imservice: Add commit_string method
* submission: Handle submitting strings
* input_method: Use for erasing
* logging: Use in merged functions
* translations: Remove redundant ones
* translations: Translate builtin layouts
* greek: Rename to gr which is used by gnome settings
[ Sebastian Krzyszkowiak ]
* layouts: Add Polish layouts
[ Dorota Czaplejewicz ]
* locks: Draw based on current view
* locking: Lock keys statelessly
* layouts: Better accented uppercase in PL
* emoji: Add more choices
* row: Eliminate angle
* layout: Center views relative to each other and the layout bounds
* drawing: Generalized foreach_visible_button
* variant: Fix double-free
* variant: Fix leak
* keyboard_layout: Fix leak
* layout: Improve scoping of locked variable
* terminal: Make */ easier to reach
[ Sebastian Krzyszkowiak ]
* layouts: terminal: Use altline outline for dot key
[ Dorota Czaplejewicz ]
* text input: Disable erasing
* cargo: Update deps
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Wed, 19 Feb 2020 14:32:39 +0000
squeekboard (1.8.1) amber-phone; urgency=medium squeekboard (1.8.1) amber-phone; urgency=medium
[ Dorota Czaplejewicz ] [ Dorota Czaplejewicz ]

View File

@ -116,6 +116,7 @@ settings_get_layout(GSettings *settings, char **type, char **layout)
GVariant *inputs = g_settings_get_value(settings, "sources"); GVariant *inputs = g_settings_get_value(settings, "sources");
// current layout is always first // current layout is always first
g_variant_get_child(inputs, 0, "(ss)", type, layout); g_variant_get_child(inputs, 0, "(ss)", type, layout);
g_variant_unref(inputs);
} }
void void
@ -139,9 +140,11 @@ eekboard_context_service_update_layout(EekboardContextService *context, enum squ
switch (priv->purpose) { switch (priv->purpose) {
case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER: case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER:
case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE: case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE:
g_free(keyboard_layout);
keyboard_layout = g_strdup("number"); keyboard_layout = g_strdup("number");
break; break;
case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL: case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL:
g_free(keyboard_layout);
keyboard_layout = g_strdup("terminal"); keyboard_layout = g_strdup("terminal");
break; break;
default: default:

View File

@ -31,10 +31,29 @@ pub enum Action {
SetModifier(Modifier), SetModifier(Modifier),
/// Submit some text /// Submit some text
Submit { Submit {
/// Text to submit with input-method /// Text to submit with input-method.
/// If None, then keys are to be submitted instead.
text: Option<CString>, text: Option<CString>,
/// The key events this symbol submits when submitting text is not possible /// The key events this symbol submits when submitting text is not possible
keys: Vec<KeySym>, keys: Vec<KeySym>,
}, },
/// Erase a position behind the cursor
Erase,
ShowPreferences, ShowPreferences,
} }
impl Action {
pub fn is_locked(&self, view_name: &str) -> bool {
match self {
Action::LockView { lock, unlock: _ } => lock == view_name,
_ => false,
}
}
pub fn is_active(&self, view_name: &str) -> bool {
match self {
Action::SetView(view) => view == view_name,
Action::LockView { lock, unlock: _ } => lock == view_name,
_ => false,
}
}
}

View File

@ -15,6 +15,7 @@ use std::vec::Vec;
use xkbcommon::xkb; use xkbcommon::xkb;
use ::action;
use ::keyboard::{ use ::keyboard::{
KeyState, PressType, KeyState, PressType,
generate_keymap, generate_keycodes, FormattingError generate_keymap, generate_keycodes, FormattingError
@ -264,6 +265,9 @@ enum Action {
SetView(String), SetView(String),
#[serde(rename="show_prefs")] #[serde(rename="show_prefs")]
ShowPrefs, ShowPrefs,
/// Remove last character
#[serde(rename="erase")]
Erase,
} }
#[derive(Debug, Clone, Deserialize, PartialEq)] #[derive(Debug, Clone, Deserialize, PartialEq)]
@ -386,13 +390,16 @@ impl Layout {
) )
}).collect() }).collect()
}, },
action::Action::Erase => vec![
*keymap.get("BackSpace")
.expect(&format!("BackSpace missing from keymap")),
],
_ => Vec::new(), _ => Vec::new(),
}; };
( (
name.into(), name.into(),
KeyState { KeyState {
pressed: PressType::Released, pressed: PressType::Released,
locked: false,
keycodes, keycodes,
action, action,
} }
@ -417,8 +424,8 @@ impl Layout {
)} )}
); );
let views = HashMap::from_iter( let views: Vec<_> = self.views.iter()
self.views.iter().map(|(name, view)| { .map(|(name, view)| {
let rows = view.iter().map(|row| { let rows = view.iter().map(|row| {
let buttons = row.split_ascii_whitespace() let buttons = row.split_ascii_whitespace()
.map(|name| { .map(|name| {
@ -432,8 +439,7 @@ impl Layout {
&mut warning_handler, &mut warning_handler,
)) ))
}); });
::layout::Row { layout::Row {
angle: 0,
buttons: add_offsets( buttons: add_offsets(
buttons, buttons,
|button| button.size.width, |button| button.size.width,
@ -446,8 +452,25 @@ impl Layout {
name.clone(), name.clone(),
layout::View::new(rows) layout::View::new(rows)
) )
}) }).collect();
);
// Center views on the same point.
let views = {
let total_size = layout::View::calculate_super_size(
views.iter().map(|(_name, view)| view).collect()
);
HashMap::from_iter(views.into_iter().map(|(name, view)| (
name,
(
layout::c::Point {
x: (total_size.width - view.get_width()) / 2.0,
y: (total_size.height - view.get_height()) / 2.0,
},
view,
),
)))
};
( (
Ok(::layout::LayoutData { Ok(::layout::LayoutData {
@ -558,6 +581,7 @@ fn create_action<H: logging::Handler>(
SubmitData::Action( SubmitData::Action(
Action::ShowPrefs Action::ShowPrefs
) => ::action::Action::ShowPreferences, ) => ::action::Action::ShowPreferences,
SubmitData::Action(Action::Erase) => action::Action::Erase,
SubmitData::Keysym(keysym) => ::action::Action::Submit { SubmitData::Keysym(keysym) => ::action::Action::Submit {
text: None, text: None,
keys: vec!(::action::KeySym( keys: vec!(::action::KeySym(
@ -589,7 +613,7 @@ fn create_action<H: logging::Handler>(
false => format!("U{:04X}", codepoint as u32), false => format!("U{:04X}", codepoint as u32),
}) })
}).collect(), }).collect(),
} },
} }
} }
@ -743,7 +767,7 @@ mod tests {
.build(ProblemPanic).0 .build(ProblemPanic).0
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
out.views["base"] out.views["base"].1
.get_rows()[0].1 .get_rows()[0].1
.buttons[0].1 .buttons[0].1
.label, .label,
@ -758,7 +782,7 @@ mod tests {
.build(ProblemPanic).0 .build(ProblemPanic).0
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
out.views["base"] out.views["base"].1
.get_rows()[0].1 .get_rows()[0].1
.buttons[0].1 .buttons[0].1
.label, .label,
@ -774,7 +798,7 @@ mod tests {
.build(ProblemPanic).0 .build(ProblemPanic).0
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
out.views["base"] out.views["base"].1
.get_rows()[0].1 .get_rows()[0].1
.buttons[0].1 .buttons[0].1
.state.borrow() .state.borrow()

View File

@ -37,6 +37,7 @@ mod c {
); );
} }
/// Draws all buttons that are not in the base state
#[no_mangle] #[no_mangle]
pub extern "C" pub extern "C"
fn squeek_layout_draw_all_changed( fn squeek_layout_draw_all_changed(
@ -47,20 +48,18 @@ mod c {
let layout = unsafe { &mut *layout }; let layout = unsafe { &mut *layout };
let cr = unsafe { cairo::Context::from_raw_none(cr) }; let cr = unsafe { cairo::Context::from_raw_none(cr) };
let view = layout.get_current_view(); layout.foreach_visible_button(|offset, button| {
for (row_offset, row) in &view.get_rows() { let state = RefCell::borrow(&button.state).clone();
for (x_offset, button) in &row.buttons { let locked = state.action.is_active(&layout.current_view);
let state = RefCell::borrow(&button.state).clone(); if state.pressed == keyboard::PressType::Pressed || locked {
if state.pressed == keyboard::PressType::Pressed || state.locked { render_button_at_position(
render_button_at_position( renderer, &cr,
renderer, &cr, offset,
row_offset + Point { x: *x_offset, y: 0.0 }, button.as_ref(),
button.as_ref(), state.pressed, locked,
state.pressed, state.locked, );
);
}
} }
} })
} }
#[no_mangle] #[no_mangle]
@ -72,17 +71,15 @@ mod c {
) { ) {
let layout = unsafe { &mut *layout }; let layout = unsafe { &mut *layout };
let cr = unsafe { cairo::Context::from_raw_none(cr) }; let cr = unsafe { cairo::Context::from_raw_none(cr) };
let view = layout.get_current_view();
for (row_offset, row) in &view.get_rows() { layout.foreach_visible_button(|offset, button| {
for (x_offset, button) in &row.buttons { render_button_at_position(
render_button_at_position( renderer, &cr,
renderer, &cr, offset,
row_offset + Point { x: *x_offset, y: 0.0 }, button.as_ref(),
button.as_ref(), keyboard::PressType::Released, false,
keyboard::PressType::Released, false, );
); })
}
}
} }
} }

View File

@ -49,6 +49,23 @@ void imservice_connect_listeners(struct zwp_input_method_v2 *im, struct imservic
zwp_input_method_v2_add_listener(im, &input_method_listener, imservice); zwp_input_method_v2_add_listener(im, &input_method_listener, imservice);
} }
void
eek_input_method_commit_string(struct zwp_input_method_v2 *zwp_input_method_v2, const char *text)
{
zwp_input_method_v2_commit_string(zwp_input_method_v2, text);
}
void
eek_input_method_delete_surrounding_text(struct zwp_input_method_v2 *zwp_input_method_v2, uint32_t before_length, uint32_t after_length) {
zwp_input_method_v2_delete_surrounding_text(zwp_input_method_v2, before_length, after_length);
};
void
eek_input_method_commit(struct zwp_input_method_v2 *zwp_input_method_v2, uint32_t serial)
{
zwp_input_method_v2_commit(zwp_input_method_v2, serial);
}
/// Declared explicitly because _destroy is inline, /// Declared explicitly because _destroy is inline,
/// making it unavailable in Rust /// making it unavailable in Rust
void imservice_destroy_im(struct zwp_input_method_v2 *im) { void imservice_destroy_im(struct zwp_input_method_v2 *im) {

View File

@ -1,3 +1,8 @@
/*! Manages zwp_input_method_v2 protocol.
*
* Library module.
*/
use std::boxed::Box; use std::boxed::Box;
use std::ffi::CString; use std::ffi::CString;
use std::fmt; use std::fmt;
@ -32,6 +37,9 @@ pub mod c {
fn imservice_destroy_im(im: *mut c::InputMethod); fn imservice_destroy_im(im: *mut c::InputMethod);
#[allow(improper_ctypes)] // IMService will never be dereferenced in C #[allow(improper_ctypes)] // IMService will never be dereferenced in C
pub fn imservice_connect_listeners(im: *mut InputMethod, imservice: *const IMService); pub fn imservice_connect_listeners(im: *mut InputMethod, imservice: *const IMService);
pub fn eek_input_method_commit_string(im: *mut InputMethod, text: *const c_char);
pub fn eek_input_method_delete_surrounding_text(im: *mut InputMethod, before: u32, after: u32);
pub fn eek_input_method_commit(im: *mut InputMethod, serial: u32);
fn eekboard_context_service_set_hint_purpose(state: *const StateManager, hint: u32, purpose: u32); fn eekboard_context_service_set_hint_purpose(state: *const StateManager, hint: u32, purpose: u32);
fn server_context_service_show_keyboard(imservice: *const UIManager); fn server_context_service_show_keyboard(imservice: *const UIManager);
fn server_context_service_hide_keyboard(imservice: *const UIManager); fn server_context_service_hide_keyboard(imservice: *const UIManager);
@ -328,7 +336,7 @@ impl Default for IMProtocolState {
pub struct IMService { pub struct IMService {
/// Owned reference (still created and destroyed in C) /// Owned reference (still created and destroyed in C)
pub im: *const c::InputMethod, pub im: *mut c::InputMethod,
/// Unowned reference. Be careful, it's shared with C at large /// Unowned reference. Be careful, it's shared with C at large
state_manager: *const c::StateManager, state_manager: *const c::StateManager,
/// Unowned reference. Be careful, it's shared with C at large /// Unowned reference. Be careful, it's shared with C at large
@ -340,6 +348,11 @@ pub struct IMService {
serial: Wrapping<u32>, serial: Wrapping<u32>,
} }
pub enum SubmitError {
/// The input method had not been activated
NotActive,
}
impl IMService { impl IMService {
pub fn new( pub fn new(
im: *mut c::InputMethod, im: *mut c::InputMethod,
@ -364,4 +377,51 @@ impl IMService {
} }
imservice imservice
} }
pub fn commit_string(&self, text: &CString) -> Result<(), SubmitError> {
match self.current.active {
true => {
unsafe {
c::eek_input_method_commit_string(self.im, text.as_ptr())
}
Ok(())
},
false => Err(SubmitError::NotActive),
}
}
pub fn delete_surrounding_text(
&self,
before: u32, after: u32,
) -> Result<(), SubmitError> {
match self.current.active {
true => {
unsafe {
c::eek_input_method_delete_surrounding_text(
self.im,
before, after,
)
}
Ok(())
},
false => Err(SubmitError::NotActive),
}
}
pub fn commit(&mut self) -> Result<(), SubmitError> {
match self.current.active {
true => {
unsafe {
c::eek_input_method_commit(self.im, self.serial.0)
}
self.serial += Wrapping(1u32);
Ok(())
},
false => Err(SubmitError::NotActive),
}
}
pub fn is_active(&self) -> bool {
self.current.active
}
} }

View File

@ -1,14 +1,17 @@
/*! State of the emulated keyboard and keys. /*! State of the emulated keyboard and keys.
* Regards the keyboard as if it was composed of switches. */ * Regards the keyboard as if it was composed of switches. */
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::io; use std::io;
use std::rc::Rc;
use std::string::FromUtf8Error; use std::string::FromUtf8Error;
use ::action::Action; use ::action::Action;
use ::logging; use ::logging;
// Traits
use std::io::Write; use std::io::Write;
use std::iter::{ FromIterator, IntoIterator }; use std::iter::{ FromIterator, IntoIterator };
@ -20,10 +23,14 @@ pub enum PressType {
pub type KeyCode = u32; pub type KeyCode = u32;
/// When the submitted actions of keys need to be tracked,
/// they need a stable, comparable ID
#[derive(PartialEq)]
pub struct KeyStateId(*const KeyState);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct KeyState { pub struct KeyState {
pub pressed: PressType, pub pressed: PressType,
pub locked: bool,
/// A cache of raw keycodes derived from Action::Sumbit given a keymap /// A cache of raw keycodes derived from Action::Sumbit given a keymap
pub keycodes: Vec<KeyCode>, pub keycodes: Vec<KeyCode>,
/// Static description of what the key does when pressed or released /// Static description of what the key does when pressed or released
@ -31,17 +38,6 @@ pub struct KeyState {
} }
impl KeyState { impl KeyState {
#[must_use]
pub fn into_activated(self) -> KeyState {
match self.action {
Action::LockView { lock: _, unlock: _ } => KeyState {
locked: self.locked ^ true,
..self
},
_ => self,
}
}
#[must_use] #[must_use]
pub fn into_released(self) -> KeyState { pub fn into_released(self) -> KeyState {
KeyState { KeyState {
@ -49,6 +45,12 @@ impl KeyState {
..self ..self
} }
} }
/// KeyStates instances are the unique identifiers of pressed keys,
/// and the actions submitted with them.
pub fn get_id(keystate: &Rc<RefCell<KeyState>>) -> KeyStateId {
KeyStateId(keystate.as_ptr() as *const KeyState)
}
} }
/// Sorts an iterator by converting it to a Vector and back /// Sorts an iterator by converting it to a Vector and back
@ -66,9 +68,10 @@ fn sorted<'a, I: Iterator<Item=&'a str>>(
pub fn generate_keycodes<'a, C: IntoIterator<Item=&'a str>>( pub fn generate_keycodes<'a, C: IntoIterator<Item=&'a str>>(
key_names: C key_names: C
) -> HashMap<String, u32> { ) -> HashMap<String, u32> {
let special_keysyms = ["BackSpace", "Return"].iter().map(|&s| s);
HashMap::from_iter( HashMap::from_iter(
// sort to remove a source of indeterminism in keycode assignment // sort to remove a source of indeterminism in keycode assignment
sorted(key_names.into_iter()) sorted(key_names.into_iter().chain(special_keysyms))
.map(|name| String::from(name)) .map(|name| String::from(name))
.zip(9..) .zip(9..)
) )
@ -95,7 +98,10 @@ impl From<io::Error> for FormattingError {
} }
} }
/// Generates a de-facto single level keymap. TODO: actually drop second level /// Generates a de-facto single level keymap.
// TODO: don't rely on keys and their order,
// but rather on what keysyms and keycodes are in use.
// Iterating actions makes it hard to deduplicate keysyms.
pub fn generate_keymap( pub fn generate_keymap(
keystates: &HashMap::<String, KeyState> keystates: &HashMap::<String, KeyState>
) -> Result<String, FormattingError> { ) -> Result<String, FormattingError> {
@ -110,22 +116,40 @@ pub fn generate_keymap(
)?; )?;
for (name, state) in keystates.iter() { for (name, state) in keystates.iter() {
if let Action::Submit { text: _, keys } = &state.action { match &state.action {
if let 0 = keys.len() { Action::Submit { text: _, keys } => {
log_print!( if let 0 = keys.len() {
logging::Level::Warning, log_print!(
"Key {} has no keysyms", name, logging::Level::Warning,
); "Key {} has no keysyms", name,
}; );
for (named_keysym, keycode) in keys.iter().zip(&state.keycodes) { };
for (named_keysym, keycode) in keys.iter().zip(&state.keycodes) {
write!(
buf,
"
<{}> = {};",
named_keysym.0,
keycode,
)?;
}
},
Action::Erase => {
let mut keycodes = state.keycodes.iter();
write!( write!(
buf, buf,
" "
<{}> = {};", <BackSpace> = {};",
named_keysym.0, keycodes.next().expect("Erase key has no keycode"),
keycode,
)?; )?;
} if let Some(_) = keycodes.next() {
log_print!(
logging::Level::Bug,
"Erase key has multiple keycodes",
);
}
},
_ => {},
} }
} }
@ -137,7 +161,9 @@ pub fn generate_keymap(
xkb_symbols \"squeekboard\" {{ xkb_symbols \"squeekboard\" {{
name[Group1] = \"Letters\"; name[Group1] = \"Letters\";
name[Group2] = \"Numbers/Symbols\";" name[Group2] = \"Numbers/Symbols\";
key <BackSpace> {{ [ BackSpace ] }};"
)?; )?;
for (name, state) in keystates.iter() { for (name, state) in keystates.iter() {
@ -195,7 +221,6 @@ mod tests {
keys: vec!(KeySym("a".into()), KeySym("c".into())), keys: vec!(KeySym("a".into()), KeySym("c".into())),
}, },
keycodes: vec!(9, 10), keycodes: vec!(9, 10),
locked: false,
pressed: PressType::Released, pressed: PressType::Released,
}, },
}).unwrap(); }).unwrap();

View File

@ -329,11 +329,8 @@ pub mod c {
Point { x: x_widget, y: y_widget } Point { x: x_widget, y: y_widget }
); );
let state = { let state = layout.find_button_by_position(point)
let view = layout.get_current_view(); .map(|place| place.button.state.clone());
view.find_button_by_position(point)
.map(|place| place.button.state.clone())
};
if let Some(state) = state { if let Some(state) = state {
seat::handle_press_key( seat::handle_press_key(
@ -374,8 +371,7 @@ pub mod c {
let pressed = layout.pressed_keys.clone(); let pressed = layout.pressed_keys.clone();
let button_info = { let button_info = {
let view = layout.get_current_view(); let place = layout.find_button_by_position(point);
let place = view.find_button_by_position(point);
place.map(|place| {( place.map(|place| {(
place.button.state.clone(), place.button.state.clone(),
place.button.clone(), place.button.clone(),
@ -486,8 +482,6 @@ pub struct Button {
pub struct Row { pub struct Row {
/// Buttons together with their offset from the left /// Buttons together with their offset from the left
pub buttons: Vec<(f64, Box<Button>)>, pub buttons: Vec<(f64, Box<Button>)>,
/// Angle is not really used anywhere...
pub angle: i32,
} }
impl Row { impl Row {
@ -554,14 +548,14 @@ impl View {
}) })
} }
fn get_width(&self) -> f64 { pub fn get_width(&self) -> f64 {
// No need to call `get_rows()`, // No need to call `get_rows()`,
// as the biggest row is the most far reaching in both directions // as the biggest row is the most far reaching in both directions
// because they are all centered. // because they are all centered.
find_max_double(self.rows.iter(), |(_offset, row)| row.get_width()) find_max_double(self.rows.iter(), |(_offset, row)| row.get_width())
} }
fn get_height(&self) -> f64 { pub fn get_height(&self) -> f64 {
self.rows.iter().next_back() self.rows.iter().next_back()
.map(|(y_offset, row)| row.get_height() + y_offset) .map(|(y_offset, row)| row.get_height() + y_offset)
.unwrap_or(0.0) .unwrap_or(0.0)
@ -578,6 +572,21 @@ impl View {
row, row,
)}).collect() )}).collect()
} }
/// Returns a size which contains all the views
/// if they are all centered on the same point.
pub fn calculate_super_size(views: Vec<&View>) -> Size {
Size {
height: find_max_double(
views.iter(),
|view| view.get_height(),
),
width: find_max_double(
views.iter(),
|view| view.get_width(),
),
}
}
} }
/// The physical characteristic of layout for the purpose of styling /// The physical characteristic of layout for the purpose of styling
@ -605,7 +614,8 @@ pub struct Layout {
// Views own the actual buttons which have state // Views own the actual buttons which have state
// Maybe they should own UI only, // Maybe they should own UI only,
// and keys should be owned by a dedicated non-UI-State? // and keys should be owned by a dedicated non-UI-State?
pub views: HashMap<String, View>, /// Point is the offset within the layout
pub views: HashMap<String, (c::Point, View)>,
// Non-UI stuff // Non-UI stuff
/// xkb keymap applicable to the contained keys. Unchangeable /// xkb keymap applicable to the contained keys. Unchangeable
@ -619,12 +629,12 @@ pub struct Layout {
// When the list tracks actual location, // When the list tracks actual location,
// it becomes possible to place popovers and other UI accurately. // it becomes possible to place popovers and other UI accurately.
pub pressed_keys: HashSet<::util::Pointer<RefCell<KeyState>>>, pub pressed_keys: HashSet<::util::Pointer<RefCell<KeyState>>>,
pub locked_keys: HashSet<::util::Pointer<RefCell<KeyState>>>,
} }
/// A builder structure for picking up layout data from storage /// A builder structure for picking up layout data from storage
pub struct LayoutData { pub struct LayoutData {
pub views: HashMap<String, View>, /// Point is the offset within layout
pub views: HashMap<String, (c::Point, View)>,
pub keymap_str: CString, pub keymap_str: CString,
pub margins: Margins, pub margins: Margins,
} }
@ -650,13 +660,17 @@ impl Layout {
views: data.views, views: data.views,
keymap_str: data.keymap_str, keymap_str: data.keymap_str,
pressed_keys: HashSet::new(), pressed_keys: HashSet::new(),
locked_keys: HashSet::new(),
margins: data.margins, margins: data.margins,
} }
} }
pub fn get_current_view_position(&self) -> &(c::Point, View) {
&self.views
.get(&self.current_view).expect("Selected nonexistent view")
}
pub fn get_current_view(&self) -> &View { pub fn get_current_view(&self) -> &View {
self.views.get(&self.current_view).expect("Selected nonexistent view") &self.views.get(&self.current_view).expect("Selected nonexistent view").1
} }
fn set_view(&mut self, view: String) -> Result<(), NoSuchView> { fn set_view(&mut self, view: String) -> Result<(), NoSuchView> {
@ -670,16 +684,9 @@ impl Layout {
/// Calculates size without margins /// Calculates size without margins
fn calculate_inner_size(&self) -> Size { fn calculate_inner_size(&self) -> Size {
Size { View::calculate_super_size(
height: find_max_double( self.views.iter().map(|(_, (_offset, v))| v).collect()
self.views.iter(), )
|(_name, view)| view.get_height(),
),
width: find_max_double(
self.views.iter(),
|(_name, view)| view.get_width(),
),
}
} }
/// Size including margins /// Size including margins
@ -714,6 +721,42 @@ impl Layout {
scale: 1.0, scale: 1.0,
}) })
} }
fn find_button_by_position(&self, point: c::Point) -> Option<ButtonPlace> {
let (offset, layout) = self.get_current_view_position();
layout.find_button_by_position(point - offset)
}
pub fn foreach_visible_button<F>(&self, mut f: F)
where F: FnMut(c::Point, &Box<Button>)
{
let (view_offset, view) = self.get_current_view_position();
for (row_offset, row) in &view.get_rows() {
for (x_offset, button) in &row.buttons {
let offset = view_offset
+ row_offset.clone()
+ c::Point { x: *x_offset, y: 0.0 };
f(offset, button);
}
}
}
pub fn get_locked_keys(&self) -> Vec<Rc<RefCell<KeyState>>> {
let mut out = Vec::new();
let view = self.get_current_view();
for (_, row) in &view.get_rows() {
for (_, button) in &row.buttons {
let locked = {
let state = RefCell::borrow(&button.state).clone();
state.action.is_locked(&self.current_view)
};
if locked {
out.push(button.state.clone());
}
}
}
out
}
} }
mod procedures { mod procedures {
@ -765,7 +808,6 @@ mod procedures {
let row = Row { let row = Row {
buttons: vec!((0.1, button)), buttons: vec!((0.1, button)),
angle: 0,
}; };
let view = View { let view = View {
@ -841,9 +883,9 @@ mod seat {
#[must_use] #[must_use]
fn unstick_locks(layout: &mut Layout) -> ViewChange { fn unstick_locks(layout: &mut Layout) -> ViewChange {
let mut new_view = None; let mut new_view = None;
for key in layout.locked_keys.clone() { for key in layout.get_locked_keys().clone() {
let key: &Rc<RefCell<KeyState>> = key.borrow(); let key: &Rc<RefCell<KeyState>> = key.borrow();
let mut key = RefCell::borrow_mut(key); let key = RefCell::borrow(key);
match &key.action { match &key.action {
Action::LockView { lock: _, unlock: view } => { Action::LockView { lock: _, unlock: view } => {
new_view = Some(view.clone()); new_view = Some(view.clone());
@ -854,7 +896,6 @@ mod seat {
a, a,
), ),
}; };
key.locked = false;
} }
ViewChange { ViewChange {
@ -876,11 +917,7 @@ mod seat {
); );
} }
let mut key = rckey.borrow_mut(); let mut key = rckey.borrow_mut();
submission.virtual_keyboard.switch( submission.handle_press(&key, KeyState::get_id(rckey), time);
&key.keycodes,
PressType::Pressed,
time,
);
key.pressed = PressType::Pressed; key.pressed = PressType::Pressed;
} }
@ -899,32 +936,25 @@ mod seat {
// update // update
let key = key.into_released(); let key = key.into_released();
let key = match action {
Action::LockView { lock: _, unlock: _ } => key.into_activated(),
_ => key,
};
// process changes // process changes
match action { match action {
Action::Submit { text: _, keys: _ } => { Action::Submit { text: _, keys: _ }
| Action::Erase
=> {
unstick_locks(layout).apply(); unstick_locks(layout).apply();
submission.virtual_keyboard.switch( submission.handle_release(KeyState::get_id(rckey), time);
&key.keycodes,
PressType::Released,
time,
);
}, },
Action::SetView(view) => { Action::SetView(view) => {
try_set_view(layout, view) try_set_view(layout, view)
}, },
Action::LockView { lock, unlock } => { Action::LockView { lock, unlock } => {
// The button that triggered this will be in the right state let gets_locked = !key.action.is_locked(&layout.current_view);
// due to commit at the end.
unstick_locks(layout) unstick_locks(layout)
// It doesn't matter what the resulting view should be, // It doesn't matter what the resulting view should be,
// it's getting changed anyway. // it's getting changed anyway.
.choose_view( .choose_view(
match key.locked { match gets_locked {
true => lock.clone(), true => lock.clone(),
false => unlock.clone(), false => unlock.clone(),
} }
@ -966,11 +996,6 @@ mod seat {
let pointer = ::util::Pointer(rckey.clone()); let pointer = ::util::Pointer(rckey.clone());
// Apply state changes // Apply state changes
layout.pressed_keys.remove(&pointer); layout.pressed_keys.remove(&pointer);
if key.locked {
layout.locked_keys.insert(pointer);
} else {
layout.locked_keys.remove(&pointer);
}
// Commit activated button state changes // Commit activated button state changes
RefCell::replace(rckey, key); RefCell::replace(rckey, key);
} }
@ -985,7 +1010,6 @@ mod test {
pub fn make_state() -> Rc<RefCell<::keyboard::KeyState>> { pub fn make_state() -> Rc<RefCell<::keyboard::KeyState>> {
Rc::new(RefCell::new(::keyboard::KeyState { Rc::new(RefCell::new(::keyboard::KeyState {
pressed: PressType::Released, pressed: PressType::Released,
locked: false,
keycodes: Vec::new(), keycodes: Vec::new(),
action: Action::SetView("default".into()), action: Action::SetView("default".into()),
})) }))
@ -1012,7 +1036,6 @@ mod test {
( (
0.0, 0.0,
Row { Row {
angle: 0,
buttons: vec![( buttons: vec![(
0.0, 0.0,
Box::new(Button { Box::new(Button {
@ -1025,7 +1048,6 @@ mod test {
( (
10.0, 10.0,
Row { Row {
angle: 0,
buttons: vec![( buttons: vec![(
0.0, 0.0,
Box::new(Button { Box::new(Button {
@ -1049,7 +1071,6 @@ mod test {
( (
0.0, 0.0,
Row { Row {
angle: 0,
buttons: vec![( buttons: vec![(
0.0, 0.0,
Box::new(Button { Box::new(Button {
@ -1064,7 +1085,6 @@ mod test {
current_view: String::new(), current_view: String::new(),
keymap_str: CString::new("").unwrap(), keymap_str: CString::new("").unwrap(),
kind: ArrangementKind::Base, kind: ArrangementKind::Base,
locked_keys: HashSet::new(),
pressed_keys: HashSet::new(), pressed_keys: HashSet::new(),
// Lots of bottom margin // Lots of bottom margin
margins: Margins { margins: Margins {
@ -1074,7 +1094,7 @@ mod test {
bottom: 1.0, bottom: 1.0,
}, },
views: hashmap! { views: hashmap! {
String::new() => view, String::new() => (c::Point { x: 0.0, y: 0.0 }, view),
}, },
}; };
assert_eq!( assert_eq!(

View File

@ -91,6 +91,11 @@ mod variants {
unsafe { unsafe {
let ret = glib_sys::g_variant_builder_end(builder); let ret = glib_sys::g_variant_builder_end(builder);
glib_sys::g_variant_builder_unref(builder); glib_sys::g_variant_builder_unref(builder);
// HACK: This is to prevent C taking ownership
// of "floating" Variants,
// where Rust gets to keep a stale reference
// and crash when trying to drop it.
glib_sys::g_variant_ref_sink(ret);
glib::Variant::from_glib_full(ret) glib::Variant::from_glib_full(ret)
} }
} }
@ -141,7 +146,7 @@ fn set_layout(kind: String, name: String) {
.chain(inputs).collect(); .chain(inputs).collect();
settings.set_value( settings.set_value(
"sources", "sources",
&variants::ArrayPairString(inputs).to_variant() &variants::ArrayPairString(inputs).to_variant(),
); );
settings.apply(); settings.apply();
} }

View File

@ -16,14 +16,16 @@ const KEYBOARDS: &[(*const str, *const str)] = &[
("us_wide", include_str!("../data/keyboards/us_wide.yaml")), ("us_wide", include_str!("../data/keyboards/us_wide.yaml")),
("de", include_str!("../data/keyboards/de.yaml")), ("de", include_str!("../data/keyboards/de.yaml")),
("de_wide", include_str!("../data/keyboards/de_wide.yaml")), ("de_wide", include_str!("../data/keyboards/de_wide.yaml")),
("el", include_str!("../data/keyboards/el.yaml")),
("es", include_str!("../data/keyboards/es.yaml")), ("es", include_str!("../data/keyboards/es.yaml")),
("fi", include_str!("../data/keyboards/fi.yaml")), ("fi", include_str!("../data/keyboards/fi.yaml")),
("gr", include_str!("../data/keyboards/gr.yaml")),
("it", include_str!("../data/keyboards/it.yaml")), ("it", include_str!("../data/keyboards/it.yaml")),
("jp+kana", include_str!("../data/keyboards/jp+kana.yaml")), ("jp+kana", include_str!("../data/keyboards/jp+kana.yaml")),
("jp+kana_wide", include_str!("../data/keyboards/jp+kana_wide.yaml")), ("jp+kana_wide", include_str!("../data/keyboards/jp+kana_wide.yaml")),
("no", include_str!("../data/keyboards/no.yaml")), ("no", include_str!("../data/keyboards/no.yaml")),
("number", include_str!("../data/keyboards/number.yaml")), ("number", include_str!("../data/keyboards/number.yaml")),
("pl", include_str!("../data/keyboards/pl.yaml")),
("pl_wide", include_str!("../data/keyboards/pl_wide.yaml")),
("se", include_str!("../data/keyboards/se.yaml")), ("se", include_str!("../data/keyboards/se.yaml")),
// layout+overlay // layout+overlay
("terminal", include_str!("../data/keyboards/terminal.yaml")), ("terminal", include_str!("../data/keyboards/terminal.yaml")),

View File

@ -17,7 +17,11 @@
* and those events SHOULD NOT cause any lost events. * and those events SHOULD NOT cause any lost events.
* */ * */
use ::action::Action;
use ::imservice;
use ::imservice::IMService; use ::imservice::IMService;
use ::keyboard::{ KeyCode, KeyState, KeyStateId, PressType };
use ::logging;
use ::vkeyboard::VirtualKeyboard; use ::vkeyboard::VirtualKeyboard;
/// Gathers stuff defined in C or called by C /// Gathers stuff defined in C or called by C
@ -57,6 +61,7 @@ pub mod c {
Submission { Submission {
imservice, imservice,
virtual_keyboard: VirtualKeyboard(vk), virtual_keyboard: VirtualKeyboard(vk),
pressed: Vec::new(),
} }
)) ))
} }
@ -92,9 +97,94 @@ pub mod c {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct Timestamp(pub u32); pub struct Timestamp(pub u32);
pub struct Submission { enum SubmittedAction {
// used by C callbacks internally, TODO: make use with virtual keyboard /// A collection of keycodes that were pressed
#[allow(dead_code)] VirtualKeyboard(Vec<KeyCode>),
imservice: Option<Box<IMService>>, IMService,
pub virtual_keyboard: VirtualKeyboard, }
pub struct Submission {
imservice: Option<Box<IMService>>,
virtual_keyboard: VirtualKeyboard,
pressed: Vec<(KeyStateId, SubmittedAction)>,
}
impl Submission {
/// Sends a submit text event if possible;
/// otherwise sends key press and makes a note of it
pub fn handle_press(
&mut self,
key: &KeyState, key_id: KeyStateId,
time: Timestamp,
) {
match &key.action {
Action::Submit { text: _, keys: _ }
| Action::Erase
=> (),
_ => {
log_print!(
logging::Level::Bug,
"Submitted key with action other than Submit or Erase",
);
return;
},
};
let was_committed_as_text = match (&mut self.imservice, &key.action) {
(Some(imservice), Action::Submit { text: Some(text), keys: _ }) => {
let submit_result = imservice.commit_string(text)
.and_then(|_| imservice.commit());
match submit_result {
Ok(()) => true,
Err(imservice::SubmitError::NotActive) => false,
}
},
/* Delete_surrounding_text takes byte offsets,
* so cannot work without get_surrounding_text.
* This is a bug in the protocol.
(Some(imservice), Action::Erase) => {
let submit_result = imservice.delete_surrounding_text(1, 0)
.and_then(|_| imservice.commit());
match submit_result {
Ok(()) => true,
Err(imservice::SubmitError::NotActive) => false,
}
}*/
(_, _) => false,
};
let submit_action = match was_committed_as_text {
true => SubmittedAction::IMService,
false => {
self.virtual_keyboard.switch(
&key.keycodes,
PressType::Pressed,
time,
);
SubmittedAction::VirtualKeyboard(key.keycodes.clone())
},
};
self.pressed.push((key_id, submit_action));
}
pub fn handle_release(&mut self, key_id: KeyStateId, time: Timestamp) {
let index = self.pressed.iter().position(|(id, _)| *id == key_id);
if let Some(index) = index {
let (_id, action) = self.pressed.remove(index);
match action {
// string already sent, nothing to do
SubmittedAction::IMService => {},
// no matter if the imservice got activated,
// keys must be released
SubmittedAction::VirtualKeyboard(keycodes) => {
self.virtual_keyboard.switch(
&keycodes,
PressType::Released,
time,
)
},
}
};
}
} }

View File

@ -60,7 +60,7 @@ fn check_layout(layout: Layout) {
let state = xkb::State::new(&keymap); let state = xkb::State::new(&keymap);
// "Press" each button with keysyms // "Press" each button with keysyms
for view in layout.views.values() { for (_pos, view) in layout.views.values() {
for (_y, row) in &view.get_rows() { for (_y, row) in &view.get_rows() {
for (_x, button) in &row.buttons { for (_x, button) in &row.buttons {
let keystate = button.state.borrow(); let keystate = button.state.borrow();

View File

@ -50,13 +50,14 @@ endforeach
foreach layout : [ foreach layout : [
'us', 'us_wide', 'us', 'us_wide',
'de', 'de_wide', 'de', 'de_wide',
'el',
'es', 'es',
'fi', 'fi',
'gr',
'it', 'it',
'jp+kana','jp+kana_wide', 'jp+kana','jp+kana_wide',
'no', 'no',
'number', 'number',
'pl', 'pl_wide',
'se', 'se',
'terminal', 'terminal',