Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2641a3b3d8 | |||
| b45039a813 | |||
| 04b105ab38 | |||
| 80388c0042 | |||
| 37820bf169 | |||
| d8e58fd774 | |||
| fcb57c9093 | |||
| b578414655 | |||
| 89b1f51ed5 | |||
| 7b1755a489 | |||
| 676a2b60ac | |||
| 32dc25dfbf | |||
| 484d64cfb9 | |||
| 637da2c177 | |||
| 3210a363ab | |||
| 8da8d55b98 | |||
| d8ca9f47ca | |||
| a3638f4bfb | |||
| f45f2db948 | |||
| 40bf3ca5de | |||
| e800a88893 | |||
| 24c3fac505 | |||
| 46f8790fc0 | |||
| 3cdced0c0c | |||
| bffd212e10 | |||
| c2c379b870 | |||
| 1ae29ff7bc | |||
| d3cd7dc11f | |||
| d3695d3bc9 | |||
| 11952ed29a | |||
| 842e616cd3 | |||
| a265427e8e | |||
| e6c45a63fb | |||
| e82e256581 | |||
| bedabb6188 | |||
| a030f55a7c | |||
| 49aa4256a9 | |||
| eb7d0d5db9 | |||
| 575619e812 | |||
| 630cfc8e59 | |||
| 2a11bce945 | |||
| a332efca45 | |||
| 5b3c185a16 | |||
| 38842f9743 | |||
| 3cbfd8351c | |||
| c6cc58fd8e | |||
| 9522d4e302 | |||
| 8f62520648 | |||
| e36c4e597f | |||
| 8ab6997b21 | |||
| 3b06eadef5 | |||
| 287e851770 |
87
data/keyboards/es+cat.yaml
Normal file
87
data/keyboards/es+cat.yaml
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
---
|
||||||
|
outlines:
|
||||||
|
default: { width: 35.33, height: 52 }
|
||||||
|
altline: { width: 52.67, height: 52 }
|
||||||
|
wide: { width: 62, height: 52 }
|
||||||
|
spaceline: { width: 99.67, height: 52 }
|
||||||
|
special: { width: 44, height: 52 }
|
||||||
|
|
||||||
|
views:
|
||||||
|
base:
|
||||||
|
- "q w e r t y u i o p"
|
||||||
|
- "a s d f g h j k l ç"
|
||||||
|
- "Shift_L z x c v b n m BackSpace"
|
||||||
|
- "show_numbers show_eschars preferences space ? period Return"
|
||||||
|
upper:
|
||||||
|
- "Q W E R T Y U I O P"
|
||||||
|
- "A S D F G H J K L Ç"
|
||||||
|
- "Shift_L Z X C V B N M BackSpace"
|
||||||
|
- "show_numbers show_eschars preferences space ¿ period Return"
|
||||||
|
numbers:
|
||||||
|
- "1 2 3 4 5 6 7 8 9 0"
|
||||||
|
- "@ # € % & - _ + ( )"
|
||||||
|
- "show_symbols , \" ' colon ; ! = BackSpace"
|
||||||
|
- "show_letters show_eschars preferences space ? period Return"
|
||||||
|
symbols:
|
||||||
|
- "~ ` | · √ π τ ÷ × ¶"
|
||||||
|
- "© ® £ $ ¥ ^ ° * { }"
|
||||||
|
- "show_numbers \\ / < > = [ ] BackSpace"
|
||||||
|
- "show_letters show_eschars preferences space ? period Return"
|
||||||
|
eschars:
|
||||||
|
- "á é í ó ú Á É Í Ó Ú"
|
||||||
|
- "à è ì ò ù À È Ì Ò Ù"
|
||||||
|
- "show_numbers ü ç ï Ü Ç Ï ¡ BackSpace"
|
||||||
|
- "show_letters show_eschars preferences space « » Return"
|
||||||
|
|
||||||
|
buttons:
|
||||||
|
Shift_L:
|
||||||
|
action:
|
||||||
|
locking:
|
||||||
|
lock_view: "upper"
|
||||||
|
unlock_view: "base"
|
||||||
|
outline: "altline"
|
||||||
|
icon: "key-shift"
|
||||||
|
BackSpace:
|
||||||
|
outline: "altline"
|
||||||
|
icon: "edit-clear-symbolic"
|
||||||
|
action: "erase"
|
||||||
|
preferences:
|
||||||
|
action: "show_prefs"
|
||||||
|
outline: "default"
|
||||||
|
icon: "keyboard-mode-symbolic"
|
||||||
|
show_numbers:
|
||||||
|
action:
|
||||||
|
set_view: "numbers"
|
||||||
|
outline: "altline"
|
||||||
|
label: "123"
|
||||||
|
show_letters:
|
||||||
|
action:
|
||||||
|
set_view: "base"
|
||||||
|
outline: "altline"
|
||||||
|
label: "abc"
|
||||||
|
show_symbols:
|
||||||
|
action:
|
||||||
|
set_view: "symbols"
|
||||||
|
outline: "altline"
|
||||||
|
label: "*/="
|
||||||
|
show_eschars:
|
||||||
|
action:
|
||||||
|
locking:
|
||||||
|
lock_view: "eschars"
|
||||||
|
unlock_view: "base"
|
||||||
|
outline: "altline"
|
||||||
|
label: "àÀ"
|
||||||
|
|
||||||
|
period:
|
||||||
|
outline: "default"
|
||||||
|
text: "."
|
||||||
|
space:
|
||||||
|
outline: "spaceline"
|
||||||
|
text: " "
|
||||||
|
Return:
|
||||||
|
outline: "altline"
|
||||||
|
icon: "key-enter"
|
||||||
|
keysym: "Return"
|
||||||
|
colon:
|
||||||
|
text: ":"
|
||||||
|
|
||||||
71
data/keyboards/il.yaml
Normal file
71
data/keyboards/il.yaml
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
---
|
||||||
|
outlines:
|
||||||
|
default: { width: 40, height: 60 }
|
||||||
|
altline: { width: 56, height: 60 }
|
||||||
|
wide: { width: 62, height: 60 }
|
||||||
|
spaceline: { width: 142, height: 60 }
|
||||||
|
special: { width: 44, height: 60 }
|
||||||
|
|
||||||
|
views:
|
||||||
|
base:
|
||||||
|
- "' - ק ר א ט ו ן ם פ"
|
||||||
|
- "ש ד ג כ ע י ח ל ך ף"
|
||||||
|
- "ז ס ב ה נ מ צ ת ץ BackSpace"
|
||||||
|
- "show_numbers comma preferences space period Return"
|
||||||
|
numbers:
|
||||||
|
- "1 2 3 4 5 6 7 8 9 0"
|
||||||
|
- "@ # ₪ % & - _ + ( )"
|
||||||
|
- "show_symbols , \" ' colon ; ! ? BackSpace"
|
||||||
|
- "show_letters preferences space period Return"
|
||||||
|
symbols:
|
||||||
|
- "~ ` | · √ π τ ÷ × ¶"
|
||||||
|
- "© ® £ € $ ^ ° * { }"
|
||||||
|
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
|
||||||
|
- "show_letters preferences space period Return"
|
||||||
|
|
||||||
|
buttons:
|
||||||
|
BackSpace:
|
||||||
|
outline: "default"
|
||||||
|
icon: "edit-clear-symbolic"
|
||||||
|
action: erase
|
||||||
|
comma:
|
||||||
|
outline: "special"
|
||||||
|
text: ","
|
||||||
|
|
||||||
|
preferences:
|
||||||
|
action: show_prefs
|
||||||
|
outline: "special"
|
||||||
|
icon: "keyboard-mode-symbolic"
|
||||||
|
show_numbers:
|
||||||
|
action:
|
||||||
|
set_view: "numbers"
|
||||||
|
outline: "wide"
|
||||||
|
label: "123"
|
||||||
|
show_numbers_from_symbols:
|
||||||
|
action:
|
||||||
|
set_view: "numbers"
|
||||||
|
outline: "altline"
|
||||||
|
label: "123"
|
||||||
|
show_letters:
|
||||||
|
action:
|
||||||
|
set_view: "base"
|
||||||
|
outline: "wide"
|
||||||
|
label: "ABC"
|
||||||
|
show_symbols:
|
||||||
|
action:
|
||||||
|
set_view: "symbols"
|
||||||
|
outline: "altline"
|
||||||
|
label: "*/="
|
||||||
|
period:
|
||||||
|
outline: "special"
|
||||||
|
text: "."
|
||||||
|
space:
|
||||||
|
outline: "spaceline"
|
||||||
|
text: " "
|
||||||
|
Return:
|
||||||
|
outline: "wide"
|
||||||
|
icon: "key-enter"
|
||||||
|
keysym: "Return"
|
||||||
|
colon:
|
||||||
|
text: ":"
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ views:
|
|||||||
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 , \" ' : ; ! = BackSpace"
|
||||||
- "show_letters show_eschars preferences space ? . Return"
|
- "show_letters show_eschars preferences space ? . Return"
|
||||||
symbols:
|
symbols:
|
||||||
- "~ ` | · √ π τ ÷ × ¶"
|
- "~ ` | · √ π τ ÷ × ¶"
|
||||||
@ -86,7 +86,4 @@ buttons:
|
|||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "key-enter"
|
icon: "key-enter"
|
||||||
keysym: "Return"
|
keysym: "Return"
|
||||||
colon:
|
|
||||||
label: ":"
|
|
||||||
"\"":
|
|
||||||
keysym: "quotedbl"
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@ views:
|
|||||||
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 , \" ' : ; ! ? BackSpace"
|
||||||
- "show_letters show_eschars preferences space ? . Return"
|
- "show_letters show_eschars preferences space ? . Return"
|
||||||
symbols:
|
symbols:
|
||||||
- "~ ` | · √ π τ ÷ × ¶"
|
- "~ ` | · √ π τ ÷ × ¶"
|
||||||
@ -84,7 +84,4 @@ buttons:
|
|||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "key-enter"
|
icon: "key-enter"
|
||||||
keysym: "Return"
|
keysym: "Return"
|
||||||
colon:
|
|
||||||
label: ":"
|
|
||||||
"\"":
|
|
||||||
keysym: "quotedbl"
|
|
||||||
|
|||||||
@ -52,6 +52,8 @@ buttons:
|
|||||||
locking:
|
locking:
|
||||||
lock_view: "upper_accents"
|
lock_view: "upper_accents"
|
||||||
unlock_view: "accents"
|
unlock_view: "accents"
|
||||||
|
looks_locked_from:
|
||||||
|
- "upper"
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "key-shift"
|
icon: "key-shift"
|
||||||
BackSpace:
|
BackSpace:
|
||||||
@ -94,6 +96,8 @@ buttons:
|
|||||||
locking:
|
locking:
|
||||||
lock_view: "upper_accents"
|
lock_view: "upper_accents"
|
||||||
unlock_view: "upper"
|
unlock_view: "upper"
|
||||||
|
looks_locked_from:
|
||||||
|
- "accents"
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
label: "ĄĘ"
|
label: "ĄĘ"
|
||||||
period:
|
period:
|
||||||
|
|||||||
84
data/keyboards/th_wide.yaml
Normal file
84
data/keyboards/th_wide.yaml
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
---
|
||||||
|
outlines:
|
||||||
|
default: { width: 75, height: 56 }
|
||||||
|
altline: { width: 75, height: 56 }
|
||||||
|
wide: { width: 135, height: 56 }
|
||||||
|
spaceline: { width: 450, height: 56 }
|
||||||
|
spacelinesymbol: { width: 300, height: 56 }
|
||||||
|
special: { width: 90, height: 56 }
|
||||||
|
|
||||||
|
views:
|
||||||
|
base:
|
||||||
|
- "ๅ / _ ภ ถ ุ ึ ค ต จ ข ช"
|
||||||
|
- "ๆ ไ ำ พ ะ ั ี ร น ย บ ล"
|
||||||
|
- "ฟ ห ก ด เ ้ ่ า ส ว ง ฃ"
|
||||||
|
- "Shift_L ผ ป แ อ ิ ื ท ม ใ ฝ BackSpace"
|
||||||
|
- "show_numbers preferences space period Return"
|
||||||
|
upper:
|
||||||
|
- "+ ๑ ๒ ๓ ๔ ู ฿ ๕ ๖ ๗ ๘ ๙"
|
||||||
|
- "๐ \" ฎ ฑ ธ ํ ๊ ณ ฯ ญ ฐ ,"
|
||||||
|
- "ฤ ฆ ฏ โ ฌ ็ ๋ ษ ศ ซ . ฅ"
|
||||||
|
- "Shift_L ( ) ฉ ฮ ฺ ์ ? ฒ ฬ ฦ BackSpace"
|
||||||
|
- "show_numbers preferences space period Return"
|
||||||
|
numbers:
|
||||||
|
- "1 2 3 4 5 6 7 8 9 0"
|
||||||
|
- "@ # $ % & - _ + ( )"
|
||||||
|
- "show_symbols , \" ' colon ; ! ? BackSpace"
|
||||||
|
- "show_letters preferences spacesymbol period Return"
|
||||||
|
symbols:
|
||||||
|
- "~ ` | · √ π τ ÷ × ¶"
|
||||||
|
- "© ® £ € ¥ ^ ° * { }"
|
||||||
|
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
|
||||||
|
- "show_letters preferences spacesymbol period Return"
|
||||||
|
|
||||||
|
buttons:
|
||||||
|
Shift_L:
|
||||||
|
action:
|
||||||
|
locking:
|
||||||
|
lock_view: "upper"
|
||||||
|
unlock_view: "base"
|
||||||
|
outline: "altline"
|
||||||
|
icon: "key-shift"
|
||||||
|
BackSpace:
|
||||||
|
outline: "altline"
|
||||||
|
icon: "edit-clear-symbolic"
|
||||||
|
action: erase
|
||||||
|
preferences:
|
||||||
|
action: show_prefs
|
||||||
|
outline: "special"
|
||||||
|
icon: "keyboard-mode-symbolic"
|
||||||
|
show_numbers:
|
||||||
|
action:
|
||||||
|
set_view: "numbers"
|
||||||
|
outline: "wide"
|
||||||
|
label: "123"
|
||||||
|
show_numbers_from_symbols:
|
||||||
|
action:
|
||||||
|
set_view: "numbers"
|
||||||
|
outline: "altline"
|
||||||
|
label: "123"
|
||||||
|
show_letters:
|
||||||
|
action:
|
||||||
|
set_view: "base"
|
||||||
|
outline: "wide"
|
||||||
|
label: "กขค"
|
||||||
|
show_symbols:
|
||||||
|
action:
|
||||||
|
set_view: "symbols"
|
||||||
|
outline: "altline"
|
||||||
|
label: "*/="
|
||||||
|
period:
|
||||||
|
outline: "special"
|
||||||
|
text: "."
|
||||||
|
space:
|
||||||
|
outline: "spaceline"
|
||||||
|
text: " "
|
||||||
|
spacesymbol:
|
||||||
|
outline: "spacelinesymbol"
|
||||||
|
text: " "
|
||||||
|
Return:
|
||||||
|
outline: "wide"
|
||||||
|
icon: "key-enter"
|
||||||
|
keysym: "Return"
|
||||||
|
colon:
|
||||||
|
text: ":"
|
||||||
78
data/keyboards/us+colemak_wide.yaml
Normal file
78
data/keyboards/us+colemak_wide.yaml
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
---
|
||||||
|
outlines:
|
||||||
|
default: { width: 54, height: 42 }
|
||||||
|
altline: { width: 81, height: 42 }
|
||||||
|
wide: { width: 108, height: 42 }
|
||||||
|
spaceline: { width: 216, height: 42 }
|
||||||
|
special: { width: 54, height: 42 }
|
||||||
|
|
||||||
|
views:
|
||||||
|
base:
|
||||||
|
- "q w f p g j l u y"
|
||||||
|
- "a r s t d h n e i o"
|
||||||
|
- "Shift_L z x c v b k m BackSpace"
|
||||||
|
- "show_numbers preferences space . Return"
|
||||||
|
upper:
|
||||||
|
- "Q W F P G J L U Y"
|
||||||
|
- "A R S T D H N E I O"
|
||||||
|
- "Shift_L Z X C V B K M BackSpace"
|
||||||
|
- "show_numbers preferences space . Return"
|
||||||
|
numbers:
|
||||||
|
- "1 2 3 4 5 6 7 8 9 0"
|
||||||
|
- "@ # $ % & - _ + ( )"
|
||||||
|
- "show_symbols , \" ' colon ; ! ? BackSpace"
|
||||||
|
- "show_letters preferences space . Return"
|
||||||
|
symbols:
|
||||||
|
- "~ ` | · √ π τ ÷ × ¶"
|
||||||
|
- "© ® £ € ¥ ^ ° * { }"
|
||||||
|
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
|
||||||
|
- "show_letters preferences space . Return"
|
||||||
|
|
||||||
|
buttons:
|
||||||
|
Shift_L:
|
||||||
|
action:
|
||||||
|
locking:
|
||||||
|
lock_view: "upper"
|
||||||
|
unlock_view: "base"
|
||||||
|
outline: "altline"
|
||||||
|
icon: "key-shift"
|
||||||
|
BackSpace:
|
||||||
|
outline: "altline"
|
||||||
|
icon: "edit-clear-symbolic"
|
||||||
|
action: "erase"
|
||||||
|
preferences:
|
||||||
|
action: "show_prefs"
|
||||||
|
outline: "special"
|
||||||
|
icon: "keyboard-mode-symbolic"
|
||||||
|
show_numbers:
|
||||||
|
action:
|
||||||
|
set_view: "numbers"
|
||||||
|
outline: "wide"
|
||||||
|
label: "123"
|
||||||
|
show_numbers_from_symbols:
|
||||||
|
action:
|
||||||
|
set_view: "numbers"
|
||||||
|
outline: "altline"
|
||||||
|
label: "123"
|
||||||
|
show_letters:
|
||||||
|
action:
|
||||||
|
set_view: "base"
|
||||||
|
outline: "wide"
|
||||||
|
label: "ABC"
|
||||||
|
show_symbols:
|
||||||
|
action:
|
||||||
|
set_view: "symbols"
|
||||||
|
outline: "altline"
|
||||||
|
label: "*/="
|
||||||
|
".":
|
||||||
|
outline: "special"
|
||||||
|
text: "."
|
||||||
|
space:
|
||||||
|
outline: "spaceline"
|
||||||
|
text: " "
|
||||||
|
Return:
|
||||||
|
outline: "wide"
|
||||||
|
icon: "key-enter"
|
||||||
|
keysym: "Return"
|
||||||
|
colon:
|
||||||
|
text: ":"
|
||||||
89
data/keyboards/us+dvorak.yaml
Normal file
89
data/keyboards/us+dvorak.yaml
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
---
|
||||||
|
outlines:
|
||||||
|
default: { width: 35.33, height: 52 }
|
||||||
|
altline: { width: 52.67, height: 52 }
|
||||||
|
wide: { width: 62, height: 52 }
|
||||||
|
spaceline: { width: 142, height: 52 }
|
||||||
|
special: { width: 44, height: 52 }
|
||||||
|
|
||||||
|
views:
|
||||||
|
base:
|
||||||
|
- "Shift_L p y f g c r l BackSpace"
|
||||||
|
- "a o e u i d h t n s"
|
||||||
|
- ", q j k x b m w v z"
|
||||||
|
- "show_numbers preferences space period Return"
|
||||||
|
upper:
|
||||||
|
- "Shift_L P Y F G C R L BackSpace"
|
||||||
|
- "A O E U I D H T N S"
|
||||||
|
- ", Q J K X B M W V Z"
|
||||||
|
- "show_numbers preferences space period Return"
|
||||||
|
numbers:
|
||||||
|
- "show_symbols , \" ' colon ; ! ? BackSpace"
|
||||||
|
- "* # $ / & - _ + ( )"
|
||||||
|
- "1 2 3 4 5 6 7 8 9 0"
|
||||||
|
- "show_letters preferences space period Return"
|
||||||
|
symbols:
|
||||||
|
- "show_numbers_from_symbols \\ % < > = [ ] BackSpace"
|
||||||
|
- "© ® £ € ¥ ^ ° @ { }"
|
||||||
|
- "~ ` | · √ π τ ÷ × ¶"
|
||||||
|
- "show_letters preferences space period Return"
|
||||||
|
|
||||||
|
buttons:
|
||||||
|
Shift_L:
|
||||||
|
action:
|
||||||
|
locking:
|
||||||
|
lock_view: "upper"
|
||||||
|
unlock_view: "base"
|
||||||
|
outline: "altline"
|
||||||
|
icon: "key-shift"
|
||||||
|
BackSpace:
|
||||||
|
outline: "altline"
|
||||||
|
icon: "edit-clear-symbolic"
|
||||||
|
action: "erase"
|
||||||
|
preferences:
|
||||||
|
action: "show_prefs"
|
||||||
|
outline: "special"
|
||||||
|
icon: "keyboard-mode-symbolic"
|
||||||
|
show_numbers:
|
||||||
|
action:
|
||||||
|
set_view: "numbers"
|
||||||
|
outline: "wide"
|
||||||
|
label: "123"
|
||||||
|
show_numbers_from_symbols:
|
||||||
|
action:
|
||||||
|
set_view: "numbers"
|
||||||
|
outline: "altline"
|
||||||
|
label: "123"
|
||||||
|
show_letters:
|
||||||
|
action:
|
||||||
|
set_view: "base"
|
||||||
|
outline: "wide"
|
||||||
|
label: "ABC"
|
||||||
|
show_symbols:
|
||||||
|
action:
|
||||||
|
set_view: "symbols"
|
||||||
|
outline: "altline"
|
||||||
|
label: "*/="
|
||||||
|
period:
|
||||||
|
outline: "special"
|
||||||
|
text: "."
|
||||||
|
space:
|
||||||
|
outline: "spaceline"
|
||||||
|
text: " "
|
||||||
|
Return:
|
||||||
|
outline: "wide"
|
||||||
|
icon: "key-enter"
|
||||||
|
keysym: "Return"
|
||||||
|
colon:
|
||||||
|
text: ":"
|
||||||
|
|
||||||
|
# The US QWERTY layout has fewer letters on the third row, and so has
|
||||||
|
# the shift & backspace keys placed there. In contrast, the US DVORAK
|
||||||
|
# layout has fewer letters on the first row, which makes it a good
|
||||||
|
# choice for the shift & backspace keys. That leads to what may be,
|
||||||
|
# for many people, an unexpected layout in numbers mode: the numerals
|
||||||
|
# are on the third row (not the first) so that the backspace key
|
||||||
|
# remains in a consistent location regardless of mode, without
|
||||||
|
# sacrificing key width. (Once could argue that in numbers mode, the
|
||||||
|
# numerals should be closer to the enter key.) As with any keyboard
|
||||||
|
# layout, familiarity comes with repeated use.
|
||||||
89
data/keyboards/us+dvorak_wide.yaml
Normal file
89
data/keyboards/us+dvorak_wide.yaml
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
---
|
||||||
|
outlines:
|
||||||
|
default: { width: 54, height: 42 }
|
||||||
|
altline: { width: 81, height: 42 }
|
||||||
|
wide: { width: 108, height: 42 }
|
||||||
|
spaceline: { width: 216, height: 42 }
|
||||||
|
special: { width: 54, height: 42 }
|
||||||
|
|
||||||
|
views:
|
||||||
|
base:
|
||||||
|
- "Shift_L p y f g c r l BackSpace"
|
||||||
|
- "a o e u i d h t n s"
|
||||||
|
- ", q j k x b m w v z"
|
||||||
|
- "show_numbers preferences space period Return"
|
||||||
|
upper:
|
||||||
|
- "Shift_L P Y F G C R L BackSpace"
|
||||||
|
- "A O E U I D H T N S"
|
||||||
|
- ", Q J K X B M W V Z"
|
||||||
|
- "show_numbers preferences space period Return"
|
||||||
|
numbers:
|
||||||
|
- "show_symbols , \" ' colon ; ! ? BackSpace"
|
||||||
|
- "* # $ / & - _ + ( )"
|
||||||
|
- "1 2 3 4 5 6 7 8 9 0"
|
||||||
|
- "show_letters preferences space period Return"
|
||||||
|
symbols:
|
||||||
|
- "show_numbers_from_symbols \\ % < > = [ ] BackSpace"
|
||||||
|
- "© ® £ € ¥ ^ ° @ { }"
|
||||||
|
- "~ ` | · √ π τ ÷ × ¶"
|
||||||
|
- "show_letters preferences space period Return"
|
||||||
|
|
||||||
|
buttons:
|
||||||
|
Shift_L:
|
||||||
|
action:
|
||||||
|
locking:
|
||||||
|
lock_view: "upper"
|
||||||
|
unlock_view: "base"
|
||||||
|
outline: "altline"
|
||||||
|
icon: "key-shift"
|
||||||
|
BackSpace:
|
||||||
|
outline: "altline"
|
||||||
|
icon: "edit-clear-symbolic"
|
||||||
|
action: "erase"
|
||||||
|
preferences:
|
||||||
|
action: "show_prefs"
|
||||||
|
outline: "special"
|
||||||
|
icon: "keyboard-mode-symbolic"
|
||||||
|
show_numbers:
|
||||||
|
action:
|
||||||
|
set_view: "numbers"
|
||||||
|
outline: "wide"
|
||||||
|
label: "123"
|
||||||
|
show_numbers_from_symbols:
|
||||||
|
action:
|
||||||
|
set_view: "numbers"
|
||||||
|
outline: "altline"
|
||||||
|
label: "123"
|
||||||
|
show_letters:
|
||||||
|
action:
|
||||||
|
set_view: "base"
|
||||||
|
outline: "wide"
|
||||||
|
label: "ABC"
|
||||||
|
show_symbols:
|
||||||
|
action:
|
||||||
|
set_view: "symbols"
|
||||||
|
outline: "altline"
|
||||||
|
label: "*/="
|
||||||
|
period:
|
||||||
|
outline: "special"
|
||||||
|
text: "."
|
||||||
|
space:
|
||||||
|
outline: "spaceline"
|
||||||
|
text: " "
|
||||||
|
Return:
|
||||||
|
outline: "wide"
|
||||||
|
icon: "key-enter"
|
||||||
|
keysym: "Return"
|
||||||
|
colon:
|
||||||
|
text: ":"
|
||||||
|
|
||||||
|
# The US QWERTY layout has fewer letters on the third row, and so has
|
||||||
|
# the shift & backspace keys placed there. In contrast, the US DVORAK
|
||||||
|
# layout has fewer letters on the first row, which makes it a good
|
||||||
|
# choice for the shift & backspace keys. That leads to what may be,
|
||||||
|
# for many people, an unexpected layout in numbers mode: the numerals
|
||||||
|
# are on the third row (not the first) so that the backspace key
|
||||||
|
# remains in a consistent location regardless of mode, without
|
||||||
|
# sacrificing key width. (Once could argue that in numbers mode, the
|
||||||
|
# numerals should be closer to the enter key.) As with any keyboard
|
||||||
|
# layout, familiarity comes with repeated use.
|
||||||
19
data/langs/he-IL.txt
Normal file
19
data/langs/he-IL.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
be בלגית
|
||||||
|
br פורטוגזית (ברזיל)
|
||||||
|
cz צ'כית
|
||||||
|
de גרמנית
|
||||||
|
dk דנית
|
||||||
|
es ספרדית
|
||||||
|
emoji אימוג'י
|
||||||
|
fi פינית
|
||||||
|
fr צרפתית
|
||||||
|
gr יוונית
|
||||||
|
il עברית
|
||||||
|
it איטלקית
|
||||||
|
no נורווגית
|
||||||
|
pl פולנית
|
||||||
|
ru רוסית
|
||||||
|
se שוודית
|
||||||
|
terminal טרמינל
|
||||||
|
ua אוקראינית
|
||||||
|
us אנגלית (ארה"ב)
|
||||||
@ -31,11 +31,16 @@ sq_button.wide {
|
|||||||
border-color: #3e3a44;
|
border-color: #3e3a44;
|
||||||
}
|
}
|
||||||
|
|
||||||
sq_button.locked {
|
sq_button.latched {
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
color: #2b292f;
|
color: #2b292f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sq_button.locked {
|
||||||
|
background: #ffffff;
|
||||||
|
color: #1c71d8;
|
||||||
|
}
|
||||||
|
|
||||||
sq_button.action {
|
sq_button.action {
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,11 +34,16 @@ sq_button.wide {
|
|||||||
border-color: @borders; /* #3e3a44; */
|
border-color: @borders; /* #3e3a44; */
|
||||||
}
|
}
|
||||||
|
|
||||||
sq_button.locked {
|
sq_button.latched {
|
||||||
background: @theme_fg_color; /*#ffffff;*/
|
background: @theme_fg_color; /*#ffffff;*/
|
||||||
color: @theme_bg_color; /*#2b292f;*/
|
color: @theme_bg_color; /*#2b292f;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sq_button.locked {
|
||||||
|
background: @theme_fg_color; /*#ffffff;*/
|
||||||
|
color: mix(@theme_selected_bg_color, @theme_bg_color, 0.4); /*#2b292f;*/
|
||||||
|
}
|
||||||
|
|
||||||
sq_button.action {
|
sq_button.action {
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
}
|
}
|
||||||
|
|||||||
3
debian/check_release.py
vendored
3
debian/check_release.py
vendored
@ -5,6 +5,7 @@ Feed it the first changelog line, and then all available tags.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import re, sys
|
import re, sys
|
||||||
tag = "v" + re.findall("\\((.*)\\)", input())[0]
|
version = re.findall("\\((.*)\\)", input())[0]
|
||||||
|
tag = 'v' + re.findall("([0-9]+\\.[0-9]+\\.[0-9]+).*", version)[0]
|
||||||
if tag not in map(str.strip, sys.stdin.readlines()):
|
if tag not in map(str.strip, sys.stdin.readlines()):
|
||||||
raise Exception("Changelog's current version doesn't have a tag. Push the tag!")
|
raise Exception("Changelog's current version doesn't have a tag. Push the tag!")
|
||||||
|
|||||||
2
debian/compat
vendored
2
debian/compat
vendored
@ -1 +1 @@
|
|||||||
10
|
12
|
||||||
|
|||||||
1
debian/control
vendored
1
debian/control
vendored
@ -41,6 +41,7 @@ Depends:
|
|||||||
${misc:Depends},
|
${misc:Depends},
|
||||||
Breaks:
|
Breaks:
|
||||||
librem5-base (<< 24),
|
librem5-base (<< 24),
|
||||||
|
phosh (<= 0.10),
|
||||||
Description: On-screen keyboard for Wayland
|
Description: On-screen keyboard for Wayland
|
||||||
Virtual keyboard supporting Wayland, built primarily for the Librem 5 phone.
|
Virtual keyboard supporting Wayland, built primarily for the Librem 5 phone.
|
||||||
|
|
||||||
|
|||||||
2
debian/squeekboard.install
vendored
2
debian/squeekboard.install
vendored
@ -1,2 +1,2 @@
|
|||||||
tools/squeekboard-restyled usr/bin
|
|
||||||
usr/bin/squeekboard /usr/bin
|
usr/bin/squeekboard /usr/bin
|
||||||
|
usr/share/applications/sm.puri.Squeekboard.desktop
|
||||||
|
|||||||
16
debian/squeekboard.user.service
vendored
Normal file
16
debian/squeekboard.user.service
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Squeekboard - a Wayland virtual keyboard
|
||||||
|
PartOf=graphical-session.target
|
||||||
|
# Don't stop restarting the program
|
||||||
|
StartLimitIntervalSec=0
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Environment="GTK_THEME=Adwaita:dark"
|
||||||
|
ExecStart=/usr/bin/squeekboard
|
||||||
|
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=3s
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=graphical-session.target
|
||||||
|
|
||||||
@ -45,6 +45,8 @@
|
|||||||
typedef struct _EekGtkKeyboardPrivate
|
typedef struct _EekGtkKeyboardPrivate
|
||||||
{
|
{
|
||||||
EekRenderer *renderer; // owned, nullable
|
EekRenderer *renderer; // owned, nullable
|
||||||
|
struct render_geometry render_geometry; // mutable
|
||||||
|
|
||||||
EekboardContextService *eekboard_context; // unowned reference
|
EekboardContextService *eekboard_context; // unowned reference
|
||||||
struct submission *submission; // unowned reference
|
struct submission *submission; // unowned reference
|
||||||
|
|
||||||
@ -72,12 +74,23 @@ eek_gtk_keyboard_real_realize (GtkWidget *self)
|
|||||||
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->realize (self);
|
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->realize (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_allocation_size(EekGtkKeyboard *gtk_keyboard,
|
||||||
|
struct squeek_layout *layout, gdouble width, gdouble height)
|
||||||
|
{
|
||||||
|
// This is where size-dependent surfaces would be released
|
||||||
|
EekGtkKeyboardPrivate *priv =
|
||||||
|
eek_gtk_keyboard_get_instance_private (gtk_keyboard);
|
||||||
|
priv->render_geometry = eek_render_geometry_from_allocation_size(
|
||||||
|
layout, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
eek_gtk_keyboard_real_draw (GtkWidget *self,
|
eek_gtk_keyboard_real_draw (GtkWidget *self,
|
||||||
cairo_t *cr)
|
cairo_t *cr)
|
||||||
{
|
{
|
||||||
|
EekGtkKeyboard *keyboard = EEK_GTK_KEYBOARD (self);
|
||||||
EekGtkKeyboardPrivate *priv =
|
EekGtkKeyboardPrivate *priv =
|
||||||
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
|
eek_gtk_keyboard_get_instance_private (keyboard);
|
||||||
GtkAllocation allocation;
|
GtkAllocation allocation;
|
||||||
gtk_widget_get_allocation (self, &allocation);
|
gtk_widget_get_allocation (self, &allocation);
|
||||||
|
|
||||||
@ -92,15 +105,14 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
|
|||||||
priv->keyboard,
|
priv->keyboard,
|
||||||
pcontext);
|
pcontext);
|
||||||
|
|
||||||
eek_renderer_set_allocation_size (priv->renderer,
|
set_allocation_size (keyboard, priv->keyboard->layout,
|
||||||
priv->keyboard->layout,
|
allocation.width, allocation.height);
|
||||||
allocation.width,
|
|
||||||
allocation.height);
|
|
||||||
eek_renderer_set_scale_factor (priv->renderer,
|
eek_renderer_set_scale_factor (priv->renderer,
|
||||||
gtk_widget_get_scale_factor (self));
|
gtk_widget_get_scale_factor (self));
|
||||||
}
|
}
|
||||||
|
|
||||||
eek_renderer_render_keyboard (priv->renderer, priv->submission, cr, priv->keyboard);
|
eek_renderer_render_keyboard (priv->renderer, priv->render_geometry,
|
||||||
|
priv->submission, cr, priv->keyboard);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,8 +129,9 @@ static void
|
|||||||
eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
|
eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
|
||||||
GtkAllocation *allocation)
|
GtkAllocation *allocation)
|
||||||
{
|
{
|
||||||
|
EekGtkKeyboard *keyboard = EEK_GTK_KEYBOARD (self);
|
||||||
EekGtkKeyboardPrivate *priv =
|
EekGtkKeyboardPrivate *priv =
|
||||||
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
|
eek_gtk_keyboard_get_instance_private (keyboard);
|
||||||
// check if the change would switch types
|
// check if the change would switch types
|
||||||
enum squeek_arrangement_kind new_type = get_type(
|
enum squeek_arrangement_kind new_type = get_type(
|
||||||
(uint32_t)(allocation->width - allocation->x),
|
(uint32_t)(allocation->width - allocation->x),
|
||||||
@ -130,10 +143,8 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (priv->renderer) {
|
if (priv->renderer) {
|
||||||
eek_renderer_set_allocation_size (priv->renderer,
|
set_allocation_size (keyboard, priv->keyboard->layout,
|
||||||
priv->keyboard->layout,
|
allocation->width, allocation->height);
|
||||||
allocation->width,
|
|
||||||
allocation->height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->
|
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->
|
||||||
@ -162,7 +173,7 @@ static void depress(EekGtkKeyboard *self,
|
|||||||
}
|
}
|
||||||
squeek_layout_depress(priv->keyboard->layout,
|
squeek_layout_depress(priv->keyboard->layout,
|
||||||
priv->submission,
|
priv->submission,
|
||||||
x, y, eek_renderer_get_transformation(priv->renderer), time, self);
|
x, y, priv->render_geometry.widget_to_layout, time, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drag(EekGtkKeyboard *self,
|
static void drag(EekGtkKeyboard *self,
|
||||||
@ -174,7 +185,7 @@ static void drag(EekGtkKeyboard *self,
|
|||||||
}
|
}
|
||||||
squeek_layout_drag(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout,
|
squeek_layout_drag(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout,
|
||||||
priv->submission,
|
priv->submission,
|
||||||
x, y, eek_renderer_get_transformation(priv->renderer), time,
|
x, y, priv->render_geometry.widget_to_layout, time,
|
||||||
priv->eekboard_context, self);
|
priv->eekboard_context, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,8 +196,7 @@ static void release(EekGtkKeyboard *self, guint32 time)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
squeek_layout_release(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout,
|
squeek_layout_release(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout,
|
||||||
priv->submission,
|
priv->submission, priv->render_geometry.widget_to_layout, time,
|
||||||
eek_renderer_get_transformation(priv->renderer), time,
|
|
||||||
priv->eekboard_context, self);
|
priv->eekboard_context, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,6 +406,24 @@ eek_gtk_keyboard_new (EekboardContextService *eekservice,
|
|||||||
priv->submission = submission;
|
priv->submission = submission;
|
||||||
priv->layout = layout;
|
priv->layout = layout;
|
||||||
priv->renderer = NULL;
|
priv->renderer = NULL;
|
||||||
|
// This should really be done on initialization.
|
||||||
|
// Before the widget is allocated,
|
||||||
|
// we don't really know what geometry it takes.
|
||||||
|
// When it's off the screen, we also kinda don't.
|
||||||
|
struct render_geometry initial_geometry = {
|
||||||
|
// Set to 100 just to make sure if there's any attempt to use it,
|
||||||
|
// it actually gives plausible results instead of blowing up,
|
||||||
|
// e.g. on zero division.
|
||||||
|
.allocation_width = 100,
|
||||||
|
.allocation_height = 100,
|
||||||
|
.widget_to_layout = {
|
||||||
|
.origin_x = 0,
|
||||||
|
.origin_y = 0,
|
||||||
|
.scale = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
priv->render_geometry = initial_geometry;
|
||||||
|
|
||||||
g_signal_connect (eekservice,
|
g_signal_connect (eekservice,
|
||||||
"notify::keyboard",
|
"notify::keyboard",
|
||||||
G_CALLBACK(on_notify_keyboard),
|
G_CALLBACK(on_notify_keyboard),
|
||||||
|
|||||||
@ -28,6 +28,7 @@
|
|||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
#include "eek/eek-renderer.h"
|
||||||
#include "eek/eek-types.h"
|
#include "eek/eek-types.h"
|
||||||
|
|
||||||
struct submission;
|
struct submission;
|
||||||
|
|||||||
@ -18,8 +18,6 @@
|
|||||||
* 02110-1301 USA
|
* 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
@ -33,10 +31,6 @@
|
|||||||
static void render_button_label (cairo_t *cr, GtkStyleContext *ctx,
|
static void render_button_label (cairo_t *cr, GtkStyleContext *ctx,
|
||||||
const gchar *label, EekBounds bounds);
|
const gchar *label, EekBounds bounds);
|
||||||
|
|
||||||
void eek_render_button (EekRenderer *self,
|
|
||||||
cairo_t *cr, const struct squeek_button *button,
|
|
||||||
gboolean pressed, gboolean locked);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
render_outline (cairo_t *cr,
|
render_outline (cairo_t *cr,
|
||||||
GtkStyleContext *ctx,
|
GtkStyleContext *ctx,
|
||||||
@ -60,21 +54,21 @@ render_outline (cairo_t *cr,
|
|||||||
position.x, position.y, position.width, position.height);
|
position.x, position.y, position.width, position.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void render_button_in_context(gint scale_factor,
|
/// Rust interface
|
||||||
|
void eek_render_button_in_context(uint32_t scale_factor,
|
||||||
cairo_t *cr,
|
cairo_t *cr,
|
||||||
GtkStyleContext *ctx,
|
GtkStyleContext *ctx,
|
||||||
const struct squeek_button *button) {
|
EekBounds bounds,
|
||||||
|
const char *icon_name,
|
||||||
|
const gchar *label) {
|
||||||
/* blank background */
|
/* blank background */
|
||||||
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
|
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
|
||||||
cairo_paint (cr);
|
cairo_paint (cr);
|
||||||
|
|
||||||
EekBounds bounds = squeek_button_get_bounds(button);
|
|
||||||
render_outline (cr, ctx, bounds);
|
render_outline (cr, ctx, bounds);
|
||||||
cairo_paint (cr);
|
cairo_paint (cr);
|
||||||
|
|
||||||
/* render icon (if any) */
|
/* render icon (if any) */
|
||||||
const char *icon_name = squeek_button_get_icon_name(button);
|
|
||||||
|
|
||||||
if (icon_name) {
|
if (icon_name) {
|
||||||
cairo_surface_t *icon_surface =
|
cairo_surface_t *icon_surface =
|
||||||
eek_renderer_get_icon_surface (icon_name, 16, scale_factor);
|
eek_renderer_get_icon_surface (icon_name, 16, scale_factor);
|
||||||
@ -104,25 +98,27 @@ static void render_button_in_context(gint scale_factor,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const gchar *label = squeek_button_get_label(button);
|
|
||||||
if (label) {
|
if (label) {
|
||||||
render_button_label (cr, ctx, label, squeek_button_get_bounds(button));
|
render_button_label (cr, ctx, label, bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
/// Prepare context for drawing the button.
|
||||||
eek_render_button (EekRenderer *self,
|
/// The context MUST be released using the corresponing "put" procedure
|
||||||
cairo_t *cr,
|
/// before drawing the next button.
|
||||||
const struct squeek_button *button,
|
/// Interface for Rust.
|
||||||
gboolean pressed,
|
GtkStyleContext *
|
||||||
gboolean locked)
|
eek_get_style_context_for_button (EekRenderer *self,
|
||||||
|
const char *name,
|
||||||
|
const char *outline_name,
|
||||||
|
const char *locked_class,
|
||||||
|
uint64_t pressed)
|
||||||
{
|
{
|
||||||
GtkStyleContext *ctx = self->button_context;
|
GtkStyleContext *ctx = self->button_context;
|
||||||
/* Set the name of the button on the widget path, using the name obtained
|
/* Set the name of the button on the widget path, using the name obtained
|
||||||
from the button's symbol. */
|
from the button's symbol. */
|
||||||
g_autoptr (GtkWidgetPath) path = NULL;
|
g_autoptr (GtkWidgetPath) path = NULL;
|
||||||
path = gtk_widget_path_copy (gtk_style_context_get_path (ctx));
|
path = gtk_widget_path_copy (gtk_style_context_get_path (ctx));
|
||||||
const char *name = squeek_button_get_name(button);
|
|
||||||
gtk_widget_path_iter_set_name (path, -1, name);
|
gtk_widget_path_iter_set_name (path, -1, name);
|
||||||
|
|
||||||
/* Update the style context with the updated widget path. */
|
/* Update the style context with the updated widget path. */
|
||||||
@ -131,19 +127,22 @@ eek_render_button (EekRenderer *self,
|
|||||||
(pressed) or normal. */
|
(pressed) or normal. */
|
||||||
gtk_style_context_set_state(ctx,
|
gtk_style_context_set_state(ctx,
|
||||||
pressed ? GTK_STATE_FLAG_ACTIVE : GTK_STATE_FLAG_NORMAL);
|
pressed ? GTK_STATE_FLAG_ACTIVE : GTK_STATE_FLAG_NORMAL);
|
||||||
const char *outline_name = squeek_button_get_outline_name(button);
|
if (locked_class) {
|
||||||
if (locked) {
|
gtk_style_context_add_class(ctx, locked_class);
|
||||||
gtk_style_context_add_class(ctx, "locked");
|
|
||||||
}
|
}
|
||||||
gtk_style_context_add_class(ctx, outline_name);
|
gtk_style_context_add_class(ctx, outline_name);
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
render_button_in_context(self->scale_factor, cr, ctx, button);
|
/// Interface for Rust.
|
||||||
|
void eek_put_style_context_for_button(GtkStyleContext *ctx,
|
||||||
|
const char *outline_name,
|
||||||
|
const char *locked_class) {
|
||||||
// Save and restore functions don't work if gtk_render_* was used in between
|
// Save and restore functions don't work if gtk_render_* was used in between
|
||||||
gtk_style_context_set_state(ctx, GTK_STATE_FLAG_NORMAL);
|
gtk_style_context_set_state(ctx, GTK_STATE_FLAG_NORMAL);
|
||||||
gtk_style_context_remove_class(ctx, outline_name);
|
gtk_style_context_remove_class(ctx, outline_name);
|
||||||
if (locked) {
|
if (locked_class) {
|
||||||
gtk_style_context_remove_class(ctx, "locked");
|
gtk_style_context_remove_class(ctx, locked_class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,22 +193,23 @@ render_button_label (cairo_t *cr,
|
|||||||
// FIXME: Pass just the active modifiers instead of entire submission
|
// FIXME: Pass just the active modifiers instead of entire submission
|
||||||
void
|
void
|
||||||
eek_renderer_render_keyboard (EekRenderer *self,
|
eek_renderer_render_keyboard (EekRenderer *self,
|
||||||
|
struct render_geometry geometry,
|
||||||
struct submission *submission,
|
struct submission *submission,
|
||||||
cairo_t *cr,
|
cairo_t *cr,
|
||||||
LevelKeyboard *keyboard)
|
LevelKeyboard *keyboard)
|
||||||
{
|
{
|
||||||
g_return_if_fail (self->allocation_width > 0.0);
|
g_return_if_fail (geometry.allocation_width > 0.0);
|
||||||
g_return_if_fail (self->allocation_height > 0.0);
|
g_return_if_fail (geometry.allocation_height > 0.0);
|
||||||
|
|
||||||
/* Paint the background covering the entire widget area */
|
/* Paint the background covering the entire widget area */
|
||||||
gtk_render_background (self->view_context,
|
gtk_render_background (self->view_context,
|
||||||
cr,
|
cr,
|
||||||
0, 0,
|
0, 0,
|
||||||
self->allocation_width, self->allocation_height);
|
geometry.allocation_width, geometry.allocation_height);
|
||||||
|
|
||||||
cairo_save(cr);
|
cairo_save(cr);
|
||||||
cairo_translate (cr, self->widget_to_layout.origin_x, self->widget_to_layout.origin_y);
|
cairo_translate (cr, geometry.widget_to_layout.origin_x, geometry.widget_to_layout.origin_y);
|
||||||
cairo_scale (cr, self->widget_to_layout.scale, self->widget_to_layout.scale);
|
cairo_scale (cr, geometry.widget_to_layout.scale, geometry.widget_to_layout.scale);
|
||||||
|
|
||||||
squeek_draw_layout_base_view(keyboard->layout, self, cr);
|
squeek_draw_layout_base_view(keyboard->layout, self, cr);
|
||||||
squeek_layout_draw_all_changed(keyboard->layout, self, cr, submission);
|
squeek_layout_draw_all_changed(keyboard->layout, self, cr, submission);
|
||||||
@ -261,8 +261,6 @@ static void
|
|||||||
renderer_init (EekRenderer *self)
|
renderer_init (EekRenderer *self)
|
||||||
{
|
{
|
||||||
self->pcontext = NULL;
|
self->pcontext = NULL;
|
||||||
self->allocation_width = 0.0;
|
|
||||||
self->allocation_height = 0.0;
|
|
||||||
self->scale_factor = 1;
|
self->scale_factor = 1;
|
||||||
|
|
||||||
self->css_provider = squeek_load_style();
|
self->css_provider = squeek_load_style();
|
||||||
@ -309,22 +307,18 @@ eek_renderer_new (LevelKeyboard *keyboard,
|
|||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
struct render_geometry
|
||||||
eek_renderer_set_allocation_size (EekRenderer *renderer,
|
eek_render_geometry_from_allocation_size (struct squeek_layout *layout,
|
||||||
struct squeek_layout *layout,
|
|
||||||
gdouble width,
|
gdouble width,
|
||||||
gdouble height)
|
gdouble height)
|
||||||
{
|
{
|
||||||
g_return_if_fail (width > 0.0 && height > 0.0);
|
struct render_geometry ret = {
|
||||||
|
.allocation_width = width,
|
||||||
renderer->allocation_width = width;
|
.allocation_height = height,
|
||||||
renderer->allocation_height = height;
|
.widget_to_layout = squeek_layout_calculate_transformation(
|
||||||
|
layout, width, height),
|
||||||
renderer->widget_to_layout = squeek_layout_calculate_transformation(
|
};
|
||||||
layout,
|
return ret;
|
||||||
renderer->allocation_width, renderer->allocation_height);
|
|
||||||
|
|
||||||
// This is where size-dependent surfaces would be released
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -333,6 +327,11 @@ eek_renderer_set_scale_factor (EekRenderer *renderer, gint scale)
|
|||||||
renderer->scale_factor = scale;
|
renderer->scale_factor = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Rust interface.
|
||||||
|
uint32_t eek_renderer_get_scale_factor(EekRenderer *renderer) {
|
||||||
|
return renderer->scale_factor;
|
||||||
|
}
|
||||||
|
|
||||||
cairo_surface_t *
|
cairo_surface_t *
|
||||||
eek_renderer_get_icon_surface (const gchar *icon_name,
|
eek_renderer_get_icon_surface (const gchar *icon_name,
|
||||||
gint size,
|
gint size,
|
||||||
@ -356,8 +355,3 @@ eek_renderer_get_icon_surface (const gchar *icon_name,
|
|||||||
}
|
}
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct transformation
|
|
||||||
eek_renderer_get_transformation (EekRenderer *renderer) {
|
|
||||||
return renderer->widget_to_layout;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -41,22 +41,23 @@ typedef struct EekRenderer
|
|||||||
gchar *extra_style; // owned
|
gchar *extra_style; // owned
|
||||||
|
|
||||||
// Mutable state
|
// Mutable state
|
||||||
|
gint scale_factor; /* the outputs scale factor */
|
||||||
|
} EekRenderer;
|
||||||
|
|
||||||
|
|
||||||
|
/// Mutable part of the renderer state.
|
||||||
|
/// TODO: Possibly should include scale factor.
|
||||||
|
struct render_geometry {
|
||||||
/// Background extents
|
/// Background extents
|
||||||
gdouble allocation_width;
|
gdouble allocation_width;
|
||||||
gdouble allocation_height;
|
gdouble allocation_height;
|
||||||
gint scale_factor; /* the outputs scale factor */
|
|
||||||
/// Coords transformation
|
/// Coords transformation
|
||||||
struct transformation widget_to_layout;
|
struct transformation widget_to_layout;
|
||||||
} EekRenderer;
|
};
|
||||||
|
|
||||||
|
|
||||||
GType eek_renderer_get_type (void) G_GNUC_CONST;
|
GType eek_renderer_get_type (void) G_GNUC_CONST;
|
||||||
EekRenderer *eek_renderer_new (LevelKeyboard *keyboard,
|
EekRenderer *eek_renderer_new (LevelKeyboard *keyboard,
|
||||||
PangoContext *pcontext);
|
PangoContext *pcontext);
|
||||||
void eek_renderer_set_allocation_size
|
|
||||||
(EekRenderer *renderer, struct squeek_layout *layout,
|
|
||||||
gdouble width,
|
|
||||||
gdouble height);
|
|
||||||
void eek_renderer_set_scale_factor (EekRenderer *renderer,
|
void eek_renderer_set_scale_factor (EekRenderer *renderer,
|
||||||
gint scale);
|
gint scale);
|
||||||
|
|
||||||
@ -64,13 +65,14 @@ cairo_surface_t *eek_renderer_get_icon_surface(const gchar *icon_name,
|
|||||||
gint size,
|
gint size,
|
||||||
gint scale);
|
gint scale);
|
||||||
|
|
||||||
void eek_renderer_render_keyboard (EekRenderer *renderer, struct submission *submission,
|
void eek_renderer_render_keyboard (EekRenderer *renderer, struct render_geometry geometry, struct submission *submission,
|
||||||
cairo_t *cr, LevelKeyboard *keyboard);
|
cairo_t *cr, LevelKeyboard *keyboard);
|
||||||
void
|
void
|
||||||
eek_renderer_free (EekRenderer *self);
|
eek_renderer_free (EekRenderer *self);
|
||||||
|
|
||||||
struct transformation
|
struct render_geometry
|
||||||
eek_renderer_get_transformation (EekRenderer *renderer);
|
eek_render_geometry_from_allocation_size (struct squeek_layout *layout,
|
||||||
|
gdouble width, gdouble height);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
#endif /* EEK_RENDERER_H */
|
#endif /* EEK_RENDERER_H */
|
||||||
|
|||||||
@ -90,13 +90,5 @@ struct transformation {
|
|||||||
gdouble scale;
|
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
|
G_END_DECLS
|
||||||
#endif /* EEK_TYPES_H */
|
#endif /* EEK_TYPES_H */
|
||||||
|
|||||||
@ -294,8 +294,8 @@
|
|||||||
|
|
||||||
The serial number reflects the last state of the zwp_input_method_v2
|
The serial number reflects the last state of the zwp_input_method_v2
|
||||||
object known to the client. The value of the serial argument must be
|
object known to the client. The value of the serial argument must be
|
||||||
equal to the number of commit requests already issued on that object.
|
equal to the number of done events already issued on that object.
|
||||||
When the compositor receives a done event with a serial different than
|
When the compositor receives a commit request with a serial different than
|
||||||
the number of past commit requests, it must proceed as normal, except
|
the number of past commit requests, it must proceed as normal, except
|
||||||
it should not change the current state of the zwp_input_method_v2
|
it should not change the current state of the zwp_input_method_v2
|
||||||
object.
|
object.
|
||||||
|
|||||||
@ -10,13 +10,14 @@ pub struct KeySym(pub String);
|
|||||||
type View = String;
|
type View = String;
|
||||||
|
|
||||||
/// Use to send modified keypresses
|
/// Use to send modified keypresses
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum Modifier {
|
pub enum Modifier {
|
||||||
/// Control and Alt are the only modifiers
|
/// Control and Alt are the only modifiers
|
||||||
/// which doesn't interfere with levels,
|
/// which doesn't interfere with levels,
|
||||||
/// so it's simple to implement as levels are deprecated in squeekboard.
|
/// so it's simple to implement as levels are deprecated in squeekboard.
|
||||||
Control,
|
Control,
|
||||||
Alt,
|
Alt,
|
||||||
|
Mod4,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Action to perform on the keypress and, in reverse, on keyrelease
|
/// Action to perform on the keypress and, in reverse, on keyrelease
|
||||||
@ -29,6 +30,11 @@ pub enum Action {
|
|||||||
lock: View,
|
lock: View,
|
||||||
/// When unlocked by pressing it or emitting a key
|
/// When unlocked by pressing it or emitting a key
|
||||||
unlock: View,
|
unlock: View,
|
||||||
|
/// Whether key has a latched state
|
||||||
|
/// that pops when another key is pressed.
|
||||||
|
latches: bool,
|
||||||
|
/// Should take on *locked* appearance whenever latch comes back to those views.
|
||||||
|
looks_locked_from: Vec<View>,
|
||||||
},
|
},
|
||||||
/// Hold this modifier for as long as the button is pressed
|
/// Hold this modifier for as long as the button is pressed
|
||||||
ApplyModifier(Modifier),
|
ApplyModifier(Modifier),
|
||||||
@ -48,14 +54,24 @@ pub enum Action {
|
|||||||
impl Action {
|
impl Action {
|
||||||
pub fn is_locked(&self, view_name: &str) -> bool {
|
pub fn is_locked(&self, view_name: &str) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Action::LockView { lock, unlock: _ } => lock == view_name,
|
Action::LockView { lock, unlock: _, latches: _, looks_locked_from: _ } => lock == view_name,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn has_locked_appearance_from(&self, locked_view_name: &str) -> bool {
|
||||||
|
match self {
|
||||||
|
Action::LockView { lock: _, unlock: _, latches: _, looks_locked_from } => {
|
||||||
|
looks_locked_from.iter()
|
||||||
|
.find(|view| locked_view_name == view.as_str())
|
||||||
|
.is_some()
|
||||||
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn is_active(&self, view_name: &str) -> bool {
|
pub fn is_active(&self, view_name: &str) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Action::SetView(view) => view == view_name,
|
Action::SetView(view) => view == view_name,
|
||||||
Action::LockView { lock, unlock: _ } => lock == view_name,
|
Action::LockView { lock, unlock: _, latches: _, looks_locked_from: _ } => lock == view_name,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/data.rs
17
src/data.rs
@ -289,7 +289,13 @@ struct ButtonMeta {
|
|||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
enum Action {
|
enum Action {
|
||||||
#[serde(rename="locking")]
|
#[serde(rename="locking")]
|
||||||
Locking { lock_view: String, unlock_view: String },
|
Locking {
|
||||||
|
lock_view: String,
|
||||||
|
unlock_view: String,
|
||||||
|
pops: Option<bool>,
|
||||||
|
#[serde(default)]
|
||||||
|
looks_locked_from: Vec<String>,
|
||||||
|
},
|
||||||
#[serde(rename="set_view")]
|
#[serde(rename="set_view")]
|
||||||
SetView(String),
|
SetView(String),
|
||||||
#[serde(rename="show_prefs")]
|
#[serde(rename="show_prefs")]
|
||||||
@ -600,7 +606,9 @@ fn create_action<H: logging::Handler>(
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
SubmitData::Action(Action::Locking {
|
SubmitData::Action(Action::Locking {
|
||||||
lock_view, unlock_view
|
lock_view, unlock_view,
|
||||||
|
pops,
|
||||||
|
looks_locked_from,
|
||||||
}) => ::action::Action::LockView {
|
}) => ::action::Action::LockView {
|
||||||
lock: filter_view_name(
|
lock: filter_view_name(
|
||||||
name,
|
name,
|
||||||
@ -614,6 +622,8 @@ fn create_action<H: logging::Handler>(
|
|||||||
&view_names,
|
&view_names,
|
||||||
warning_handler,
|
warning_handler,
|
||||||
),
|
),
|
||||||
|
latches: pops.unwrap_or(true),
|
||||||
|
looks_locked_from,
|
||||||
},
|
},
|
||||||
SubmitData::Action(
|
SubmitData::Action(
|
||||||
Action::ShowPrefs
|
Action::ShowPrefs
|
||||||
@ -658,6 +668,9 @@ fn create_action<H: logging::Handler>(
|
|||||||
Modifier::Alt => action::Action::ApplyModifier(
|
Modifier::Alt => action::Action::ApplyModifier(
|
||||||
action::Modifier::Alt,
|
action::Modifier::Alt,
|
||||||
),
|
),
|
||||||
|
Modifier::Mod4 => action::Action::ApplyModifier(
|
||||||
|
action::Modifier::Mod4,
|
||||||
|
),
|
||||||
unsupported_modifier => {
|
unsupported_modifier => {
|
||||||
warning_handler.handle(
|
warning_handler.handle(
|
||||||
logging::Level::Bug,
|
logging::Level::Bug,
|
||||||
|
|||||||
211
src/drawing.rs
211
src/drawing.rs
@ -3,20 +3,24 @@
|
|||||||
use cairo;
|
use cairo;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use ::action::Action;
|
use ::action::{ Action, Modifier };
|
||||||
use ::keyboard;
|
use ::keyboard;
|
||||||
use ::layout::{ Button, Layout };
|
use ::layout::{ Button, Label, LatchedState, Layout };
|
||||||
use ::layout::c::{ EekGtkKeyboard, Point };
|
use ::layout::c::{ Bounds, EekGtkKeyboard, Point };
|
||||||
use ::submission::Submission;
|
use ::submission::Submission;
|
||||||
|
|
||||||
use glib::translate::FromGlibPtrNone;
|
use glib::translate::FromGlibPtrNone;
|
||||||
use gtk::WidgetExt;
|
use gtk::WidgetExt;
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
mod c {
|
mod c {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use cairo_sys;
|
use cairo_sys;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::{ c_char, c_void };
|
||||||
|
|
||||||
// This is constructed only in C, no need for warnings
|
// This is constructed only in C, no need for warnings
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -24,18 +28,44 @@ mod c {
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct EekRenderer(*const c_void);
|
pub struct EekRenderer(*const c_void);
|
||||||
|
|
||||||
#[no_mangle]
|
// This is constructed only in C, no need for warnings
|
||||||
|
/// Just don't clone this for no reason.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct GtkStyleContext(*const c_void);
|
||||||
|
|
||||||
|
|
||||||
extern "C" {
|
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)]
|
#[allow(improper_ctypes)]
|
||||||
pub fn eek_render_button(
|
pub fn eek_renderer_get_scale_factor(
|
||||||
renderer: EekRenderer,
|
renderer: EekRenderer,
|
||||||
|
) -> u32;
|
||||||
|
|
||||||
|
#[allow(improper_ctypes)]
|
||||||
|
pub fn eek_render_button_in_context(
|
||||||
|
scale_factor: u32,
|
||||||
cr: *mut cairo_sys::cairo_t,
|
cr: *mut cairo_sys::cairo_t,
|
||||||
button: *const Button,
|
ctx: GtkStyleContext,
|
||||||
|
bounds: Bounds,
|
||||||
|
icon_name: *const c_char,
|
||||||
|
label: *const c_char,
|
||||||
|
);
|
||||||
|
|
||||||
|
#[allow(improper_ctypes)]
|
||||||
|
pub fn eek_get_style_context_for_button(
|
||||||
|
renderer: EekRenderer,
|
||||||
|
name: *const c_char,
|
||||||
|
outline_name: *const c_char,
|
||||||
|
locked_class: *const c_char,
|
||||||
pressed: u64,
|
pressed: u64,
|
||||||
locked: u64,
|
) -> GtkStyleContext;
|
||||||
|
|
||||||
|
#[allow(improper_ctypes)]
|
||||||
|
pub fn eek_put_style_context_for_button(
|
||||||
|
ctx: GtkStyleContext,
|
||||||
|
outline_name: *const c_char,
|
||||||
|
locked_class: *const c_char,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,13 +85,16 @@ mod c {
|
|||||||
|
|
||||||
layout.foreach_visible_button(|offset, button| {
|
layout.foreach_visible_button(|offset, button| {
|
||||||
let state = RefCell::borrow(&button.state).clone();
|
let state = RefCell::borrow(&button.state).clone();
|
||||||
let active_mod = match &state.action {
|
|
||||||
Action::ApplyModifier(m) => active_modifiers.contains(m),
|
let locked = LockedStyle::from_action(
|
||||||
_ => false,
|
&state.action,
|
||||||
};
|
&active_modifiers,
|
||||||
let locked = state.action.is_active(&layout.current_view)
|
layout.get_view_latched(),
|
||||||
| active_mod;
|
&layout.current_view,
|
||||||
if state.pressed == keyboard::PressType::Pressed || locked {
|
);
|
||||||
|
if state.pressed == keyboard::PressType::Pressed
|
||||||
|
|| locked != LockedStyle::Free
|
||||||
|
{
|
||||||
render_button_at_position(
|
render_button_at_position(
|
||||||
renderer, &cr,
|
renderer, &cr,
|
||||||
offset,
|
offset,
|
||||||
@ -87,20 +120,55 @@ mod c {
|
|||||||
renderer, &cr,
|
renderer, &cr,
|
||||||
offset,
|
offset,
|
||||||
button.as_ref(),
|
button.as_ref(),
|
||||||
keyboard::PressType::Released, false,
|
keyboard::PressType::Released,
|
||||||
|
LockedStyle::Free,
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
enum LockedStyle {
|
||||||
|
Free,
|
||||||
|
Latched,
|
||||||
|
Locked,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LockedStyle {
|
||||||
|
fn from_action(
|
||||||
|
action: &Action,
|
||||||
|
mods: &HashSet<Modifier>,
|
||||||
|
latched_view: &LatchedState,
|
||||||
|
current_view: &str,
|
||||||
|
) -> LockedStyle {
|
||||||
|
let active_mod = match action {
|
||||||
|
Action::ApplyModifier(m) => mods.contains(m),
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let active_view = action.is_active(current_view);
|
||||||
|
let latched_button = match latched_view {
|
||||||
|
LatchedState::Not => false,
|
||||||
|
LatchedState::FromView(view) => !action.has_locked_appearance_from(view),
|
||||||
|
};
|
||||||
|
match (active_mod, active_view, latched_button) {
|
||||||
|
// Modifiers don't latch.
|
||||||
|
(true, _, _) => LockedStyle::Locked,
|
||||||
|
(false, true, false) => LockedStyle::Locked,
|
||||||
|
(false, true, true) => LockedStyle::Latched,
|
||||||
|
_ => LockedStyle::Free,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Renders a button at a position (button's own bounds ignored)
|
/// Renders a button at a position (button's own bounds ignored)
|
||||||
pub fn render_button_at_position(
|
fn render_button_at_position(
|
||||||
renderer: c::EekRenderer,
|
renderer: c::EekRenderer,
|
||||||
cr: &cairo::Context,
|
cr: &cairo::Context,
|
||||||
position: Point,
|
position: Point,
|
||||||
button: &Button,
|
button: &Button,
|
||||||
pressed: keyboard::PressType,
|
pressed: keyboard::PressType,
|
||||||
locked: bool,
|
locked: LockedStyle,
|
||||||
) {
|
) {
|
||||||
cr.save();
|
cr.save();
|
||||||
cr.translate(position.x, position.y);
|
cr.translate(position.x, position.y);
|
||||||
@ -109,19 +177,110 @@ pub fn render_button_at_position(
|
|||||||
button.size.width, button.size.height
|
button.size.width, button.size.height
|
||||||
);
|
);
|
||||||
cr.clip();
|
cr.clip();
|
||||||
unsafe {
|
|
||||||
c::eek_render_button(
|
let scale_factor = unsafe {
|
||||||
|
c::eek_renderer_get_scale_factor(renderer)
|
||||||
|
};
|
||||||
|
let bounds = button.get_bounds();
|
||||||
|
let (label_c, icon_name_c) = match &button.label {
|
||||||
|
Label::Text(text) => (text.as_ptr(), ptr::null()),
|
||||||
|
Label::IconName(name) => {
|
||||||
|
let l = unsafe {
|
||||||
|
// CStr doesn't allocate anything, so it only points to
|
||||||
|
// the 'static str, avoiding a memory leak
|
||||||
|
CStr::from_bytes_with_nul_unchecked(b"icon\0")
|
||||||
|
};
|
||||||
|
(l.as_ptr(), name.as_ptr())
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
with_button_context(
|
||||||
renderer,
|
renderer,
|
||||||
|
button,
|
||||||
|
pressed,
|
||||||
|
locked,
|
||||||
|
|ctx| unsafe {
|
||||||
|
// TODO: split into separate procedures:
|
||||||
|
// draw outline, draw label, draw icon.
|
||||||
|
c::eek_render_button_in_context(
|
||||||
|
scale_factor,
|
||||||
cairo::Context::to_raw_none(&cr),
|
cairo::Context::to_raw_none(&cr),
|
||||||
button as *const Button,
|
*ctx,
|
||||||
|
bounds,
|
||||||
|
icon_name_c,
|
||||||
|
label_c,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
cr.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_button_context<R, F: FnOnce(&c::GtkStyleContext) -> R>(
|
||||||
|
renderer: c::EekRenderer,
|
||||||
|
button: &Button,
|
||||||
|
pressed: keyboard::PressType,
|
||||||
|
locked: LockedStyle,
|
||||||
|
operation: F,
|
||||||
|
) -> R {
|
||||||
|
let outline_name_c = button.outline_name.as_ptr();
|
||||||
|
let locked_class_c = match locked {
|
||||||
|
LockedStyle::Free => ptr::null(),
|
||||||
|
LockedStyle::Locked => unsafe {
|
||||||
|
CStr::from_bytes_with_nul_unchecked(b"locked\0").as_ptr()
|
||||||
|
},
|
||||||
|
LockedStyle::Latched => unsafe {
|
||||||
|
CStr::from_bytes_with_nul_unchecked(b"latched\0").as_ptr()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let ctx = unsafe {
|
||||||
|
c::eek_get_style_context_for_button(
|
||||||
|
renderer,
|
||||||
|
button.name.as_ptr(),
|
||||||
|
outline_name_c,
|
||||||
|
locked_class_c,
|
||||||
pressed as u64,
|
pressed as u64,
|
||||||
locked as u64,
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
cr.restore();
|
|
||||||
|
let r = operation(&ctx);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
c::eek_put_style_context_for_button(
|
||||||
|
ctx,
|
||||||
|
outline_name_c,
|
||||||
|
locked_class_c,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn queue_redraw(keyboard: EekGtkKeyboard) {
|
pub fn queue_redraw(keyboard: EekGtkKeyboard) {
|
||||||
let widget = unsafe { gtk::Widget::from_glib_none(keyboard.0) };
|
let widget = unsafe { gtk::Widget::from_glib_none(keyboard.0) };
|
||||||
widget.queue_draw();
|
widget.queue_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_exit_only() {
|
||||||
|
assert_eq!(
|
||||||
|
LockedStyle::from_action(
|
||||||
|
&Action::LockView {
|
||||||
|
lock: "ab".into(),
|
||||||
|
unlock: "a".into(),
|
||||||
|
latches: true,
|
||||||
|
looks_locked_from: vec!["b".into()],
|
||||||
|
},
|
||||||
|
&HashSet::new(),
|
||||||
|
&LatchedState::FromView("b".into()),
|
||||||
|
"ab",
|
||||||
|
),
|
||||||
|
LockedStyle::Locked,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -32,9 +32,9 @@ pub mod c {
|
|||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct InputMethod(*const c_void);
|
pub struct InputMethod(*const c_void);
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
extern "C" {
|
extern "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_commit_string(im: *mut InputMethod, text: *const c_char);
|
||||||
@ -149,6 +149,8 @@ pub mod c {
|
|||||||
..IMProtocolState::default()
|
..IMProtocolState::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
imservice.serial += Wrapping(1u32);
|
||||||
|
|
||||||
if active_changed {
|
if active_changed {
|
||||||
(imservice.active_callback)(imservice.current.active);
|
(imservice.active_callback)(imservice.current.active);
|
||||||
if imservice.current.active {
|
if imservice.current.active {
|
||||||
@ -404,7 +406,6 @@ impl IMService {
|
|||||||
unsafe {
|
unsafe {
|
||||||
c::eek_input_method_commit(self.im, self.serial.0)
|
c::eek_input_method_commit(self.im, self.serial.0)
|
||||||
}
|
}
|
||||||
self.serial += Wrapping(1u32);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
false => Err(SubmitError::NotActive),
|
false => Err(SubmitError::NotActive),
|
||||||
|
|||||||
@ -26,13 +26,6 @@ struct squeek_layout_state {
|
|||||||
|
|
||||||
struct squeek_layout;
|
struct squeek_layout;
|
||||||
|
|
||||||
EekBounds squeek_button_get_bounds(const struct squeek_button*);
|
|
||||||
const char *squeek_button_get_label(const struct squeek_button*);
|
|
||||||
const char *squeek_button_get_icon_name(const struct squeek_button*);
|
|
||||||
const char *squeek_button_get_name(const struct squeek_button*);
|
|
||||||
const char *squeek_button_get_outline_name(const struct squeek_button*);
|
|
||||||
|
|
||||||
void squeek_button_print(const struct squeek_button* button);
|
|
||||||
|
|
||||||
struct transformation squeek_layout_calculate_transformation(
|
struct transformation squeek_layout_calculate_transformation(
|
||||||
const struct squeek_layout *layout,
|
const struct squeek_layout *layout,
|
||||||
|
|||||||
541
src/layout.rs
541
src/layout.rs
@ -41,9 +41,7 @@ pub mod c {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use gtk_sys;
|
use gtk_sys;
|
||||||
use std::ffi::CStr;
|
use std::os::raw::c_void;
|
||||||
use std::os::raw::{ c_char, c_void };
|
|
||||||
use std::ptr;
|
|
||||||
|
|
||||||
use std::ops::{ Add, Sub };
|
use std::ops::{ Add, Sub };
|
||||||
|
|
||||||
@ -52,7 +50,6 @@ pub mod c {
|
|||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct EekGtkKeyboard(pub *const gtk_sys::GtkWidget);
|
pub struct EekGtkKeyboard(pub *const gtk_sys::GtkWidget);
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[allow(improper_ctypes)]
|
#[allow(improper_ctypes)]
|
||||||
pub fn eek_gtk_keyboard_emit_feedback(
|
pub fn eek_gtk_keyboard_emit_feedback(
|
||||||
@ -163,64 +160,6 @@ pub mod c {
|
|||||||
|
|
||||||
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
|
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_button_get_bounds(button: *const ::layout::Button) -> Bounds {
|
|
||||||
let button = unsafe { &*button };
|
|
||||||
Bounds {
|
|
||||||
x: 0.0, y: 0.0,
|
|
||||||
width: button.size.width, height: button.size.height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_button_get_label(
|
|
||||||
button: *const ::layout::Button
|
|
||||||
) -> *const c_char {
|
|
||||||
let button = unsafe { &*button };
|
|
||||||
match &button.label {
|
|
||||||
Label::Text(text) => text.as_ptr(),
|
|
||||||
// returning static strings to C is a bit cumbersome
|
|
||||||
Label::IconName(_) => unsafe {
|
|
||||||
// CStr doesn't allocate anything, so it only points to
|
|
||||||
// the 'static str, avoiding a memory leak
|
|
||||||
CStr::from_bytes_with_nul_unchecked(b"icon\0")
|
|
||||||
}.as_ptr(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_button_get_icon_name(button: *const Button) -> *const c_char {
|
|
||||||
let button = unsafe { &*button };
|
|
||||||
match &button.label {
|
|
||||||
Label::Text(_) => ptr::null(),
|
|
||||||
Label::IconName(name) => name.as_ptr(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_button_get_name(button: *const Button) -> *const c_char {
|
|
||||||
let button = unsafe { &*button };
|
|
||||||
button.name.as_ptr()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_button_get_outline_name(button: *const Button) -> *const c_char {
|
|
||||||
let button = unsafe { &*button };
|
|
||||||
button.outline_name.as_ptr()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_button_print(button: *const ::layout::Button) {
|
|
||||||
let button = unsafe { &*button };
|
|
||||||
println!("{:?}", button);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Positions the layout contents within the available space.
|
/// Positions the layout contents within the available space.
|
||||||
/// The origin of the transformation is the point inside the margins.
|
/// The origin of the transformation is the point inside the margins.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -485,6 +424,15 @@ pub struct Button {
|
|||||||
pub state: Rc<RefCell<KeyState>>,
|
pub state: Rc<RefCell<KeyState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Button {
|
||||||
|
pub fn get_bounds(&self) -> c::Bounds {
|
||||||
|
c::Bounds {
|
||||||
|
x: 0.0, y: 0.0,
|
||||||
|
width: self.size.width, height: self.size.height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The graphical representation of a row of buttons
|
/// The graphical representation of a row of buttons
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Row {
|
pub struct Row {
|
||||||
@ -552,6 +500,7 @@ pub struct Spacing {
|
|||||||
pub button: f64,
|
pub button: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct View {
|
pub struct View {
|
||||||
/// Rows together with their offsets from the top left
|
/// Rows together with their offsets from the top left
|
||||||
rows: Vec<(c::Point, Row)>,
|
rows: Vec<(c::Point, Row)>,
|
||||||
@ -665,6 +614,19 @@ pub struct Margins {
|
|||||||
pub right: f64,
|
pub right: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum LatchedState {
|
||||||
|
/// Holds view to return to.
|
||||||
|
FromView(String),
|
||||||
|
Not,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LatchedState {
|
||||||
|
pub fn is_latched(&self) -> bool {
|
||||||
|
self != &LatchedState::Not
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: split into sth like
|
// TODO: split into sth like
|
||||||
// Arrangement (views) + details (keymap) + State (keys)
|
// Arrangement (views) + details (keymap) + State (keys)
|
||||||
/// State of the UI, contains the backend as well
|
/// State of the UI, contains the backend as well
|
||||||
@ -672,6 +634,12 @@ pub struct Layout {
|
|||||||
pub margins: Margins,
|
pub margins: Margins,
|
||||||
pub kind: ArrangementKind,
|
pub kind: ArrangementKind,
|
||||||
pub current_view: String,
|
pub current_view: String,
|
||||||
|
|
||||||
|
// If current view is latched,
|
||||||
|
// clicking any button that emits an action (erase, submit, set modifier)
|
||||||
|
// will cause lock buttons to unlatch.
|
||||||
|
view_latched: LatchedState,
|
||||||
|
|
||||||
// Views own the actual buttons which have state
|
// 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?
|
||||||
@ -718,6 +686,7 @@ impl Layout {
|
|||||||
Layout {
|
Layout {
|
||||||
kind,
|
kind,
|
||||||
current_view: "base".to_owned(),
|
current_view: "base".to_owned(),
|
||||||
|
view_latched: LatchedState::Not,
|
||||||
views: data.views,
|
views: data.views,
|
||||||
keymaps: data.keymaps,
|
keymaps: data.keymaps,
|
||||||
pressed_keys: HashSet::new(),
|
pressed_keys: HashSet::new(),
|
||||||
@ -743,6 +712,12 @@ impl Layout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Layout is passed around mutably,
|
||||||
|
// so better keep the field away from direct access.
|
||||||
|
pub fn get_view_latched(&self) -> &LatchedState {
|
||||||
|
&self.view_latched
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates size without margins
|
/// Calculates size without margins
|
||||||
fn calculate_inner_size(&self) -> Size {
|
fn calculate_inner_size(&self) -> Size {
|
||||||
View::calculate_super_size(
|
View::calculate_super_size(
|
||||||
@ -818,8 +793,117 @@ impl Layout {
|
|||||||
}
|
}
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn apply_view_transition(
|
||||||
|
&mut self,
|
||||||
|
action: &Action,
|
||||||
|
) {
|
||||||
|
let (transition, new_latched) = Layout::process_action_for_view(
|
||||||
|
action,
|
||||||
|
&self.current_view,
|
||||||
|
&self.view_latched,
|
||||||
|
);
|
||||||
|
|
||||||
|
match transition {
|
||||||
|
ViewTransition::UnlatchAll => self.unstick_locks(),
|
||||||
|
ViewTransition::ChangeTo(view) => try_set_view(self, view.into()),
|
||||||
|
ViewTransition::NoChange => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
self.view_latched = new_latched;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unlatch all latched keys,
|
||||||
|
/// so that the new view is the one before first press.
|
||||||
|
fn unstick_locks(&mut self) {
|
||||||
|
if let LatchedState::FromView(name) = self.view_latched.clone() {
|
||||||
|
match self.set_view(name.clone()) {
|
||||||
|
Ok(_) => { self.view_latched = LatchedState::Not; }
|
||||||
|
Err(e) => log_print!(
|
||||||
|
logging::Level::Bug,
|
||||||
|
"Bad view {}, can't unlatch ({:?})",
|
||||||
|
name,
|
||||||
|
e,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Last bool is new latch state.
|
||||||
|
/// It doesn't make sense when the result carries UnlatchAll,
|
||||||
|
/// but let's not be picky.
|
||||||
|
///
|
||||||
|
/// Although the state is not defined at the keys
|
||||||
|
/// (it's in the relationship between view and action),
|
||||||
|
/// keys go through the following stages when clicked repeatedly:
|
||||||
|
/// unlocked+unlatched -> locked+latched -> locked+unlatched
|
||||||
|
/// -> unlocked+unlatched
|
||||||
|
fn process_action_for_view<'a>(
|
||||||
|
action: &'a Action,
|
||||||
|
current_view: &str,
|
||||||
|
latched: &LatchedState,
|
||||||
|
) -> (ViewTransition<'a>, LatchedState) {
|
||||||
|
match action {
|
||||||
|
Action::Submit { text: _, keys: _ }
|
||||||
|
| Action::Erase
|
||||||
|
| Action::ApplyModifier(_)
|
||||||
|
=> {
|
||||||
|
let t = match latched {
|
||||||
|
LatchedState::FromView(_) => ViewTransition::UnlatchAll,
|
||||||
|
LatchedState::Not => ViewTransition::NoChange,
|
||||||
|
};
|
||||||
|
(t, LatchedState::Not)
|
||||||
|
},
|
||||||
|
Action::SetView(view) => (
|
||||||
|
ViewTransition::ChangeTo(view),
|
||||||
|
LatchedState::Not,
|
||||||
|
),
|
||||||
|
Action::LockView { lock, unlock, latches, looks_locked_from: _ } => {
|
||||||
|
use self::ViewTransition as VT;
|
||||||
|
let locked = action.is_locked(current_view);
|
||||||
|
match (locked, latched, latches) {
|
||||||
|
// Was unlocked, now make locked but latched.
|
||||||
|
(false, LatchedState::Not, true) => (
|
||||||
|
VT::ChangeTo(lock),
|
||||||
|
LatchedState::FromView(current_view.into()),
|
||||||
|
),
|
||||||
|
// Layout is latched for reason other than this button.
|
||||||
|
(false, LatchedState::FromView(view), true) => (
|
||||||
|
VT::ChangeTo(lock),
|
||||||
|
LatchedState::FromView(view.clone()),
|
||||||
|
),
|
||||||
|
// Was latched, now only locked.
|
||||||
|
(true, LatchedState::FromView(_), true)
|
||||||
|
=> (VT::NoChange, LatchedState::Not),
|
||||||
|
// Was unlocked, can't latch so now make fully locked.
|
||||||
|
(false, _, false)
|
||||||
|
=> (VT::ChangeTo(lock), LatchedState::Not),
|
||||||
|
// Was locked, now make unlocked.
|
||||||
|
(true, _, _)
|
||||||
|
=> (VT::ChangeTo(unlock), LatchedState::Not),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => (ViewTransition::NoChange, latched.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
enum ViewTransition<'a> {
|
||||||
|
ChangeTo(&'a str),
|
||||||
|
UnlatchAll,
|
||||||
|
NoChange,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_set_view(layout: &mut Layout, view_name: &str) {
|
||||||
|
layout.set_view(view_name.into())
|
||||||
|
.or_print(
|
||||||
|
logging::Problem::Bug,
|
||||||
|
&format!("Bad view {}, ignoring", view_name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
mod procedures {
|
mod procedures {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -898,67 +982,6 @@ pub struct UIBackend {
|
|||||||
mod seat {
|
mod seat {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn try_set_view(layout: &mut Layout, view_name: String) {
|
|
||||||
layout.set_view(view_name.clone())
|
|
||||||
.or_print(
|
|
||||||
logging::Problem::Bug,
|
|
||||||
&format!("Bad view {}, ignoring", view_name),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A vessel holding an obligation to switch view.
|
|
||||||
/// Use with #[must_use]
|
|
||||||
struct ViewChange<'a> {
|
|
||||||
layout: &'a mut Layout,
|
|
||||||
view_name: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ViewChange<'a> {
|
|
||||||
fn choose_view(self, view_name: String) -> ViewChange<'a> {
|
|
||||||
ViewChange {
|
|
||||||
view_name: Some(view_name),
|
|
||||||
..self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn apply(self) {
|
|
||||||
if let Some(name) = self.view_name {
|
|
||||||
try_set_view(self.layout, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find all impermanent view changes and undo them in an arbitrary order.
|
|
||||||
/// Return an obligation to actually switch the view.
|
|
||||||
/// The final view is the "unlock" view
|
|
||||||
/// from one of the currently stuck keys.
|
|
||||||
// As long as only one stuck button is used, this should be fine.
|
|
||||||
// This is guaranteed because pressing a lock button unlocks all others.
|
|
||||||
// TODO: Make some broader guarantee about the resulting view,
|
|
||||||
// e.g. by maintaining a stack of stuck keys.
|
|
||||||
#[must_use]
|
|
||||||
fn unstick_locks(layout: &mut Layout) -> ViewChange {
|
|
||||||
let mut new_view = None;
|
|
||||||
for key in layout.get_locked_keys().clone() {
|
|
||||||
let key: &Rc<RefCell<KeyState>> = key.borrow();
|
|
||||||
let key = RefCell::borrow(key);
|
|
||||||
match &key.action {
|
|
||||||
Action::LockView { lock: _, unlock: view } => {
|
|
||||||
new_view = Some(view.clone());
|
|
||||||
},
|
|
||||||
a => log_print!(
|
|
||||||
logging::Level::Bug,
|
|
||||||
"Non-locking action {:?} was found inside locked keys",
|
|
||||||
a,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewChange {
|
|
||||||
layout,
|
|
||||||
view_name: new_view,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle_press_key(
|
pub fn handle_press_key(
|
||||||
layout: &mut Layout,
|
layout: &mut Layout,
|
||||||
submission: &mut Submission,
|
submission: &mut Submission,
|
||||||
@ -1018,37 +1041,22 @@ mod seat {
|
|||||||
};
|
};
|
||||||
let action = key.action.clone();
|
let action = key.action.clone();
|
||||||
|
|
||||||
|
layout.apply_view_transition(&action);
|
||||||
|
|
||||||
// update
|
// update
|
||||||
let key = key.into_released();
|
let key = key.into_released();
|
||||||
|
|
||||||
// process changes
|
// process non-view switching
|
||||||
match action {
|
match action {
|
||||||
Action::Submit { text: _, keys: _ }
|
Action::Submit { text: _, keys: _ }
|
||||||
| Action::Erase
|
| Action::Erase
|
||||||
=> {
|
=> {
|
||||||
unstick_locks(layout).apply();
|
|
||||||
submission.handle_release(KeyState::get_id(rckey), time);
|
submission.handle_release(KeyState::get_id(rckey), time);
|
||||||
},
|
},
|
||||||
Action::SetView(view) => {
|
|
||||||
try_set_view(layout, view)
|
|
||||||
},
|
|
||||||
Action::LockView { lock, unlock } => {
|
|
||||||
let gets_locked = !key.action.is_locked(&layout.current_view);
|
|
||||||
unstick_locks(layout)
|
|
||||||
// It doesn't matter what the resulting view should be,
|
|
||||||
// it's getting changed anyway.
|
|
||||||
.choose_view(
|
|
||||||
match gets_locked {
|
|
||||||
true => lock.clone(),
|
|
||||||
false => unlock.clone(),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.apply()
|
|
||||||
},
|
|
||||||
Action::ApplyModifier(modifier) => {
|
Action::ApplyModifier(modifier) => {
|
||||||
// FIXME: key id is unneeded with stateless locks
|
// FIXME: key id is unneeded with stateless locks
|
||||||
let key_id = KeyState::get_id(rckey);
|
let key_id = KeyState::get_id(rckey);
|
||||||
let gets_locked = !submission.is_modifier_active(modifier.clone());
|
let gets_locked = !submission.is_modifier_active(modifier);
|
||||||
match gets_locked {
|
match gets_locked {
|
||||||
true => submission.handle_add_modifier(
|
true => submission.handle_add_modifier(
|
||||||
key_id,
|
key_id,
|
||||||
@ -1083,6 +1091,8 @@ mod seat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// Other keys are handled in view switcher before.
|
||||||
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
let pointer = ::util::Pointer(rckey.clone());
|
let pointer = ::util::Pointer(rckey.clone());
|
||||||
@ -1100,14 +1110,20 @@ mod test {
|
|||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use ::keyboard::PressType;
|
use ::keyboard::PressType;
|
||||||
|
|
||||||
pub fn make_state() -> Rc<RefCell<::keyboard::KeyState>> {
|
pub fn make_state_with_action(action: Action)
|
||||||
|
-> Rc<RefCell<::keyboard::KeyState>>
|
||||||
|
{
|
||||||
Rc::new(RefCell::new(::keyboard::KeyState {
|
Rc::new(RefCell::new(::keyboard::KeyState {
|
||||||
pressed: PressType::Released,
|
pressed: PressType::Released,
|
||||||
keycodes: Vec::new(),
|
keycodes: Vec::new(),
|
||||||
action: Action::SetView("default".into()),
|
action,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn make_state() -> Rc<RefCell<::keyboard::KeyState>> {
|
||||||
|
make_state_with_action(Action::SetView("default".into()))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn make_button_with_state(
|
pub fn make_button_with_state(
|
||||||
name: String,
|
name: String,
|
||||||
state: Rc<RefCell<::keyboard::KeyState>>,
|
state: Rc<RefCell<::keyboard::KeyState>>,
|
||||||
@ -1121,6 +1137,242 @@ mod test {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn latch_lock_unlock() {
|
||||||
|
let action = Action::LockView {
|
||||||
|
lock: "lock".into(),
|
||||||
|
unlock: "unlock".into(),
|
||||||
|
latches: true,
|
||||||
|
looks_locked_from: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Layout::process_action_for_view(&action, "unlock", &LatchedState::Not),
|
||||||
|
(ViewTransition::ChangeTo("lock"), LatchedState::FromView("unlock".into())),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Layout::process_action_for_view(&action, "lock", &LatchedState::FromView("unlock".into())),
|
||||||
|
(ViewTransition::NoChange, LatchedState::Not),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Layout::process_action_for_view(&action, "lock", &LatchedState::Not),
|
||||||
|
(ViewTransition::ChangeTo("unlock"), LatchedState::Not),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Layout::process_action_for_view(&Action::Erase, "lock", &LatchedState::FromView("base".into())),
|
||||||
|
(ViewTransition::UnlatchAll, LatchedState::Not),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn latch_pop_layout() {
|
||||||
|
let switch = Action::LockView {
|
||||||
|
lock: "locked".into(),
|
||||||
|
unlock: "base".into(),
|
||||||
|
latches: true,
|
||||||
|
looks_locked_from: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let submit = Action::Erase;
|
||||||
|
|
||||||
|
let view = View::new(vec![(
|
||||||
|
0.0,
|
||||||
|
Row::new(vec![
|
||||||
|
(
|
||||||
|
0.0,
|
||||||
|
make_button_with_state(
|
||||||
|
"switch".into(),
|
||||||
|
make_state_with_action(switch.clone())
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
1.0,
|
||||||
|
make_button_with_state(
|
||||||
|
"submit".into(),
|
||||||
|
make_state_with_action(submit.clone())
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
)]);
|
||||||
|
|
||||||
|
let mut layout = Layout {
|
||||||
|
current_view: "base".into(),
|
||||||
|
view_latched: LatchedState::Not,
|
||||||
|
keymaps: Vec::new(),
|
||||||
|
kind: ArrangementKind::Base,
|
||||||
|
pressed_keys: HashSet::new(),
|
||||||
|
margins: Margins {
|
||||||
|
top: 0.0,
|
||||||
|
left: 0.0,
|
||||||
|
right: 0.0,
|
||||||
|
bottom: 0.0,
|
||||||
|
},
|
||||||
|
views: hashmap! {
|
||||||
|
// Both can use the same structure.
|
||||||
|
// Switching doesn't depend on the view shape
|
||||||
|
// as long as the switching button is present.
|
||||||
|
"base".into() => (c::Point { x: 0.0, y: 0.0 }, view.clone()),
|
||||||
|
"locked".into() => (c::Point { x: 0.0, y: 0.0 }, view),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Basic cycle
|
||||||
|
layout.apply_view_transition(&switch);
|
||||||
|
assert_eq!(&layout.current_view, "locked");
|
||||||
|
layout.apply_view_transition(&switch);
|
||||||
|
assert_eq!(&layout.current_view, "locked");
|
||||||
|
layout.apply_view_transition(&submit);
|
||||||
|
assert_eq!(&layout.current_view, "locked");
|
||||||
|
layout.apply_view_transition(&switch);
|
||||||
|
assert_eq!(&layout.current_view, "base");
|
||||||
|
layout.apply_view_transition(&switch);
|
||||||
|
// Unlatch
|
||||||
|
assert_eq!(&layout.current_view, "locked");
|
||||||
|
layout.apply_view_transition(&submit);
|
||||||
|
assert_eq!(&layout.current_view, "base");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reverse_unlatch_layout() {
|
||||||
|
let switch = Action::LockView {
|
||||||
|
lock: "locked".into(),
|
||||||
|
unlock: "base".into(),
|
||||||
|
latches: true,
|
||||||
|
looks_locked_from: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let unswitch = Action::LockView {
|
||||||
|
lock: "locked".into(),
|
||||||
|
unlock: "unlocked".into(),
|
||||||
|
latches: false,
|
||||||
|
looks_locked_from: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let submit = Action::Erase;
|
||||||
|
|
||||||
|
let view = View::new(vec![(
|
||||||
|
0.0,
|
||||||
|
Row::new(vec![
|
||||||
|
(
|
||||||
|
0.0,
|
||||||
|
make_button_with_state(
|
||||||
|
"switch".into(),
|
||||||
|
make_state_with_action(switch.clone())
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
1.0,
|
||||||
|
make_button_with_state(
|
||||||
|
"submit".into(),
|
||||||
|
make_state_with_action(submit.clone())
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
)]);
|
||||||
|
|
||||||
|
let mut layout = Layout {
|
||||||
|
current_view: "base".into(),
|
||||||
|
view_latched: LatchedState::Not,
|
||||||
|
keymaps: Vec::new(),
|
||||||
|
kind: ArrangementKind::Base,
|
||||||
|
pressed_keys: HashSet::new(),
|
||||||
|
margins: Margins {
|
||||||
|
top: 0.0,
|
||||||
|
left: 0.0,
|
||||||
|
right: 0.0,
|
||||||
|
bottom: 0.0,
|
||||||
|
},
|
||||||
|
views: hashmap! {
|
||||||
|
// Both can use the same structure.
|
||||||
|
// Switching doesn't depend on the view shape
|
||||||
|
// as long as the switching button is present.
|
||||||
|
"base".into() => (c::Point { x: 0.0, y: 0.0 }, view.clone()),
|
||||||
|
"locked".into() => (c::Point { x: 0.0, y: 0.0 }, view.clone()),
|
||||||
|
"unlocked".into() => (c::Point { x: 0.0, y: 0.0 }, view),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
layout.apply_view_transition(&switch);
|
||||||
|
assert_eq!(&layout.current_view, "locked");
|
||||||
|
layout.apply_view_transition(&unswitch);
|
||||||
|
assert_eq!(&layout.current_view, "unlocked");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn latch_twopop_layout() {
|
||||||
|
let switch = Action::LockView {
|
||||||
|
lock: "locked".into(),
|
||||||
|
unlock: "base".into(),
|
||||||
|
latches: true,
|
||||||
|
looks_locked_from: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let switch_again = Action::LockView {
|
||||||
|
lock: "ĄĘ".into(),
|
||||||
|
unlock: "locked".into(),
|
||||||
|
latches: true,
|
||||||
|
looks_locked_from: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let submit = Action::Erase;
|
||||||
|
|
||||||
|
let view = View::new(vec![(
|
||||||
|
0.0,
|
||||||
|
Row::new(vec![
|
||||||
|
(
|
||||||
|
0.0,
|
||||||
|
make_button_with_state(
|
||||||
|
"switch".into(),
|
||||||
|
make_state_with_action(switch.clone())
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
1.0,
|
||||||
|
make_button_with_state(
|
||||||
|
"submit".into(),
|
||||||
|
make_state_with_action(submit.clone())
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
)]);
|
||||||
|
|
||||||
|
let mut layout = Layout {
|
||||||
|
current_view: "base".into(),
|
||||||
|
view_latched: LatchedState::Not,
|
||||||
|
keymaps: Vec::new(),
|
||||||
|
kind: ArrangementKind::Base,
|
||||||
|
pressed_keys: HashSet::new(),
|
||||||
|
margins: Margins {
|
||||||
|
top: 0.0,
|
||||||
|
left: 0.0,
|
||||||
|
right: 0.0,
|
||||||
|
bottom: 0.0,
|
||||||
|
},
|
||||||
|
views: hashmap! {
|
||||||
|
// All can use the same structure.
|
||||||
|
// Switching doesn't depend on the view shape
|
||||||
|
// as long as the switching button is present.
|
||||||
|
"base".into() => (c::Point { x: 0.0, y: 0.0 }, view.clone()),
|
||||||
|
"locked".into() => (c::Point { x: 0.0, y: 0.0 }, view.clone()),
|
||||||
|
"ĄĘ".into() => (c::Point { x: 0.0, y: 0.0 }, view),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Latch twice, then Ąto-unlatch across 2 levels
|
||||||
|
layout.apply_view_transition(&switch);
|
||||||
|
println!("{:?}", layout.view_latched);
|
||||||
|
assert_eq!(&layout.current_view, "locked");
|
||||||
|
layout.apply_view_transition(&switch_again);
|
||||||
|
println!("{:?}", layout.view_latched);
|
||||||
|
assert_eq!(&layout.current_view, "ĄĘ");
|
||||||
|
layout.apply_view_transition(&submit);
|
||||||
|
println!("{:?}", layout.view_latched);
|
||||||
|
assert_eq!(&layout.current_view, "base");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_centering() {
|
fn check_centering() {
|
||||||
// A B
|
// A B
|
||||||
@ -1193,6 +1445,7 @@ mod test {
|
|||||||
]);
|
]);
|
||||||
let layout = Layout {
|
let layout = Layout {
|
||||||
current_view: String::new(),
|
current_view: String::new(),
|
||||||
|
view_latched: LatchedState::Not,
|
||||||
keymaps: Vec::new(),
|
keymaps: Vec::new(),
|
||||||
kind: ArrangementKind::Base,
|
kind: ArrangementKind::Base,
|
||||||
pressed_keys: HashSet::new(),
|
pressed_keys: HashSet::new(),
|
||||||
|
|||||||
@ -24,7 +24,6 @@ mod c {
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct GnomeXkbInfo(*const c_void);
|
pub struct GnomeXkbInfo(*const c_void);
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
// from libc
|
// from libc
|
||||||
pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int;
|
pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int;
|
||||||
|
|||||||
@ -9,7 +9,6 @@ pub mod c {
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Manager(*const c_void);
|
pub struct Manager(*const c_void);
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn eekboard_context_service_set_overlay(
|
pub fn eekboard_context_service_set_overlay(
|
||||||
manager: Manager,
|
manager: Manager,
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
#ifndef POPOVER_H__
|
|
||||||
#define POPOVER_H__
|
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
#include "eek/eek-keyboard.h"
|
|
||||||
|
|
||||||
void squeek_popover_show(GtkWidget*, struct button_place);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -29,7 +29,6 @@ use ::logging::Warn;
|
|||||||
mod c {
|
mod c {
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn popover_open_settings_panel(panel: *const c_char);
|
pub fn popover_open_settings_panel(panel: *const c_char);
|
||||||
}
|
}
|
||||||
@ -437,7 +436,8 @@ pub fn show(
|
|||||||
|
|
||||||
let settings_action = gio::SimpleAction::new("settings", None);
|
let settings_action = gio::SimpleAction::new("settings", None);
|
||||||
settings_action.connect_activate(move |_, _| {
|
settings_action.connect_activate(move |_, _| {
|
||||||
unsafe { c::popover_open_settings_panel(CString::new("region").unwrap().as_ptr()) };
|
let s = CString::new("region").unwrap();
|
||||||
|
unsafe { c::popover_open_settings_panel(s.as_ptr()) };
|
||||||
});
|
});
|
||||||
|
|
||||||
let action_group = gio::SimpleActionGroup::new();
|
let action_group = gio::SimpleActionGroup::new();
|
||||||
|
|||||||
@ -39,6 +39,7 @@ const KEYBOARDS: &[(*const str, *const str)] = &[
|
|||||||
("epo", include_str!("../data/keyboards/epo.yaml")),
|
("epo", include_str!("../data/keyboards/epo.yaml")),
|
||||||
|
|
||||||
("es", include_str!("../data/keyboards/es.yaml")),
|
("es", include_str!("../data/keyboards/es.yaml")),
|
||||||
|
("es+cat", include_str!("../data/keyboards/es+cat.yaml")),
|
||||||
|
|
||||||
("fi", include_str!("../data/keyboards/fi.yaml")),
|
("fi", include_str!("../data/keyboards/fi.yaml")),
|
||||||
|
|
||||||
@ -47,6 +48,8 @@ const KEYBOARDS: &[(*const str, *const str)] = &[
|
|||||||
|
|
||||||
("gr", include_str!("../data/keyboards/gr.yaml")),
|
("gr", include_str!("../data/keyboards/gr.yaml")),
|
||||||
|
|
||||||
|
("il", include_str!("../data/keyboards/il.yaml")),
|
||||||
|
|
||||||
("ir", include_str!("../data/keyboards/ir.yaml")),
|
("ir", include_str!("../data/keyboards/ir.yaml")),
|
||||||
("ir_wide", include_str!("../data/keyboards/ir_wide.yaml")),
|
("ir_wide", include_str!("../data/keyboards/ir_wide.yaml")),
|
||||||
|
|
||||||
@ -66,10 +69,15 @@ const KEYBOARDS: &[(*const str, *const str)] = &[
|
|||||||
("se", include_str!("../data/keyboards/se.yaml")),
|
("se", include_str!("../data/keyboards/se.yaml")),
|
||||||
|
|
||||||
("th", include_str!("../data/keyboards/th.yaml")),
|
("th", include_str!("../data/keyboards/th.yaml")),
|
||||||
|
("th_wide", include_str!("../data/keyboards/th_wide.yaml")),
|
||||||
|
|
||||||
("ua", include_str!("../data/keyboards/ua.yaml")),
|
("ua", include_str!("../data/keyboards/ua.yaml")),
|
||||||
|
|
||||||
("us+colemak", include_str!("../data/keyboards/us+colemak.yaml")),
|
("us+colemak", include_str!("../data/keyboards/us+colemak.yaml")),
|
||||||
|
("us+colemak_wide", include_str!("../data/keyboards/us+colemak_wide.yaml")),
|
||||||
|
|
||||||
|
("us+dvorak", include_str!("../data/keyboards/us+dvorak.yaml")),
|
||||||
|
("us+dvorak_wide", include_str!("../data/keyboards/us+dvorak_wide.yaml")),
|
||||||
|
|
||||||
// Others
|
// Others
|
||||||
("number", include_str!("../data/keyboards/number.yaml")),
|
("number", include_str!("../data/keyboards/number.yaml")),
|
||||||
@ -114,6 +122,7 @@ const LAYOUT_NAMES: &[(*const str, *const str)] = &[
|
|||||||
("en-US", include_str!("../data/langs/en-US.txt")),
|
("en-US", include_str!("../data/langs/en-US.txt")),
|
||||||
("es-ES", include_str!("../data/langs/es-ES.txt")),
|
("es-ES", include_str!("../data/langs/es-ES.txt")),
|
||||||
("fur-IT", include_str!("../data/langs/fur-IT.txt")),
|
("fur-IT", include_str!("../data/langs/fur-IT.txt")),
|
||||||
|
("he-IL", include_str!("../data/langs/he-IL.txt")),
|
||||||
("ja-JP", include_str!("../data/langs/ja-JP.txt")),
|
("ja-JP", include_str!("../data/langs/ja-JP.txt")),
|
||||||
("pl-PL", include_str!("../data/langs/pl-PL.txt")),
|
("pl-PL", include_str!("../data/langs/pl-PL.txt")),
|
||||||
("ru-RU", include_str!("../data/langs/ru-RU.txt")),
|
("ru-RU", include_str!("../data/langs/ru-RU.txt")),
|
||||||
|
|||||||
@ -50,9 +50,16 @@ struct squeekboard {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
GMainLoop *loop;
|
||||||
static gboolean opt_system = FALSE;
|
static gboolean opt_system = FALSE;
|
||||||
static gchar *opt_address = NULL;
|
static gchar *opt_address = NULL;
|
||||||
|
|
||||||
|
static void
|
||||||
|
quit (void)
|
||||||
|
{
|
||||||
|
g_main_loop_quit (loop);
|
||||||
|
}
|
||||||
|
|
||||||
// D-Bus
|
// D-Bus
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -131,6 +138,67 @@ static const struct wl_registry_listener registry_listener = {
|
|||||||
#define SESSION_NAME "sm.puri.OSK0"
|
#define SESSION_NAME "sm.puri.OSK0"
|
||||||
|
|
||||||
GDBusProxy *_proxy = NULL;
|
GDBusProxy *_proxy = NULL;
|
||||||
|
GDBusProxy *_client_proxy = NULL;
|
||||||
|
gchar *_client_path = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_quit_response (GDBusProxy *proxy)
|
||||||
|
{
|
||||||
|
g_debug ("Calling EndSessionResponse");
|
||||||
|
g_dbus_proxy_call (proxy, "EndSessionResponse",
|
||||||
|
g_variant_new ("(bs)", TRUE, ""), G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
G_MAXINT, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
unregister_client (void)
|
||||||
|
{
|
||||||
|
g_autoptr (GError) error = NULL;
|
||||||
|
|
||||||
|
g_return_if_fail (G_IS_DBUS_PROXY (_proxy));
|
||||||
|
g_return_if_fail (_client_path != NULL);
|
||||||
|
|
||||||
|
g_debug ("Unregistering client");
|
||||||
|
|
||||||
|
g_dbus_proxy_call_sync (_proxy,
|
||||||
|
"UnregisterClient",
|
||||||
|
g_variant_new ("(o)", _client_path),
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
G_MAXINT,
|
||||||
|
NULL,
|
||||||
|
&error);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
g_warning ("Failed to unregister client: %s", error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_object (&_client_proxy);
|
||||||
|
g_clear_pointer (&_client_path, g_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void client_proxy_signal (GDBusProxy *proxy,
|
||||||
|
const gchar *sender_name,
|
||||||
|
const gchar *signal_name,
|
||||||
|
GVariant *parameters,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
if (g_str_equal (signal_name, "QueryEndSession")) {
|
||||||
|
g_debug ("Received QueryEndSession");
|
||||||
|
send_quit_response (proxy);
|
||||||
|
} else if (g_str_equal (signal_name, "CancelEndSession")) {
|
||||||
|
g_debug ("Received CancelEndSession");
|
||||||
|
} else if (g_str_equal (signal_name, "EndSession")) {
|
||||||
|
g_debug ("Received EndSession");
|
||||||
|
send_quit_response (proxy);
|
||||||
|
unregister_client ();
|
||||||
|
quit ();
|
||||||
|
} else if (g_str_equal (signal_name, "Stop")) {
|
||||||
|
g_debug ("Received Stop");
|
||||||
|
unregister_client ();
|
||||||
|
quit ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
session_register(void) {
|
session_register(void) {
|
||||||
@ -151,7 +219,8 @@ session_register(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_dbus_proxy_call_sync(_proxy, "RegisterClient",
|
g_autoptr (GVariant) res = NULL;
|
||||||
|
res = g_dbus_proxy_call_sync(_proxy, "RegisterClient",
|
||||||
g_variant_new("(ss)", SESSION_NAME, autostart_id),
|
g_variant_new("(ss)", SESSION_NAME, autostart_id),
|
||||||
G_DBUS_CALL_FLAGS_NONE, 1000, NULL, &error);
|
G_DBUS_CALL_FLAGS_NONE, 1000, NULL, &error);
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -160,6 +229,22 @@ session_register(void) {
|
|||||||
g_clear_error(&error);
|
g_clear_error(&error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_variant_get (res, "(o)", &_client_path);
|
||||||
|
g_debug ("Registered client at '%s'", _client_path);
|
||||||
|
|
||||||
|
_client_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
||||||
|
0, NULL, "org.gnome.SessionManager", _client_path,
|
||||||
|
"org.gnome.SessionManager.ClientPrivate", NULL, &error);
|
||||||
|
if (error) {
|
||||||
|
g_warning ("Failed to get client proxy: %s", error->message);
|
||||||
|
g_clear_error (&error);
|
||||||
|
g_free (_client_path);
|
||||||
|
_client_path = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_signal_connect (_client_proxy, "g-signal", G_CALLBACK (client_proxy_signal), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -307,8 +392,7 @@ main (int argc, char **argv)
|
|||||||
|
|
||||||
session_register();
|
session_register();
|
||||||
|
|
||||||
GMainLoop *loop = g_main_loop_new (NULL, FALSE);
|
loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
|
||||||
g_main_loop_run (loop);
|
g_main_loop_run (loop);
|
||||||
|
|
||||||
if (connection) {
|
if (connection) {
|
||||||
|
|||||||
@ -270,6 +270,7 @@ impl Submission {
|
|||||||
.map(|(_id, m)| match m {
|
.map(|(_id, m)| match m {
|
||||||
Modifier::Control => Modifiers::CONTROL,
|
Modifier::Control => Modifiers::CONTROL,
|
||||||
Modifier::Alt => Modifiers::MOD1,
|
Modifier::Alt => Modifiers::MOD1,
|
||||||
|
Modifier::Mod4 => Modifiers::MOD4,
|
||||||
})
|
})
|
||||||
.fold(Modifiers::empty(), |m, n| m | n);
|
.fold(Modifiers::empty(), |m, n| m | n);
|
||||||
self.virtual_keyboard.set_modifiers_state(raw_modifiers);
|
self.virtual_keyboard.set_modifiers_state(raw_modifiers);
|
||||||
|
|||||||
@ -19,7 +19,6 @@ pub mod c {
|
|||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct UIManager(*const c_void);
|
pub struct UIManager(*const c_void);
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn server_context_service_update_visible(imservice: *const UIManager, active: u32);
|
pub fn server_context_service_update_visible(imservice: *const UIManager, active: u32);
|
||||||
pub fn server_context_service_release_visibility(imservice: *const UIManager);
|
pub fn server_context_service_release_visibility(imservice: *const UIManager);
|
||||||
|
|||||||
@ -37,7 +37,6 @@ pub mod c {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
// From libc, to let KeyMap get deallocated.
|
// From libc, to let KeyMap get deallocated.
|
||||||
fn close(fd: u32);
|
fn close(fd: u32);
|
||||||
|
|||||||
@ -67,9 +67,11 @@ foreach layout : [
|
|||||||
'dk',
|
'dk',
|
||||||
'epo',
|
'epo',
|
||||||
'es',
|
'es',
|
||||||
|
'es+cat',
|
||||||
'fi',
|
'fi',
|
||||||
'fr', 'fr_wide',
|
'fr', 'fr_wide',
|
||||||
'gr',
|
'gr',
|
||||||
|
'il',
|
||||||
'ir',
|
'ir',
|
||||||
'it',
|
'it',
|
||||||
'it+fur',
|
'it+fur',
|
||||||
@ -78,9 +80,10 @@ foreach layout : [
|
|||||||
'pl', 'pl_wide',
|
'pl', 'pl_wide',
|
||||||
'ru',
|
'ru',
|
||||||
'se',
|
'se',
|
||||||
'th',
|
'th', 'th_wide',
|
||||||
'ua',
|
'ua',
|
||||||
'us+colemak',
|
'us+colemak', 'us+colemak_wide',
|
||||||
|
'us+dvorak', 'us+dvorak_wide',
|
||||||
|
|
||||||
# Block: Not languages.
|
# Block: Not languages.
|
||||||
'emoji',
|
'emoji',
|
||||||
|
|||||||
Reference in New Issue
Block a user