Compare commits
	
		
			89 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 0f5c5ef10f | |||
| 6e183ccb13 | |||
| af0137a4fc | |||
| bb3c26b0d8 | |||
| 6dcea4599f | |||
| d32749d533 | |||
| 36306f2eea | |||
| 34a4c6ffb5 | |||
| 74e75d2dae | |||
| a3e421db3d | |||
| 241e5c0fc6 | |||
| 28e0c26671 | |||
| 7d0070a155 | |||
| 9093226abe | |||
| 45dc51f08f | |||
| b486dc8afd | |||
| e70a64a47e | |||
| 225b243446 | |||
| db994da531 | |||
| d47aff357b | |||
| 96c2c2dd1f | |||
| c8cc5b1997 | |||
| edb28cb859 | |||
| b07689939b | |||
| 6072e5768a | |||
| fe8d66a635 | |||
| c8658b00e3 | |||
| 0989771a3b | |||
| 9c2acde826 | |||
| 2352e31f01 | |||
| 8e654346a2 | |||
| 015ba79f65 | |||
| d6aa54f30c | |||
| fd0d8d4244 | |||
| c725cd7f14 | |||
| 0922d4a87a | |||
| 51562d5185 | |||
| ed8b6eec28 | |||
| e9c236a682 | |||
| 04a47ad0af | |||
| 99c577be60 | |||
| db8340181f | |||
| 4f18ffd34e | |||
| 4306ec9c1e | |||
| 31c12e5182 | |||
| 521796a46d | |||
| a187221d3f | |||
| 583b546e81 | |||
| aa9523338f | |||
| 0ed66e0eab | |||
| 6523275b6a | |||
| b9e9ca368a | |||
| c4886e362a | |||
| fc5f671e57 | |||
| 035ecd6df1 | |||
| 26d1a6047c | |||
| 60a89b6c3f | |||
| b84c402c4a | |||
| 2579d2fea9 | |||
| c75ed9b230 | |||
| 789e8b6bff | |||
| 633d15c438 | |||
| baabcb1400 | |||
| c16bbb9e7f | |||
| 623181cc34 | |||
| 76b5104fb7 | |||
| 6c0a642abf | |||
| 132435a9c8 | |||
| 521bcfc484 | |||
| 3413021d30 | |||
| ffc64c6d56 | |||
| 79672f3a2d | |||
| e1d5731466 | |||
| 09deef2d6c | |||
| 83907af456 | |||
| 878b7ed18e | |||
| e6f3b9e5be | |||
| 75992ff13f | |||
| 2d7dddd505 | |||
| afe0ed1674 | |||
| b9ab4288d7 | |||
| d816cc261a | |||
| 2e2ae96114 | |||
| ec7e7c3f8b | |||
| 5551ed2bd2 | |||
| 0da02aab21 | |||
| 1ae8d072a6 | |||
| e61a3a6fe8 | |||
| 087da5cd9e | 
@ -9,6 +9,10 @@ stages:
 | 
			
		||||
    - librem5
 | 
			
		||||
 | 
			
		||||
before_script:
 | 
			
		||||
  - apt-get -y update
 | 
			
		||||
  - apt-get -y install wget ca-certificates gnupg
 | 
			
		||||
  - echo "deb http://ci.puri.sm/ scratch librem5" > /etc/apt/sources.list.d/ci.list
 | 
			
		||||
  - wget -O- https://ci.puri.sm/ci-repo.key | apt-key add -
 | 
			
		||||
  - apt-get -y update
 | 
			
		||||
  - apt-get -y build-dep .
 | 
			
		||||
 | 
			
		||||
@ -22,6 +26,26 @@ build_meson:
 | 
			
		||||
    - meson . _build/ -Ddepdatadir=/usr/share
 | 
			
		||||
    - ninja -C _build install
 | 
			
		||||
 | 
			
		||||
build_deb:
 | 
			
		||||
    <<: *tags
 | 
			
		||||
    stage: build
 | 
			
		||||
    artifacts:
 | 
			
		||||
      paths:
 | 
			
		||||
        - "*.deb"
 | 
			
		||||
    script:
 | 
			
		||||
        - apt-get -y install devscripts
 | 
			
		||||
        - debuild -i -us -uc -b
 | 
			
		||||
        - cp ../*.deb .
 | 
			
		||||
 | 
			
		||||
test_lintian:
 | 
			
		||||
    <<: *tags
 | 
			
		||||
    stage: test
 | 
			
		||||
    dependencies:
 | 
			
		||||
        - build_deb
 | 
			
		||||
    script:
 | 
			
		||||
        - apt-get -y install lintian
 | 
			
		||||
        - lintian *.deb
 | 
			
		||||
 | 
			
		||||
test:
 | 
			
		||||
  <<: *tags
 | 
			
		||||
  stage: test
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										162
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							@ -0,0 +1,162 @@
 | 
			
		||||
# This file is automatically @generated by Cargo.
 | 
			
		||||
# It is not intended for manual editing.
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bitflags"
 | 
			
		||||
version = "1.2.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "dtoa"
 | 
			
		||||
version = "0.4.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "libc"
 | 
			
		||||
version = "0.2.62"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "linked-hash-map"
 | 
			
		||||
version = "0.5.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "maplit"
 | 
			
		||||
version = "1.0.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "memmap"
 | 
			
		||||
version = "0.7.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "proc-macro2"
 | 
			
		||||
version = "1.0.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "quote"
 | 
			
		||||
version = "1.0.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "rs"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "xkbcommon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde"
 | 
			
		||||
version = "1.0.101"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_derive"
 | 
			
		||||
version = "1.0.101"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_yaml"
 | 
			
		||||
version = "0.8.9"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "syn"
 | 
			
		||||
version = "1.0.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "unicode-xid"
 | 
			
		||||
version = "0.2.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "winapi"
 | 
			
		||||
version = "0.3.8"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "winapi-i686-pc-windows-gnu"
 | 
			
		||||
version = "0.4.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "winapi-x86_64-pc-windows-gnu"
 | 
			
		||||
version = "0.4.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "xkbcommon"
 | 
			
		||||
version = "0.4.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "yaml-rust"
 | 
			
		||||
version = "0.4.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[metadata]
 | 
			
		||||
"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2"
 | 
			
		||||
"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e"
 | 
			
		||||
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
 | 
			
		||||
"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
 | 
			
		||||
"checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
 | 
			
		||||
"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
 | 
			
		||||
"checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc"
 | 
			
		||||
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
 | 
			
		||||
"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
 | 
			
		||||
"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
 | 
			
		||||
"checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582"
 | 
			
		||||
"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
 | 
			
		||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
 | 
			
		||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
 | 
			
		||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 | 
			
		||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 | 
			
		||||
"checksum xkbcommon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fda0ea5f7ddabd51deeeda7799bee06274112f577da7dd3d954b8eda731b2fce"
 | 
			
		||||
"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d"
 | 
			
		||||
							
								
								
									
										15
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
[package]
 | 
			
		||||
name = "rs"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
bitflags = "1.0"
 | 
			
		||||
maplit = "1.0"
 | 
			
		||||
serde = { version = "1.0", features = ["derive"] }
 | 
			
		||||
serde_yaml = "0.8"
 | 
			
		||||
xkbcommon = { version = "0.4", features = ["wayland"] }
 | 
			
		||||
 | 
			
		||||
[lib]
 | 
			
		||||
name = "rs"
 | 
			
		||||
path = "src/lib.rs"
 | 
			
		||||
crate-type = ["staticlib", "rlib"]
 | 
			
		||||
							
								
								
									
										58
									
								
								HACKING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								HACKING.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
			
		||||
Hacking
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
This document describes the standards for modifying and maintaining the *squeekboard* project.
 | 
			
		||||
 | 
			
		||||
Testing
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
Most common testing is done in CI. Occasionally, and for each release, do perform manual tests to make sure that
 | 
			
		||||
 | 
			
		||||
- the application draws correctly
 | 
			
		||||
- it shows when relevant
 | 
			
		||||
- it changes layouts
 | 
			
		||||
- it changes levels
 | 
			
		||||
 | 
			
		||||
Testing with an application:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
python3 tests/entry.py
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Testing visibility:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
$ busctl call --user sm.puri.OSK0 /sm/puri/OSK0 sm.puri.OSK0 SetVisible b true
 | 
			
		||||
$ busctl call --user sm.puri.OSK0 /sm/puri/OSK0 sm.puri.OSK0 SetVisible b false
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Testing layouts:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
$ gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'us'), ('xkb', 'ua')]"
 | 
			
		||||
$ gsettings set org.gnome.desktop.input-sources current 1
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Maintenance
 | 
			
		||||
-----------
 | 
			
		||||
 | 
			
		||||
Squeekboard uses Rust & Cargo for some of its dependencies.
 | 
			
		||||
 | 
			
		||||
Use the `cargo.sh` script for maintaining the Cargo part of the build. The script takes the usual Cargo commands, after the first 2 positionsl arguments: source directory, and output artifact. So, `cargo test` becomes:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
cd build_dir
 | 
			
		||||
sh /source_path/cargo.sh /source_path '' test
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Cargo dependencies
 | 
			
		||||
 | 
			
		||||
Dependencies must be specified in `Cargo.toml` with 2 numbers: "major.minor". Since bugfix version number is meant to not affect the interface, this allows for safe updates.
 | 
			
		||||
 | 
			
		||||
`Cargo.lock` is used for remembering the revisions of all Rust dependencies. It should be updated often, preferably with each bugfix revision, and in a commit on its own:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
cd build_dir
 | 
			
		||||
sh /source_path/cargo.sh /source_path '' update
 | 
			
		||||
ninja test
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										29
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								README.md
									
									
									
									
									
								
							@ -3,14 +3,18 @@
 | 
			
		||||
 | 
			
		||||
*Squeekboard* is a virtual keyboard supporting Wayland, built primarily for the *Librem 5* phone.
 | 
			
		||||
 | 
			
		||||
It squeaks because some Rust got inside.
 | 
			
		||||
 | 
			
		||||
Features
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
### Present
 | 
			
		||||
 | 
			
		||||
- GTK3
 | 
			
		||||
- Custom xml-defined keyboards
 | 
			
		||||
- Custom yaml-defined keyboards
 | 
			
		||||
- DBus interface to show and hide
 | 
			
		||||
- Use Wayland input method protocol to show and hide
 | 
			
		||||
- Use Wayland virtual keyboard protocol
 | 
			
		||||
 | 
			
		||||
### Temporarily dropped
 | 
			
		||||
 | 
			
		||||
@ -18,8 +22,6 @@ Features
 | 
			
		||||
 | 
			
		||||
### TODO
 | 
			
		||||
 | 
			
		||||
- Use Wayland virtual keyboard protocol
 | 
			
		||||
- Use Wayland text input protocol
 | 
			
		||||
- Use Wayland input method protocol
 | 
			
		||||
- Pick up DBus interface files from /usr/share
 | 
			
		||||
 | 
			
		||||
@ -38,31 +40,20 @@ $ cd squeekboard
 | 
			
		||||
$ mkdir ../build
 | 
			
		||||
$ meson ../build/
 | 
			
		||||
$ cd ../build
 | 
			
		||||
$ ninja test
 | 
			
		||||
$ ninja install
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For development, alter the `meson` call:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
$ meson ../build/ --prefix=../install
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
and don't skip `ninja install` before running. The last step is necessary in order to find the keyboard definition files.
 | 
			
		||||
 | 
			
		||||
Running
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
$ rootston
 | 
			
		||||
$ phoc # if no compatible Wayland compositor is running yet
 | 
			
		||||
$ cd ../build/
 | 
			
		||||
$ src/squeekboard
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Testing
 | 
			
		||||
Developing
 | 
			
		||||
----------
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
$ busctl call --user sm.puri.OSK0 /sm/puri/OSK0 sm.puri.OSK0 SetVisible b true
 | 
			
		||||
$ busctl call --user sm.puri.OSK0 /sm/puri/OSK0 sm.puri.OSK0 SetVisible b false
 | 
			
		||||
$ gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'us'), ('xkb', 'ua')]"
 | 
			
		||||
$ gsettings set org.gnome.desktop.input-sources current 1
 | 
			
		||||
```
 | 
			
		||||
See `HACKING.md`
 | 
			
		||||
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
Eek cheader_filename="eek/eek.h"
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
EekGtk cheader_filename="eek/eek-gtk.h"
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
EekXkl cheader_filename="eek/eek-xkl.h"
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
gio-2.0
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
eek-0.90
 | 
			
		||||
@ -1,2 +0,0 @@
 | 
			
		||||
eek-0.90
 | 
			
		||||
x11
 | 
			
		||||
							
								
								
									
										23
									
								
								cargo.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								cargo.sh
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# This script manages Cargo operations
 | 
			
		||||
# while keeping the artifact directory within the build tree
 | 
			
		||||
# instead of the source tree
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
SOURCE_DIR="$1"
 | 
			
		||||
 | 
			
		||||
export CARGO_TARGET_DIR=`pwd`
 | 
			
		||||
if [ ! -z ${2} ]; then
 | 
			
		||||
    OUT_PATH=`realpath "${2}"`
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
cd $SOURCE_DIR
 | 
			
		||||
shift
 | 
			
		||||
shift
 | 
			
		||||
cargo $BUILD_ARG $@
 | 
			
		||||
 | 
			
		||||
if [ ! -z ${OUT_PATH} ]; then
 | 
			
		||||
    cp "${CARGO_TARGET_DIR}"/debug/librs.a "${OUT_PATH}"
 | 
			
		||||
fi
 | 
			
		||||
@ -1,64 +0,0 @@
 | 
			
		||||
<?xml version="1.0"?>
 | 
			
		||||
<geometry version="0.90">
 | 
			
		||||
  <bounds x="10" y="10" width="410.0000" height="229"/>
 | 
			
		||||
 | 
			
		||||
  <outline id="default" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="37.46341" y="0.000000"/>
 | 
			
		||||
    <point x="37.46341" y="52"/>
 | 
			
		||||
    <point x="0.000000" y="52"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="altline" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="48.39024" y="0.000000"/>
 | 
			
		||||
    <point x="48.39024" y="52"/>
 | 
			
		||||
    <point x="0.000000" y="52"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="outline7" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="88.97561" y="0.000000"/>
 | 
			
		||||
    <point x="88.97561" y="52"/>
 | 
			
		||||
    <point x="0.000000" y="52"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="spaceline" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="150.5853" y="0.000000"/>
 | 
			
		||||
    <point x="150.5853" y="52"/>
 | 
			
		||||
    <point x="0.000000" y="52"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
 | 
			
		||||
  <button name="Shift_L" oref="altline" />
 | 
			
		||||
  <button name="BackSpace" oref="altline" />
 | 
			
		||||
  <button name="preferences" oref="altline" />
 | 
			
		||||
  <button name="show_numbers" oref="altline" keycode="0" />
 | 
			
		||||
  <button name="show_letters" oref="altline" keycode="0" />
 | 
			
		||||
  <button name="show_symbols" oref="altline" keycode="0" />
 | 
			
		||||
  <button name="period" oref="altline" />
 | 
			
		||||
  <button name="space" oref="spaceline" />
 | 
			
		||||
  <button name="Return" oref="outline7" />
 | 
			
		||||
 | 
			
		||||
  <view>
 | 
			
		||||
    <section angle="0">q w e r t y u i o p</section>
 | 
			
		||||
    <section angle="0">a s d f g h j k l</section>
 | 
			
		||||
    <section angle="0"> Shift_L   z x c v b n m  BackSpace </section>
 | 
			
		||||
    <section angle="0"> show_numbers preferences         space        period    Return    </section>
 | 
			
		||||
  </view>
 | 
			
		||||
  <view>
 | 
			
		||||
    <section angle="0">Q W E R T Y U I O P</section>
 | 
			
		||||
    <section angle="0">A S D F G H J K L</section>
 | 
			
		||||
    <section angle="0"> Shift_L   Z X C V B N M  BackSpace </section>
 | 
			
		||||
    <section angle="0"> show_numbers preferences         space        period    Return    </section>
 | 
			
		||||
  </view>
 | 
			
		||||
  <view>
 | 
			
		||||
    <section angle="0">1 2 3 4 5 6 7 8 9 0</section>
 | 
			
		||||
    <section angle="0">at numbersign dollar percent ampersand minus underscore plus parenleft parenright</section>
 | 
			
		||||
    <section angle="0"> show_symbols   comma quotedbl quoteright colon semicolon exclam question  BackSpace </section>
 | 
			
		||||
    <section angle="0"> show_letters preferences         space        period    Return    </section>
 | 
			
		||||
  </view>
 | 
			
		||||
  <view>
 | 
			
		||||
    <section angle="0">asciitilde quoteleft bar U00B7 squareroot Greek_pi Greek_tau division multiply paragraph</section>
 | 
			
		||||
    <section angle="0">copyright U00AE U00A3 EuroSign U00A5 asciicircum degree asterisk braceleft braceright</section>
 | 
			
		||||
    <section angle="0"> show_numbers   backslash slash less greater equal bracketleft bracketright  BackSpace </section>
 | 
			
		||||
    <section angle="0"> show_letters preferences         space        period    Return    </section>
 | 
			
		||||
  </view>
 | 
			
		||||
</geometry>
 | 
			
		||||
@ -1,105 +0,0 @@
 | 
			
		||||
<?xml version="1.0"?>
 | 
			
		||||
<geometry version="0.90">
 | 
			
		||||
  <bounds x="0" y="10.000000" width="426.0000" height="296.5853"/>
 | 
			
		||||
 | 
			
		||||
  <outline id="outline2" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="32" y="0.000000"/>
 | 
			
		||||
    <point x="32" y="52"/>
 | 
			
		||||
    <point x="0.000000" y="52"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="altline" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="48.39024" y="0.000000"/>
 | 
			
		||||
    <point x="48.39024" y="52"/>
 | 
			
		||||
    <point x="0.000000" y="52"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="outline4" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="59.31707" y="0.000000"/>
 | 
			
		||||
    <point x="59.31707" y="52"/>
 | 
			
		||||
    <point x="0.000000" y="52"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="outline5" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="59.31707" y="0.000000"/>
 | 
			
		||||
    <point x="59.31707" y="52"/>
 | 
			
		||||
    <point x="0.000000" y="52"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="outline6" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="68.68292" y="0.000000"/>
 | 
			
		||||
    <point x="68.68292" y="52"/>
 | 
			
		||||
    <point x="0.000000" y="52"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="outline7" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="88.97561" y="0.000000"/>
 | 
			
		||||
    <point x="88.97561" y="52"/>
 | 
			
		||||
    <point x="0.000000" y="52"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="outline8" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="88.97561" y="0.000000"/>
 | 
			
		||||
    <point x="88.97561" y="52"/>
 | 
			
		||||
    <point x="0.000000" y="52"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="outline9" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="109.2682" y="0.000000"/>
 | 
			
		||||
    <point x="109.2682" y="52"/>
 | 
			
		||||
    <point x="0.000000" y="52"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="outline10" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="37.46341" y="0.000000"/>
 | 
			
		||||
    <point x="37.46341" y="52"/>
 | 
			
		||||
    <point x="0.000000" y="52"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="outline13" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="79.60975" y="0.000000"/>
 | 
			
		||||
    <point x="79.60975" y="52"/>
 | 
			
		||||
    <point x="0.000000" y="52"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="spaceline" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="150.5853" y="0.000000"/>
 | 
			
		||||
    <point x="150.5853" y="52"/>
 | 
			
		||||
    <point x="0.000000" y="52"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
 | 
			
		||||
  <button name="Shift_L" oref="altline" />
 | 
			
		||||
  <button name="BackSpace" oref="altline" />
 | 
			
		||||
  <button name="preferences" oref="altline" />
 | 
			
		||||
  <button name="show_numbers" oref="altline" keycode="0" />
 | 
			
		||||
  <button name="show_letters" oref="altline" keycode="0" />
 | 
			
		||||
  <button name="show_symbols" oref="altline" keycode="0" />
 | 
			
		||||
  <button name="space" oref="spaceline" />
 | 
			
		||||
  <button name="return" oref="outline7" />
 | 
			
		||||
 | 
			
		||||
  <view>
 | 
			
		||||
    <section angle="0">q w e r t y u i o p aring</section>
 | 
			
		||||
    <section angle="0">a s d f g h j k l oslash ae</section>
 | 
			
		||||
    <section angle="0"> Shift_L   z x c v b n m  BackSpace </section>
 | 
			
		||||
    <section angle="0"> show_numbers preferences         space        period    Return    </section>
 | 
			
		||||
  </view>
 | 
			
		||||
  <view>
 | 
			
		||||
    <section angle="0">Q W E R T Y U I O P Aring</section>
 | 
			
		||||
    <section angle="0">A S D F G H J K L Oslash AE</section>
 | 
			
		||||
    <section angle="0"> Shift_L   Z X C V B N M  BackSpace </section>
 | 
			
		||||
    <section angle="0"> show_numbers preferences         space        period    Return    </section>
 | 
			
		||||
  </view>
 | 
			
		||||
  <view>
 | 
			
		||||
    <section angle="0">1 2 3 4 5 6 7 8 9 0</section>
 | 
			
		||||
    <section angle="0">at numbersign dollar percent ampersand minus underscore plus parenleft parenright</section>
 | 
			
		||||
    <section angle="0"> show_symbols   comma quotedbl quoteright colon semicolon exclam question  BackSpace </section>
 | 
			
		||||
    <section angle="0"> show_letters preferences         space        period    Return    </section>
 | 
			
		||||
  </view>
 | 
			
		||||
  <view>
 | 
			
		||||
    <section angle="0">asciitilde quoteleft bar U00B7 squareroot Greek_pi Greek_tau division multiply paragraph</section>
 | 
			
		||||
    <section angle="0">copyright U00AE U00A3 EuroSign U00A5 asciicircum degree asterisk braceleft braceright</section>
 | 
			
		||||
    <section angle="0"> show_numbers   backslash slash less greater equal bracketleft bracketright  BackSpace </section>
 | 
			
		||||
    <section angle="0"> show_letters preferences         space        period    Return    </section>
 | 
			
		||||
  </view>
 | 
			
		||||
</geometry>
 | 
			
		||||
@ -1,40 +0,0 @@
 | 
			
		||||
<?xml version="1.0"?>
 | 
			
		||||
<geometry version="0.90">
 | 
			
		||||
  <bounds x="0" y="10.000000" width="426.0000" height="296.5853"/>
 | 
			
		||||
 | 
			
		||||
  <outline id="default" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="37.46341" y="0.000000"/>
 | 
			
		||||
    <point x="37.46341" y="52.44877"/>
 | 
			
		||||
    <point x="0.000000" y="52.44877"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="altline" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="48.39024" y="0.000000"/>
 | 
			
		||||
    <point x="48.39024" y="52.44877"/>
 | 
			
		||||
    <point x="0.000000" y="52.44877"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="outline7" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="88.97561" y="0.000000"/>
 | 
			
		||||
    <point x="88.97561" y="52.44877"/>
 | 
			
		||||
    <point x="0.000000" y="52.44877"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
  <outline id="spaceline" corner-radius="1.000000">
 | 
			
		||||
    <point x="0.000000" y="0.000000"/>
 | 
			
		||||
    <point x="120.5853" y="0.000000"/>
 | 
			
		||||
    <point x="120.5853" y="52.44877"/>
 | 
			
		||||
    <point x="0.000000" y="52.44877"/>
 | 
			
		||||
  </outline>
 | 
			
		||||
 | 
			
		||||
  <button name="BackSpace" oref="altline" />
 | 
			
		||||
  <button name="space" oref="spaceline" />
 | 
			
		||||
  <button name="Return" oref="outline7" />
 | 
			
		||||
 | 
			
		||||
  <view>
 | 
			
		||||
    <section angle="0">1 2 3 parenleft parenright</section>
 | 
			
		||||
    <section angle="0">4 5 6 numbersign asterisk</section>
 | 
			
		||||
    <section angle="0">7 8 9 plus minus</section>
 | 
			
		||||
    <section angle="0">BackSpace 0 space Return</section>
 | 
			
		||||
  </view>
 | 
			
		||||
</geometry>
 | 
			
		||||
@ -1,100 +0,0 @@
 | 
			
		||||
<?xml version="1.0"?>
 | 
			
		||||
<keyboards version="0.90">
 | 
			
		||||
  <keyboard id="ar" name="ar"
 | 
			
		||||
	    geometry="compact" symbols="ar"
 | 
			
		||||
	    longname="Arabic" language="ar"/>
 | 
			
		||||
  <keyboard id="be" name="be"
 | 
			
		||||
	    geometry="compact" symbols="be"
 | 
			
		||||
	    longname="Belarusian" language="be"/>
 | 
			
		||||
  <keyboard id="fa" name="fa"
 | 
			
		||||
	    geometry="compact" symbols="fa"
 | 
			
		||||
	    longname="Farsi (ISIRI 2901-1994)" language="fa"/>
 | 
			
		||||
  <keyboard id="he" name="he"
 | 
			
		||||
	    geometry="compact" symbols="he"
 | 
			
		||||
	    longname="Hebrew" language="he"/>
 | 
			
		||||
  <keyboard id="ja" name="ja"
 | 
			
		||||
	    geometry="compact" symbols="ja-kana"
 | 
			
		||||
	    longname="Japanese (Kana)" language="ja"/>
 | 
			
		||||
  <keyboard id="kk" name="kk"
 | 
			
		||||
	    geometry="compact" symbols="kk"
 | 
			
		||||
	    longname="Kazakh" language="kk"/>
 | 
			
		||||
  <keyboard id="ks" name="ks"
 | 
			
		||||
	    geometry="compact" symbols="ks"
 | 
			
		||||
	    longname="Kashmiri" language="ks"/>
 | 
			
		||||
  <keyboard id="my" name="my"
 | 
			
		||||
	    geometry="compact" symbols="my"
 | 
			
		||||
	    longname="Myanmar" language="my"/>
 | 
			
		||||
  <keyboard id="nb" name="nb"
 | 
			
		||||
	    geometry="extended" symbols="nb"
 | 
			
		||||
	    longname="Norwegian" language="nb"/>
 | 
			
		||||
  <keyboard id="ru" name="ru"
 | 
			
		||||
	    geometry="compact" symbols="us"
 | 
			
		||||
	    longname="Russian" language="ru"/>
 | 
			
		||||
  <keyboard id="th" name="th"
 | 
			
		||||
	    geometry="compact" symbols="th"
 | 
			
		||||
	    longname="Thai" language="th"/>
 | 
			
		||||
  <keyboard id="ua" name="ua"
 | 
			
		||||
	    geometry="compact" symbols="ua"
 | 
			
		||||
	    longname="Ukrainian" language="ua"/>
 | 
			
		||||
  <keyboard id="ug" name="ug"
 | 
			
		||||
	    geometry="compact" symbols="ug"
 | 
			
		||||
	    longname="Uyghur" language="ug"/>
 | 
			
		||||
  <keyboard id="us" name="us"
 | 
			
		||||
	    geometry="compact" symbols="us"
 | 
			
		||||
	    longname="US" language="en"/>
 | 
			
		||||
  <keyboard id="zh-bopomofo" name="zh-bopomofo"
 | 
			
		||||
	    geometry="compact" symbols="zh-bopomofo"
 | 
			
		||||
	    longname="Chinese (Bopomofo)" language="zh"/>
 | 
			
		||||
  <!-- Indic Inscript keyboards converted from m17n-lib -->
 | 
			
		||||
  <keyboard id="as-inscript" name="as-inscript"
 | 
			
		||||
	    geometry="compact" symbols="as-inscript"
 | 
			
		||||
	    longname="Assamese (Inscript)" language="as"/>
 | 
			
		||||
  <keyboard id="bn-inscript" name="bn-inscript"
 | 
			
		||||
	    geometry="compact" symbols="bn-inscript"
 | 
			
		||||
	    longname="Bengali (Inscript)" language="bn"/>
 | 
			
		||||
  <keyboard id="gu-inscript" name="gu-inscript"
 | 
			
		||||
	    geometry="compact" symbols="gu-inscript"
 | 
			
		||||
	    longname="Gujarati (Inscript)" language="gu"/>
 | 
			
		||||
  <keyboard id="hi-inscript" name="hi-inscript"
 | 
			
		||||
	    geometry="compact" symbols="hi-inscript"
 | 
			
		||||
	    longname="Hindi (Inscript)" language="hi"/>
 | 
			
		||||
  <keyboard id="kn-inscript" name="kn-inscript"
 | 
			
		||||
	    geometry="compact" symbols="kn-inscript"
 | 
			
		||||
	    longname="Kannada (Inscript)" language="kn"/>
 | 
			
		||||
  <keyboard id="ks-inscript" name="ks-inscript"
 | 
			
		||||
	    geometry="compact" symbols="ks-inscript"
 | 
			
		||||
	    longname="Kashmiri Devanagari (Inscript)" language="ks"/>
 | 
			
		||||
  <keyboard id="mai-inscript" name="mai-inscript"
 | 
			
		||||
	    geometry="compact" symbols="mai-inscript"
 | 
			
		||||
	    longname="Maithili (Inscript)" language="mai"/>
 | 
			
		||||
  <keyboard id="ml-inscript" name="ml-inscript"
 | 
			
		||||
	    geometry="compact" symbols="ml-inscript"
 | 
			
		||||
	    longname="Malayalam (Inscript)" language="ml-inscript"/>
 | 
			
		||||
  <keyboard id="mr-inscript" name="mr-inscript"
 | 
			
		||||
	    geometry="compact" symbols="mr-inscript"
 | 
			
		||||
	    longname="Marathi (Inscript)" language="mr"/>
 | 
			
		||||
  <keyboard id="or-inscript" name="or-inscript"
 | 
			
		||||
	    geometry="compact" symbols="or-inscript"
 | 
			
		||||
	    longname="Oriya (Inscript)" language="or"/>
 | 
			
		||||
  <keyboard id="pa-inscript" name="pa-inscript"
 | 
			
		||||
	    geometry="compact" symbols="pa-inscript"
 | 
			
		||||
	    longname="Punjabi (Inscript)" language="pa"/>
 | 
			
		||||
  <keyboard id="sd-inscript" name="sd-inscript"
 | 
			
		||||
	    geometry="compact" symbols="sd-inscript"
 | 
			
		||||
	    longname="Sindhi (Inscript)" language="sd"/>
 | 
			
		||||
  <keyboard id="ta-inscript" name="ta-inscript"
 | 
			
		||||
	    geometry="compact" symbols="ta-inscript"
 | 
			
		||||
	    longname="Tamil (Inscript)" language="ta"/>
 | 
			
		||||
  <keyboard id="te-inscript" name="te-inscript"
 | 
			
		||||
	    geometry="compact" symbols="te-inscript"
 | 
			
		||||
	    longname="Telugu (Inscript)" language="te"/>
 | 
			
		||||
 | 
			
		||||
  <!-- Common keyboards -->
 | 
			
		||||
  <keyboard id="number" name="number"
 | 
			
		||||
	    geometry="number-keypad" symbols="special/number"
 | 
			
		||||
	    longname="Numeric keypad" language="all"/>
 | 
			
		||||
  <keyboard id="phone" name="phone"
 | 
			
		||||
	    geometry="number-keypad" symbols="special/number"
 | 
			
		||||
	    longname="Phone keypad" language="all"/>
 | 
			
		||||
 | 
			
		||||
</keyboards>
 | 
			
		||||
							
								
								
									
										179
									
								
								data/keyboards/nb.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								data/keyboards/nb.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,179 @@
 | 
			
		||||
---
 | 
			
		||||
bounds: { x: 0, y: 10, width: 426, height: 229 }
 | 
			
		||||
 | 
			
		||||
outlines:
 | 
			
		||||
    default:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 32, height: 52 }
 | 
			
		||||
    altline:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 48.39024, height: 52 }
 | 
			
		||||
    outline7:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 88.97561, height: 52 }
 | 
			
		||||
    spaceline:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 150.5853, height: 52 }
 | 
			
		||||
 | 
			
		||||
views:
 | 
			
		||||
    base:
 | 
			
		||||
        - "q w e r t y u i o p aring"
 | 
			
		||||
        - "a s d f g h j k l oslash ae"
 | 
			
		||||
        - "Shift_L   z x c v b n m  BackSpace"
 | 
			
		||||
        - "show_numbers preferences         space        period    Return"
 | 
			
		||||
    upper:
 | 
			
		||||
        - "Q W E R T Y U I O P Aring"
 | 
			
		||||
        - "A S D F G H J K L Oslash AE"
 | 
			
		||||
        - "Shift_L   Z X C V B N M  BackSpace"
 | 
			
		||||
        - "show_numbers preferences         space        period    Return"
 | 
			
		||||
    numbers:
 | 
			
		||||
        - "1 2 3 4 5 6 7 8 9 0"
 | 
			
		||||
        - "at numbersign dollar percent ampersand minus underscore plus parenleft parenright"
 | 
			
		||||
        - "show_symbols   comma quotedbl quoteright colon semicolon exclam question  BackSpace"
 | 
			
		||||
        - "show_letters preferences         space        period    Return"
 | 
			
		||||
    symbols:
 | 
			
		||||
        - "asciitilde quoteleft bar U00B7 squareroot Greek_pi Greek_tau division multiply paragraph"
 | 
			
		||||
        - "copyright U00AE U00A3 EuroSign U00A5 asciicircum degree asterisk braceleft braceright"
 | 
			
		||||
        - "show_numbers   backslash slash less greater equal bracketleft bracketright  BackSpace"
 | 
			
		||||
        - "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"
 | 
			
		||||
    preferences:
 | 
			
		||||
        action: "show_prefs"
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        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: "*/="
 | 
			
		||||
    period:
 | 
			
		||||
        outline: altline
 | 
			
		||||
        label: "."
 | 
			
		||||
    space:
 | 
			
		||||
        outline: spaceline
 | 
			
		||||
        label: " "
 | 
			
		||||
    Return:
 | 
			
		||||
        outline: outline7
 | 
			
		||||
        icon: "key-enter"
 | 
			
		||||
    aring:
 | 
			
		||||
        label: "å"
 | 
			
		||||
    Aring:
 | 
			
		||||
        label: "Å"
 | 
			
		||||
    oslash:
 | 
			
		||||
        label: "ø"
 | 
			
		||||
    Oslash:
 | 
			
		||||
        label: "Ø"
 | 
			
		||||
    ae:
 | 
			
		||||
        label: "æ"
 | 
			
		||||
    AE:
 | 
			
		||||
        label: "Æ"
 | 
			
		||||
    asterisk:
 | 
			
		||||
        label: "*"
 | 
			
		||||
    asciitilde:
 | 
			
		||||
        label: "~"
 | 
			
		||||
    quoteleft:
 | 
			
		||||
        label: "`"
 | 
			
		||||
    bar:
 | 
			
		||||
        label: "|"
 | 
			
		||||
    U00B7:
 | 
			
		||||
        label: "·"
 | 
			
		||||
    squareroot:
 | 
			
		||||
        label: "√"
 | 
			
		||||
    Greek_pi:
 | 
			
		||||
        label: "π"
 | 
			
		||||
    division:
 | 
			
		||||
        label: "÷"
 | 
			
		||||
    multiply:
 | 
			
		||||
        label: "×"
 | 
			
		||||
    paragraph:
 | 
			
		||||
        label: "¶"
 | 
			
		||||
    Greek_tau:
 | 
			
		||||
        label: "τ"
 | 
			
		||||
    copyright:
 | 
			
		||||
        label: "©"
 | 
			
		||||
    numbersign:
 | 
			
		||||
        label: "#"
 | 
			
		||||
    U00AE:
 | 
			
		||||
        label: "®"
 | 
			
		||||
    at:
 | 
			
		||||
        label: "@"
 | 
			
		||||
    dollar:
 | 
			
		||||
        label: "$"
 | 
			
		||||
    U00A3:
 | 
			
		||||
        label: "£"
 | 
			
		||||
    percent:
 | 
			
		||||
        label: "%"
 | 
			
		||||
    EuroSign:
 | 
			
		||||
        label: "€"
 | 
			
		||||
    ampersand:
 | 
			
		||||
        label: "&"
 | 
			
		||||
    U00A5:
 | 
			
		||||
        label: "¥"
 | 
			
		||||
    minus:
 | 
			
		||||
        label: "-"
 | 
			
		||||
    asciicircum:
 | 
			
		||||
        label: "^"
 | 
			
		||||
    underscore:
 | 
			
		||||
        label: "_"
 | 
			
		||||
    degree:
 | 
			
		||||
        label: "°"
 | 
			
		||||
    plus:
 | 
			
		||||
        label: "+"
 | 
			
		||||
    equal:
 | 
			
		||||
        label: "="
 | 
			
		||||
    parenleft:
 | 
			
		||||
        label: "("
 | 
			
		||||
    parenright:
 | 
			
		||||
        label: ")"
 | 
			
		||||
    braceleft:
 | 
			
		||||
        label: "{"
 | 
			
		||||
    braceright:
 | 
			
		||||
        label: "}"
 | 
			
		||||
    comma:
 | 
			
		||||
        label: ","
 | 
			
		||||
    backslash:
 | 
			
		||||
        label: "\\"
 | 
			
		||||
    slash:
 | 
			
		||||
        label: "/"
 | 
			
		||||
    quotedbl:
 | 
			
		||||
        label: "\""
 | 
			
		||||
    quoteright:
 | 
			
		||||
        label: "'"
 | 
			
		||||
    less:
 | 
			
		||||
        label: "<"
 | 
			
		||||
    greater:
 | 
			
		||||
        label: ">"
 | 
			
		||||
    colon:
 | 
			
		||||
        label: ":"
 | 
			
		||||
    semicolon:
 | 
			
		||||
        label: ";"
 | 
			
		||||
    exclam:
 | 
			
		||||
        label: "!"
 | 
			
		||||
    question:
 | 
			
		||||
        label: "?"
 | 
			
		||||
    bracketleft:
 | 
			
		||||
        label: "["
 | 
			
		||||
    bracketright:
 | 
			
		||||
        label: "]"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										47
									
								
								data/keyboards/number.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								data/keyboards/number.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
			
		||||
---
 | 
			
		||||
bounds: { x: 0, y: 10, width: 410, height: 229 }
 | 
			
		||||
 | 
			
		||||
outlines:
 | 
			
		||||
    default:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 37.46341, height: 52 }
 | 
			
		||||
    altline:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 48.39024, height: 52 }
 | 
			
		||||
    outline7:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 88.97561, height: 52 }
 | 
			
		||||
    spaceline:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 120.5853, height: 52 }
 | 
			
		||||
 | 
			
		||||
views:
 | 
			
		||||
    base:
 | 
			
		||||
        - "1 2 3 parenleft parenright"
 | 
			
		||||
        - "4 5 6 numbersign asterisk"
 | 
			
		||||
        - "7 8 9 plus minus"
 | 
			
		||||
        - "BackSpace 0 space Return"
 | 
			
		||||
 | 
			
		||||
buttons:
 | 
			
		||||
    BackSpace:
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        icon: "edit-clear-symbolic"
 | 
			
		||||
    space:
 | 
			
		||||
        outline: spaceline
 | 
			
		||||
        label: " "
 | 
			
		||||
    Return:
 | 
			
		||||
        outline: outline7
 | 
			
		||||
        icon: "key-enter"
 | 
			
		||||
    asterisk:
 | 
			
		||||
        label: "*"
 | 
			
		||||
    numbersign:
 | 
			
		||||
        label: "#"
 | 
			
		||||
    minus:
 | 
			
		||||
        label: "-"
 | 
			
		||||
    plus:
 | 
			
		||||
        label: "+"
 | 
			
		||||
    parenleft:
 | 
			
		||||
        label: "("
 | 
			
		||||
    parenright:
 | 
			
		||||
        label: ")"
 | 
			
		||||
 | 
			
		||||
@ -1,132 +0,0 @@
 | 
			
		||||
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
 | 
			
		||||
<symbols version="0.90">
 | 
			
		||||
  <symbol label="*">asterisk</symbol>
 | 
			
		||||
  <symbol label="+/=">show_symbols</symbol>
 | 
			
		||||
  <symbol label="τ">Greek_tau</symbol>
 | 
			
		||||
  <symbol label="å">aring</symbol>
 | 
			
		||||
  <symbol label="ø">oslash</symbol>
 | 
			
		||||
  <symbol label="æ">ae</symbol>
 | 
			
		||||
  <symbol label="Å">Aring</symbol>
 | 
			
		||||
  <symbol label="Ø">Oslash</symbol>
 | 
			
		||||
  <symbol label="Æ">AE</symbol>
 | 
			
		||||
  <symbol label="q">q</symbol>
 | 
			
		||||
  <symbol label="Q">Q</symbol>
 | 
			
		||||
  <symbol label="1">1</symbol>
 | 
			
		||||
  <symbol label="~">asciitilde</symbol>
 | 
			
		||||
  <symbol label="w">w</symbol>
 | 
			
		||||
  <symbol label="W">W</symbol>
 | 
			
		||||
  <symbol label="2">2</symbol>
 | 
			
		||||
  <symbol label="`">quoteleft</symbol>
 | 
			
		||||
  <symbol label="e">e</symbol>
 | 
			
		||||
  <symbol label="E">E</symbol>
 | 
			
		||||
  <symbol label="3">3</symbol>
 | 
			
		||||
  <symbol label="|">bar</symbol>
 | 
			
		||||
  <symbol label="r">r</symbol>
 | 
			
		||||
  <symbol label="R">R</symbol>
 | 
			
		||||
  <symbol label="4">4</symbol>
 | 
			
		||||
  <symbol label="·">U00B7</symbol>
 | 
			
		||||
  <symbol label="t">t</symbol>
 | 
			
		||||
  <symbol label="T">T</symbol>
 | 
			
		||||
  <symbol label="5">5</symbol>
 | 
			
		||||
  <symbol label="√">squareroot</symbol>
 | 
			
		||||
  <symbol label="y">y</symbol>
 | 
			
		||||
  <symbol label="Y">Y</symbol>
 | 
			
		||||
  <symbol label="6">6</symbol>
 | 
			
		||||
  <symbol label="π">Greek_pi</symbol>
 | 
			
		||||
  <symbol label="u">u</symbol>
 | 
			
		||||
  <symbol label="U">U</symbol>
 | 
			
		||||
  <symbol label="7">7</symbol>
 | 
			
		||||
  <symbol label="÷">division</symbol>
 | 
			
		||||
  <symbol label="i">i</symbol>
 | 
			
		||||
  <symbol label="I">I</symbol>
 | 
			
		||||
  <symbol label="8">8</symbol>
 | 
			
		||||
  <symbol label="×">multiply</symbol>
 | 
			
		||||
  <symbol label="o">o</symbol>
 | 
			
		||||
  <symbol label="O">O</symbol>
 | 
			
		||||
  <symbol label="9">9</symbol>
 | 
			
		||||
  <symbol label="¶">paragraph</symbol>
 | 
			
		||||
  <symbol label="p">p</symbol>
 | 
			
		||||
  <symbol label="P">P</symbol>
 | 
			
		||||
  <symbol label="0">0</symbol>
 | 
			
		||||
  <symbol label="△">U25B3</symbol>
 | 
			
		||||
  <symbol keyval="229" label="å">aring</symbol>
 | 
			
		||||
  <symbol keyval="197" label="Å">Aring</symbol>
 | 
			
		||||
  <symbol label="a">a</symbol>
 | 
			
		||||
  <symbol label="A">A</symbol>
 | 
			
		||||
  <symbol label="@">at</symbol>
 | 
			
		||||
  <symbol label="©">copyright</symbol>
 | 
			
		||||
  <symbol label="s">s</symbol>
 | 
			
		||||
  <symbol label="S">S</symbol>
 | 
			
		||||
  <symbol label="#">numbersign</symbol>
 | 
			
		||||
  <symbol label="®">U00AE</symbol>
 | 
			
		||||
  <symbol label="d">d</symbol>
 | 
			
		||||
  <symbol label="D">D</symbol>
 | 
			
		||||
  <symbol label="$">dollar</symbol>
 | 
			
		||||
  <symbol label="£">U00A3</symbol>
 | 
			
		||||
  <symbol label="f">f</symbol>
 | 
			
		||||
  <symbol label="F">F</symbol>
 | 
			
		||||
  <symbol label="%">percent</symbol>
 | 
			
		||||
  <symbol label="€">EuroSign</symbol>
 | 
			
		||||
  <symbol label="g">g</symbol>
 | 
			
		||||
  <symbol label="G">G</symbol>
 | 
			
		||||
  <symbol label="&">ampersand</symbol>
 | 
			
		||||
  <symbol label="¥">U00A5</symbol>
 | 
			
		||||
  <symbol label="h">h</symbol>
 | 
			
		||||
  <symbol label="H">H</symbol>
 | 
			
		||||
  <symbol label="-">minus</symbol>
 | 
			
		||||
  <symbol label="^">asciicircum</symbol>
 | 
			
		||||
  <symbol label="j">j</symbol>
 | 
			
		||||
  <symbol label="J">J</symbol>
 | 
			
		||||
  <symbol label="_">underscore</symbol>
 | 
			
		||||
  <symbol label="°">degree</symbol>
 | 
			
		||||
  <symbol label="k">k</symbol>
 | 
			
		||||
  <symbol label="K">K</symbol>
 | 
			
		||||
  <symbol label="+">plus</symbol>
 | 
			
		||||
  <symbol label="=">equal</symbol>
 | 
			
		||||
  <symbol label="l">l</symbol>
 | 
			
		||||
  <symbol label="L">L</symbol>
 | 
			
		||||
  <symbol label="(">parenleft</symbol>
 | 
			
		||||
  <symbol label="{">braceleft</symbol>
 | 
			
		||||
  <symbol keyval="248" label="ø">oslash</symbol>
 | 
			
		||||
  <symbol keyval="216" label="Ø">Oslash</symbol>
 | 
			
		||||
  <symbol label=")">parenright</symbol>
 | 
			
		||||
  <symbol label="}">braceright</symbol>
 | 
			
		||||
  <symbol keyval="230" label="æ">ae</symbol>
 | 
			
		||||
  <symbol keyval="198" label="Æ">AE</symbol>
 | 
			
		||||
  <symbol keyval="65293" icon="key-enter">Return</symbol>
 | 
			
		||||
  <symbol keyval="65505" icon="key-shift">Shift_L</symbol>
 | 
			
		||||
  <symbol label="z">z</symbol>
 | 
			
		||||
  <symbol label="Z">Z</symbol>
 | 
			
		||||
  <symbol label=",">comma</symbol>
 | 
			
		||||
  <symbol label="\">backslash</symbol>
 | 
			
		||||
  <symbol label="x">x</symbol>
 | 
			
		||||
  <symbol label="X">X</symbol>
 | 
			
		||||
  <symbol label=""">quotedbl</symbol>
 | 
			
		||||
  <symbol label="/">slash</symbol>
 | 
			
		||||
  <symbol label="c">c</symbol>
 | 
			
		||||
  <symbol label="C">C</symbol>
 | 
			
		||||
  <symbol label="'">quoteright</symbol>
 | 
			
		||||
  <symbol label="<">less</symbol>
 | 
			
		||||
  <symbol label="v">v</symbol>
 | 
			
		||||
  <symbol label="V">V</symbol>
 | 
			
		||||
  <symbol label=":">colon</symbol>
 | 
			
		||||
  <symbol label=">">greater</symbol>
 | 
			
		||||
  <symbol label="b">b</symbol>
 | 
			
		||||
  <symbol label="B">B</symbol>
 | 
			
		||||
  <symbol label=";">semicolon</symbol>
 | 
			
		||||
  <symbol label="=">equal</symbol>
 | 
			
		||||
  <symbol label="n">n</symbol>
 | 
			
		||||
  <symbol label="N">N</symbol>
 | 
			
		||||
  <symbol label="!">exclam</symbol>
 | 
			
		||||
  <symbol label="[">bracketleft</symbol>
 | 
			
		||||
  <symbol label="m">m</symbol>
 | 
			
		||||
  <symbol label="M">M</symbol>
 | 
			
		||||
  <symbol label="?">question</symbol>
 | 
			
		||||
  <symbol label="]">bracketright</symbol>
 | 
			
		||||
  <symbol label=".">period</symbol>
 | 
			
		||||
  <symbol label="123">show_numbers</symbol>
 | 
			
		||||
  <symbol label="ABC">show_letters</symbol>
 | 
			
		||||
  <symbol label="☺" icon="keyboard-mode-symbolic" tooltip="Setup">preferences</symbol>
 | 
			
		||||
  <symbol label=" ">space</symbol>
 | 
			
		||||
  <symbol keyval="65288" icon="edit-clear-symbolic">BackSpace</symbol>
 | 
			
		||||
</symbols>
 | 
			
		||||
@ -1,22 +0,0 @@
 | 
			
		||||
<?xml version='1.0' encoding='ASCII' standalone='yes'?>
 | 
			
		||||
<symbols version="0.90">
 | 
			
		||||
  <symbol label="1">1</symbol>
 | 
			
		||||
  <symbol label="2">2</symbol>
 | 
			
		||||
  <symbol label="3">3</symbol>
 | 
			
		||||
  <symbol label="(">parenleft</symbol>
 | 
			
		||||
  <symbol label=")">parenright</symbol>
 | 
			
		||||
  <symbol label="4">4</symbol>
 | 
			
		||||
  <symbol label="5">5</symbol>
 | 
			
		||||
  <symbol label="6">6</symbol>
 | 
			
		||||
  <symbol label="#">numbersign</symbol>
 | 
			
		||||
  <symbol label="*">asterisk</symbol>
 | 
			
		||||
  <symbol label="7">7</symbol>
 | 
			
		||||
  <symbol label="8">8</symbol>
 | 
			
		||||
  <symbol label="9">9</symbol>
 | 
			
		||||
  <symbol label="+">plus</symbol>
 | 
			
		||||
  <symbol label="-">minus</symbol>
 | 
			
		||||
  <symbol label="0">0</symbol>
 | 
			
		||||
  <symbol keyval="65293" icon="key-enter">Return</symbol>
 | 
			
		||||
  <symbol label=" ">space</symbol>
 | 
			
		||||
  <symbol keyval="65288" icon="edit-clear-symbolic">BackSpace</symbol>
 | 
			
		||||
</symbols>
 | 
			
		||||
@ -1,118 +0,0 @@
 | 
			
		||||
<?xml version='1.0' encoding='ASCII' standalone='yes'?>
 | 
			
		||||
<symbols version="0.90">
 | 
			
		||||
  <symbol label="*">asterisk</symbol>
 | 
			
		||||
  <symbol label="+/=">show_symbols</symbol>
 | 
			
		||||
  <symbol label="q">q</symbol>
 | 
			
		||||
  <symbol label="Q">Q</symbol>
 | 
			
		||||
  <symbol label="1">1</symbol>
 | 
			
		||||
  <symbol label="~">asciitilde</symbol>
 | 
			
		||||
  <symbol label="w">w</symbol>
 | 
			
		||||
  <symbol label="W">W</symbol>
 | 
			
		||||
  <symbol label="2">2</symbol>
 | 
			
		||||
  <symbol label="`">quoteleft</symbol>
 | 
			
		||||
  <symbol label="e">e</symbol>
 | 
			
		||||
  <symbol label="E">E</symbol>
 | 
			
		||||
  <symbol label="3">3</symbol>
 | 
			
		||||
  <symbol label="|">bar</symbol>
 | 
			
		||||
  <symbol label="r">r</symbol>
 | 
			
		||||
  <symbol label="R">R</symbol>
 | 
			
		||||
  <symbol label="4">4</symbol>
 | 
			
		||||
  <symbol label="·">U00B7</symbol>
 | 
			
		||||
  <symbol label="t">t</symbol>
 | 
			
		||||
  <symbol label="T">T</symbol>
 | 
			
		||||
  <symbol label="5">5</symbol>
 | 
			
		||||
  <symbol label="√">squareroot</symbol>
 | 
			
		||||
  <symbol label="y">y</symbol>
 | 
			
		||||
  <symbol label="Y">Y</symbol>
 | 
			
		||||
  <symbol label="6">6</symbol>
 | 
			
		||||
  <symbol label="π">Greek_pi</symbol>
 | 
			
		||||
  <symbol label="u">u</symbol>
 | 
			
		||||
  <symbol label="U">U</symbol>
 | 
			
		||||
  <symbol label="7">7</symbol>
 | 
			
		||||
  <symbol label="÷">division</symbol>
 | 
			
		||||
  <symbol label="i">i</symbol>
 | 
			
		||||
  <symbol label="I">I</symbol>
 | 
			
		||||
  <symbol label="8">8</symbol>
 | 
			
		||||
  <symbol label="×">multiply</symbol>
 | 
			
		||||
  <symbol label="o">o</symbol>
 | 
			
		||||
  <symbol label="O">O</symbol>
 | 
			
		||||
  <symbol label="9">9</symbol>
 | 
			
		||||
  <symbol label="¶">paragraph</symbol>
 | 
			
		||||
  <symbol label="p">p</symbol>
 | 
			
		||||
  <symbol label="P">P</symbol>
 | 
			
		||||
  <symbol label="0">0</symbol>
 | 
			
		||||
  <symbol label="τ">Greek_tau</symbol>
 | 
			
		||||
  <symbol label="a">a</symbol>
 | 
			
		||||
  <symbol label="A">A</symbol>
 | 
			
		||||
  <symbol label="@">at</symbol>
 | 
			
		||||
  <symbol label="©">copyright</symbol>
 | 
			
		||||
  <symbol label="s">s</symbol>
 | 
			
		||||
  <symbol label="S">S</symbol>
 | 
			
		||||
  <symbol label="#">numbersign</symbol>
 | 
			
		||||
  <symbol label="®">U00AE</symbol>
 | 
			
		||||
  <symbol label="d">d</symbol>
 | 
			
		||||
  <symbol label="D">D</symbol>
 | 
			
		||||
  <symbol label="$">dollar</symbol>
 | 
			
		||||
  <symbol label="£">U00A3</symbol>
 | 
			
		||||
  <symbol label="f">f</symbol>
 | 
			
		||||
  <symbol label="F">F</symbol>
 | 
			
		||||
  <symbol label="%">percent</symbol>
 | 
			
		||||
  <symbol label="€">EuroSign</symbol>
 | 
			
		||||
  <symbol label="g">g</symbol>
 | 
			
		||||
  <symbol label="G">G</symbol>
 | 
			
		||||
  <symbol label="&">ampersand</symbol>
 | 
			
		||||
  <symbol label="¥">U00A5</symbol>
 | 
			
		||||
  <symbol label="h">h</symbol>
 | 
			
		||||
  <symbol label="H">H</symbol>
 | 
			
		||||
  <symbol label="-">minus</symbol>
 | 
			
		||||
  <symbol label="^">asciicircum</symbol>
 | 
			
		||||
  <symbol label="j">j</symbol>
 | 
			
		||||
  <symbol label="J">J</symbol>
 | 
			
		||||
  <symbol label="_">underscore</symbol>
 | 
			
		||||
  <symbol label="°">degree</symbol>
 | 
			
		||||
  <symbol label="k">k</symbol>
 | 
			
		||||
  <symbol label="K">K</symbol>
 | 
			
		||||
  <symbol label="+">plus</symbol>
 | 
			
		||||
  <symbol label="=">equal</symbol>
 | 
			
		||||
  <symbol label="l">l</symbol>
 | 
			
		||||
  <symbol label="L">L</symbol>
 | 
			
		||||
  <symbol label="(">parenleft</symbol>
 | 
			
		||||
  <symbol label="{">braceleft</symbol>
 | 
			
		||||
  <symbol label=")">parenright</symbol>
 | 
			
		||||
  <symbol label="}">braceright</symbol>
 | 
			
		||||
  <symbol keyval="65293" icon="key-enter">Return</symbol>
 | 
			
		||||
  <symbol keyval="65505" icon="key-shift">Shift_L</symbol>
 | 
			
		||||
  <symbol label="z">z</symbol>
 | 
			
		||||
  <symbol label="Z">Z</symbol>
 | 
			
		||||
  <symbol label=",">comma</symbol>
 | 
			
		||||
  <symbol label="\">backslash</symbol>
 | 
			
		||||
  <symbol label="x">x</symbol>
 | 
			
		||||
  <symbol label="X">X</symbol>
 | 
			
		||||
  <symbol label=""">quotedbl</symbol>
 | 
			
		||||
  <symbol label="/">slash</symbol>
 | 
			
		||||
  <symbol label="c">c</symbol>
 | 
			
		||||
  <symbol label="C">C</symbol>
 | 
			
		||||
  <symbol label="'">quoteright</symbol>
 | 
			
		||||
  <symbol label="<">less</symbol>
 | 
			
		||||
  <symbol label="v">v</symbol>
 | 
			
		||||
  <symbol label="V">V</symbol>
 | 
			
		||||
  <symbol label=":">colon</symbol>
 | 
			
		||||
  <symbol label=">">greater</symbol>
 | 
			
		||||
  <symbol label="b">b</symbol>
 | 
			
		||||
  <symbol label="B">B</symbol>
 | 
			
		||||
  <symbol label=";">semicolon</symbol>
 | 
			
		||||
  <symbol label="n">n</symbol>
 | 
			
		||||
  <symbol label="N">N</symbol>
 | 
			
		||||
  <symbol label="!">exclam</symbol>
 | 
			
		||||
  <symbol label="[">bracketleft</symbol>
 | 
			
		||||
  <symbol label="m">m</symbol>
 | 
			
		||||
  <symbol label="M">M</symbol>
 | 
			
		||||
  <symbol label="?">question</symbol>
 | 
			
		||||
  <symbol label="]">bracketright</symbol>
 | 
			
		||||
  <symbol label=".">period</symbol>
 | 
			
		||||
  <symbol label="123">show_numbers</symbol>
 | 
			
		||||
  <symbol label="ABC">show_letters</symbol>
 | 
			
		||||
  <symbol label="☺" icon="keyboard-mode-symbolic" tooltip="Setup">preferences</symbol>
 | 
			
		||||
  <symbol label=" ">space</symbol>
 | 
			
		||||
  <symbol keyval="65288" icon="edit-clear-symbolic">BackSpace</symbol>
 | 
			
		||||
</symbols>
 | 
			
		||||
							
								
								
									
										81
									
								
								data/keyboards/us.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								data/keyboards/us.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
			
		||||
---
 | 
			
		||||
bounds: { x: 10, y: 10, width: 410, height: 229 }
 | 
			
		||||
 | 
			
		||||
outlines:
 | 
			
		||||
    default:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 37.46341, height: 52 }
 | 
			
		||||
    altline:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 48.39024, height: 52 }
 | 
			
		||||
    outline7:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 88.97561, height: 52 }
 | 
			
		||||
    spaceline:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 150.5853, height: 52 }
 | 
			
		||||
 | 
			
		||||
views:
 | 
			
		||||
    base:
 | 
			
		||||
        - "q w e r t y u i o p"
 | 
			
		||||
        - "a s d f g h j k l"
 | 
			
		||||
        - "Shift_L   z x c v b n m  BackSpace"
 | 
			
		||||
        - "show_numbers preferences         space        .    Return"
 | 
			
		||||
    upper:
 | 
			
		||||
        - "Q W E R T Y U I O P"
 | 
			
		||||
        - "A S D F G H J K L"
 | 
			
		||||
        - "Shift_L   Z X C V B N M  BackSpace"
 | 
			
		||||
        - "show_numbers preferences         space        .    Return"
 | 
			
		||||
    numbers:
 | 
			
		||||
        - "1 2 3 4 5 6 7 8 9 0"
 | 
			
		||||
        - "@ # $ % & - _ + ( )"
 | 
			
		||||
        - "show_symbols   , \" ' colon ; ! ?  BackSpace"
 | 
			
		||||
        - "show_letters preferences         space        .    Return"
 | 
			
		||||
    symbols:
 | 
			
		||||
        - "~ ` | · √ π τ ÷ × ¶"
 | 
			
		||||
        - "© ® £ € ¥ ^ ° * { }"
 | 
			
		||||
        - "show_numbers   \\ / < > = [ ]  BackSpace"
 | 
			
		||||
        - "show_letters preferences         space        .    Return"
 | 
			
		||||
 | 
			
		||||
buttons:
 | 
			
		||||
    Shift_L:
 | 
			
		||||
        action:
 | 
			
		||||
            locking:
 | 
			
		||||
                lock_view: "upper"
 | 
			
		||||
                unlock_view: "base"
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        icon: "key-shift"
 | 
			
		||||
    BackSpace:
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        icon: "edit-clear-symbolic"
 | 
			
		||||
    preferences:
 | 
			
		||||
        action: "show_prefs"
 | 
			
		||||
        outline: "altline"
 | 
			
		||||
        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: "*/="
 | 
			
		||||
    ".":
 | 
			
		||||
        outline: altline
 | 
			
		||||
    space:
 | 
			
		||||
        outline: spaceline
 | 
			
		||||
        label: " "
 | 
			
		||||
    Return:
 | 
			
		||||
        outline: outline7
 | 
			
		||||
        icon: "key-enter"
 | 
			
		||||
    colon:
 | 
			
		||||
        label: ":"
 | 
			
		||||
    "\"":
 | 
			
		||||
        keysym: "quotedbl"
 | 
			
		||||
@ -6,4 +6,5 @@ Exec=squeekboard
 | 
			
		||||
Icon=squeekboard
 | 
			
		||||
Terminal=false
 | 
			
		||||
Type=Application
 | 
			
		||||
NoDisplay=true
 | 
			
		||||
Categories=GTK;Utility;
 | 
			
		||||
 | 
			
		||||
@ -2,10 +2,6 @@
 | 
			
		||||
<gresources>
 | 
			
		||||
  <gresource prefix="/sm/puri/squeekboard">
 | 
			
		||||
   <file compressed="true">style.css</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/geometry/compact.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/geometry/extended.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/geometry/number-keypad.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/keyboards.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ar.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/as-inscript.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/be.xml</file>
 | 
			
		||||
@ -23,7 +19,6 @@
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ml-inscript.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/mr-inscript.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/my.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/nb.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/or-inscript.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/pa-inscript.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ru.xml</file>
 | 
			
		||||
@ -33,9 +28,7 @@
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/th.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ua.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ug.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/us.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/zh-bopomofo.xml</file>
 | 
			
		||||
   <file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/special/number.xml</file>
 | 
			
		||||
   <file>icons/key-enter.svg</file>
 | 
			
		||||
   <file>icons/key-shift.svg</file>
 | 
			
		||||
   <file>icons/keyboard-mode-symbolic.svg</file>
 | 
			
		||||
 | 
			
		||||
@ -17,3 +17,23 @@
 | 
			
		||||
    background: #1c71d8;
 | 
			
		||||
    border-color: #3584e4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Return {
 | 
			
		||||
    background: #1c71d8;
 | 
			
		||||
    border-color: #1a5fb4
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Return:active {
 | 
			
		||||
    background: #1c71d8;
 | 
			
		||||
    border-color: #3584e4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Shift_L {
 | 
			
		||||
    background: #2b292f;
 | 
			
		||||
    border-color: #3e3a44
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Shift_L:active {
 | 
			
		||||
    background: #1c71d8;
 | 
			
		||||
    border-color: #3584e4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								debian/cargo/config
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								debian/cargo/config
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
# When modifying this file, consider instead
 | 
			
		||||
# to take advantage of the method that Cargo packagers use
 | 
			
		||||
# to set up all the necessary stuff automatically:
 | 
			
		||||
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=907629#30
 | 
			
		||||
 | 
			
		||||
[source.crates-io]
 | 
			
		||||
registry = 'https://github.com/rust-lang/crates.io-index'
 | 
			
		||||
replace-with = 'vendored-sources'
 | 
			
		||||
 | 
			
		||||
[source.vendored-sources]
 | 
			
		||||
directory = '/usr/share/cargo/registry'
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@ -1,3 +1,16 @@
 | 
			
		||||
squeekboard (1.2.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * Use Cargo-based dependencies
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Tue, 24 Sep 2019 10:42:15 +0000
 | 
			
		||||
 | 
			
		||||
squeekboard (1.1.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * Use new keyboard layout format
 | 
			
		||||
 | 
			
		||||
 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Mon, 02 Sep 2019 10:12:02 +0000
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
squeekboard (1.0.10) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * Use a shared DBus definition
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@ -3,12 +3,19 @@ Section: x11
 | 
			
		||||
Priority: optional
 | 
			
		||||
Maintainer: Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>
 | 
			
		||||
Build-Depends:
 | 
			
		||||
 cargo,
 | 
			
		||||
 debhelper (>= 10),
 | 
			
		||||
 meson (>=0.43.0),
 | 
			
		||||
 meson (>=0.51.0),
 | 
			
		||||
 ninja-build,
 | 
			
		||||
 pkg-config,
 | 
			
		||||
 libglib2.0-dev,
 | 
			
		||||
 libgtk-3-dev,
 | 
			
		||||
 libcroco3-dev,
 | 
			
		||||
 librust-bitflags-1-dev (>= 1.0),
 | 
			
		||||
 librust-maplit-1-dev (>= 1.0),
 | 
			
		||||
 librust-serde-derive-1-dev (>= 1.0),
 | 
			
		||||
 librust-serde-yaml-0.8-dev (>= 0.8),
 | 
			
		||||
 librust-xkbcommon-0.4+wayland-dev (>= 0.4),
 | 
			
		||||
 libwayland-dev (>= 1.16),
 | 
			
		||||
 rustc,
 | 
			
		||||
 wayland-protocols (>= 1.14),
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							@ -1,8 +1,15 @@
 | 
			
		||||
#!/usr/bin/make -f
 | 
			
		||||
 | 
			
		||||
export CARGO_HOME = $(CURDIR)/debian/cargo
 | 
			
		||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
 | 
			
		||||
 | 
			
		||||
%:
 | 
			
		||||
	dh $@ --builddirectory=_build --buildsystem=meson
 | 
			
		||||
 | 
			
		||||
# The Debian version of linked-hash-map doesn't provide any hash,
 | 
			
		||||
# causing Cargo to refuse to build with a crates.io copy
 | 
			
		||||
build:
 | 
			
		||||
	rm Cargo.lock
 | 
			
		||||
	dh $@ --builddirectory=_build --buildsystem=meson
 | 
			
		||||
 | 
			
		||||
override_dh_autoreconf:
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								debian/squeekboard.lintian-overrides
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								debian/squeekboard.lintian-overrides
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
# yaml-rust 0.4.3 shares some roots with libyaml, including the string which lintian checks, creating a false positive
 | 
			
		||||
squeekboard binary: embedded-library usr/bin/squeekboard: libyaml
 | 
			
		||||
@ -34,7 +34,6 @@
 | 
			
		||||
 | 
			
		||||
#include "eek-renderer.h"
 | 
			
		||||
#include "eek-keyboard.h"
 | 
			
		||||
#include "src/symbol.h"
 | 
			
		||||
 | 
			
		||||
#include "eek-gtk-keyboard.h"
 | 
			
		||||
 | 
			
		||||
@ -62,15 +61,15 @@ typedef struct _EekGtkKeyboardPrivate
 | 
			
		||||
G_DEFINE_TYPE_WITH_PRIVATE (EekGtkKeyboard, eek_gtk_keyboard, GTK_TYPE_DRAWING_AREA)
 | 
			
		||||
 | 
			
		||||
static void       on_button_pressed          (struct squeek_button *button, struct squeek_view *view,
 | 
			
		||||
                                           EekGtkKeyboard *self);
 | 
			
		||||
static void       on_button_released         (struct squeek_button *button,
 | 
			
		||||
                                           struct squeek_view *view,
 | 
			
		||||
                                           EekGtkKeyboard *self);
 | 
			
		||||
static void       render_pressed_button      (GtkWidget   *widget, struct button_place *place);
 | 
			
		||||
static void       render_locked_button       (GtkWidget   *widget,
 | 
			
		||||
                                           struct button_place *place);
 | 
			
		||||
static void       render_released_button     (GtkWidget   *widget,
 | 
			
		||||
                                           struct squeek_button *button);
 | 
			
		||||
                                              EekGtkKeyboard *self);
 | 
			
		||||
static void       on_button_released         (const struct squeek_button *button,
 | 
			
		||||
                                              struct squeek_view *view,
 | 
			
		||||
                                              EekGtkKeyboard *self);
 | 
			
		||||
static void       render_pressed_button      (GtkWidget *widget, struct button_place *place);
 | 
			
		||||
static void       render_locked_button       (GtkWidget *widget,
 | 
			
		||||
                                              struct button_place *place);
 | 
			
		||||
static void       render_released_button     (GtkWidget *widget,
 | 
			
		||||
                                              const struct squeek_button *button);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_gtk_keyboard_real_realize (GtkWidget      *self)
 | 
			
		||||
@ -81,7 +80,8 @@ eek_gtk_keyboard_real_realize (GtkWidget      *self)
 | 
			
		||||
                           GDK_KEY_RELEASE_MASK |
 | 
			
		||||
                           GDK_BUTTON_PRESS_MASK |
 | 
			
		||||
                           GDK_BUTTON_RELEASE_MASK |
 | 
			
		||||
                           GDK_BUTTON_MOTION_MASK);
 | 
			
		||||
                           GDK_BUTTON_MOTION_MASK |
 | 
			
		||||
                           GDK_TOUCH_MASK);
 | 
			
		||||
 | 
			
		||||
    GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->realize (self);
 | 
			
		||||
}
 | 
			
		||||
@ -109,25 +109,23 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
 | 
			
		||||
 | 
			
		||||
    eek_renderer_render_keyboard (priv->renderer, cr);
 | 
			
		||||
 | 
			
		||||
    struct squeek_view *view = priv->keyboard->views[priv->keyboard->level];
 | 
			
		||||
    struct squeek_view *view = squeek_layout_get_current_view(priv->keyboard->layout);
 | 
			
		||||
 | 
			
		||||
    /* redraw pressed key */
 | 
			
		||||
    const GList *list = priv->keyboard->pressed_buttons;
 | 
			
		||||
    const GList *list = priv->keyboard->pressed_keys;
 | 
			
		||||
    for (const GList *head = list; head; head = g_list_next (head)) {
 | 
			
		||||
        struct button_place place = squeek_view_find_key(
 | 
			
		||||
            view, squeek_button_get_key(head->data)
 | 
			
		||||
            view, head->data
 | 
			
		||||
        );
 | 
			
		||||
        if (place.button)
 | 
			
		||||
            render_pressed_button (self, &place);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* redraw locked key */
 | 
			
		||||
    list = priv->keyboard->locked_buttons;
 | 
			
		||||
    list = priv->keyboard->locked_keys;
 | 
			
		||||
    for (const GList *head = list; head; head = g_list_next (head)) {
 | 
			
		||||
        struct button_place place = squeek_view_find_key(
 | 
			
		||||
            view, squeek_button_get_key(
 | 
			
		||||
                ((EekModifierKey *)head->data)->button
 | 
			
		||||
            )
 | 
			
		||||
            view, ((EekModifierKey *)head->data)->key
 | 
			
		||||
        );
 | 
			
		||||
        if (place.button)
 | 
			
		||||
            render_locked_button (self, &place);
 | 
			
		||||
@ -160,56 +158,78 @@ static void depress(EekGtkKeyboard *self,
 | 
			
		||||
    struct squeek_button *button = eek_renderer_find_button_by_position (priv->renderer, view, x, y);
 | 
			
		||||
 | 
			
		||||
    if (button) {
 | 
			
		||||
        eek_keyboard_press_button(priv->keyboard, button, time);
 | 
			
		||||
        eek_keyboard_press_key(
 | 
			
		||||
            priv->keyboard,
 | 
			
		||||
            squeek_button_get_key(button),
 | 
			
		||||
            time
 | 
			
		||||
        );
 | 
			
		||||
        on_button_pressed(button, view, self);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void drag(EekGtkKeyboard *self,
 | 
			
		||||
                 gdouble x, gdouble y, guint32 time) {
 | 
			
		||||
                 gdouble x, gdouble y, guint32 time)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
			
		||||
    struct squeek_view *view = level_keyboard_current(priv->keyboard);
 | 
			
		||||
    struct squeek_button *button = eek_renderer_find_button_by_position (priv->renderer, view, x, y);
 | 
			
		||||
    GList *list, *head;
 | 
			
		||||
 | 
			
		||||
    list = g_list_copy(priv->keyboard->pressed_buttons);
 | 
			
		||||
    list = g_list_copy(priv->keyboard->pressed_keys);
 | 
			
		||||
 | 
			
		||||
    if (button) {
 | 
			
		||||
        gboolean found = FALSE;
 | 
			
		||||
 | 
			
		||||
        for (head = list; head; head = g_list_next (head)) {
 | 
			
		||||
            if (head->data == button) {
 | 
			
		||||
            struct squeek_key *key = head->data;
 | 
			
		||||
            if (squeek_button_has_key(button, key)) {
 | 
			
		||||
                found = TRUE;
 | 
			
		||||
            } else {
 | 
			
		||||
                eek_keyboard_release_button(priv->keyboard, head->data, time);
 | 
			
		||||
                on_button_released(button, view, self);
 | 
			
		||||
                eek_keyboard_release_key(priv->keyboard, key, time);
 | 
			
		||||
                // The released handler proceeds to ignore this info...
 | 
			
		||||
                // let's do this for consistency nevertheless
 | 
			
		||||
                struct button_place place = squeek_view_find_key(view, key);
 | 
			
		||||
                on_button_released(place.button, view, self);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        g_list_free (list);
 | 
			
		||||
 | 
			
		||||
        if (!found) {
 | 
			
		||||
            eek_keyboard_press_button(priv->keyboard, button, time);
 | 
			
		||||
            eek_keyboard_press_key(
 | 
			
		||||
                priv->keyboard,
 | 
			
		||||
                squeek_button_get_key(button),
 | 
			
		||||
                time
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            on_button_pressed(button, view, self);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        for (head = list; head; head = g_list_next (head)) {
 | 
			
		||||
            eek_keyboard_release_button(priv->keyboard, head->data, time);
 | 
			
		||||
            on_button_released(head->data, view, self);
 | 
			
		||||
            struct squeek_key *key = head->data;
 | 
			
		||||
            eek_keyboard_release_key(priv->keyboard, key, time);
 | 
			
		||||
            // The released handler proceeds to ignore this info...
 | 
			
		||||
            // let's do this for consistency nevertheless
 | 
			
		||||
            struct button_place place = squeek_view_find_key(view, key);
 | 
			
		||||
            on_button_released(place.button, view, self);
 | 
			
		||||
        }
 | 
			
		||||
        g_list_free (list);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void release(EekGtkKeyboard *self, guint32 time) {
 | 
			
		||||
static void release(EekGtkKeyboard *self, guint32 time)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
    struct squeek_view *view = level_keyboard_current(priv->keyboard);
 | 
			
		||||
 | 
			
		||||
    GList *list = g_list_copy(priv->keyboard->pressed_buttons);
 | 
			
		||||
    GList *list = g_list_copy(priv->keyboard->pressed_keys);
 | 
			
		||||
    for (GList *head = list; head; head = g_list_next (head)) {
 | 
			
		||||
        struct squeek_button *button = head->data;
 | 
			
		||||
        eek_keyboard_release_button(priv->keyboard, button, time);
 | 
			
		||||
        on_button_released(button, view, self);
 | 
			
		||||
        struct squeek_key *key = head->data;
 | 
			
		||||
        eek_keyboard_release_key(priv->keyboard, key, time);
 | 
			
		||||
        // The released handler proceeds to ignore this info...
 | 
			
		||||
        // let's do this for consistency nevertheless
 | 
			
		||||
        struct button_place place = squeek_view_find_key(view, key);
 | 
			
		||||
        on_button_released(place.button, view, self);
 | 
			
		||||
    }
 | 
			
		||||
    g_list_free (list);
 | 
			
		||||
}
 | 
			
		||||
@ -254,27 +274,27 @@ handle_touch_event (GtkWidget     *widget,
 | 
			
		||||
    EekGtkKeyboard        *self = EEK_GTK_KEYBOARD (widget);
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
    /* For each new touch, release the previous one and record the new event
 | 
			
		||||
       sequence. */
 | 
			
		||||
    if (event->type == GDK_TOUCH_BEGIN) {
 | 
			
		||||
        if (priv->sequence) {
 | 
			
		||||
            // Ignore second and following touch points
 | 
			
		||||
            return FALSE;
 | 
			
		||||
        }
 | 
			
		||||
        release(self, event->time);
 | 
			
		||||
        priv->sequence = event->sequence;
 | 
			
		||||
        depress(self, event->x, event->y, event->time);
 | 
			
		||||
        return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (priv->sequence != event->sequence) {
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (event->type == GDK_TOUCH_UPDATE) {
 | 
			
		||||
    /* Only allow the latest touch point to be dragged. */
 | 
			
		||||
    if (event->type == GDK_TOUCH_UPDATE && event->sequence == priv->sequence) {
 | 
			
		||||
        drag(self, event->x, event->y, event->time);
 | 
			
		||||
    }
 | 
			
		||||
    if (event->type == GDK_TOUCH_END || event->type == GDK_TOUCH_CANCEL) {
 | 
			
		||||
    else if (event->type == GDK_TOUCH_END || event->type == GDK_TOUCH_CANCEL) {
 | 
			
		||||
        // TODO: can the event have different coords than the previous update event?
 | 
			
		||||
        release(self, event->time);
 | 
			
		||||
        priv->sequence = NULL;
 | 
			
		||||
        /* Only respond to the release of the latest touch point. Previous
 | 
			
		||||
           touches have already been released. */
 | 
			
		||||
        if (event->sequence == priv->sequence) {
 | 
			
		||||
            release(self, event->time);
 | 
			
		||||
            priv->sequence = NULL;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return TRUE;
 | 
			
		||||
}
 | 
			
		||||
@ -286,49 +306,20 @@ eek_gtk_keyboard_real_unmap (GtkWidget *self)
 | 
			
		||||
	    eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
 | 
			
		||||
 | 
			
		||||
    if (priv->keyboard) {
 | 
			
		||||
        GList *list, *head;
 | 
			
		||||
        GList *head;
 | 
			
		||||
 | 
			
		||||
        /* Make a copy of HEAD before sending "released" signal on
 | 
			
		||||
           elements, so that the default handler of
 | 
			
		||||
           EekKeyboard::key-released signal can remove elements from its
 | 
			
		||||
           internal copy */
 | 
			
		||||
        list = g_list_copy(priv->keyboard->pressed_buttons);
 | 
			
		||||
        for (head = list; head; head = g_list_next (head)) {
 | 
			
		||||
            g_log("squeek", G_LOG_LEVEL_DEBUG, "emit EekKey released");
 | 
			
		||||
            g_signal_emit_by_name (head->data, "released");
 | 
			
		||||
        for (head = priv->keyboard->pressed_keys; head; head = g_list_next (head)) {
 | 
			
		||||
            /* Unlike other places where we call this, we don't call
 | 
			
		||||
               on_button_released afterwards since we don't want to queue a
 | 
			
		||||
               redraw. */
 | 
			
		||||
            eek_keyboard_release_key(priv->keyboard, head->data,
 | 
			
		||||
                                        gdk_event_get_time(NULL));
 | 
			
		||||
        }
 | 
			
		||||
        g_list_free (list);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->unmap (self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
eek_gtk_keyboard_real_query_tooltip (GtkWidget  *widget,
 | 
			
		||||
                                     gint        x,
 | 
			
		||||
                                     gint        y,
 | 
			
		||||
                                     gboolean    keyboard_tooltip,
 | 
			
		||||
                                     GtkTooltip *tooltip)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboard        *self = EEK_GTK_KEYBOARD (widget);
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
			
		||||
    struct squeek_view *view = level_keyboard_current(priv->keyboard);
 | 
			
		||||
 | 
			
		||||
    struct squeek_button *button = eek_renderer_find_button_by_position (priv->renderer,
 | 
			
		||||
                                                     view,
 | 
			
		||||
                                                     (gdouble)x,
 | 
			
		||||
                                                     (gdouble)y);
 | 
			
		||||
    if (button) {
 | 
			
		||||
        //struct squeek_symbol *symbol = eek_key_get_symbol_at_index(key, 0, priv->keyboard->level);
 | 
			
		||||
        const gchar *text = NULL; // FIXME
 | 
			
		||||
        if (text) {
 | 
			
		||||
            gtk_tooltip_set_text (tooltip, text);
 | 
			
		||||
            return TRUE;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_gtk_keyboard_set_property (GObject      *object,
 | 
			
		||||
                               guint         prop_id,
 | 
			
		||||
@ -351,17 +342,16 @@ eek_gtk_keyboard_dispose (GObject *object)
 | 
			
		||||
    if (priv->renderer) {
 | 
			
		||||
        g_object_unref (priv->renderer);
 | 
			
		||||
        priv->renderer = NULL;
 | 
			
		||||
        priv->renderer = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (priv->keyboard) {
 | 
			
		||||
        GList *list, *head;
 | 
			
		||||
        GList *head;
 | 
			
		||||
 | 
			
		||||
        list = g_list_copy(priv->keyboard->pressed_buttons);
 | 
			
		||||
        for (head = list; head; head = g_list_next (head)) {
 | 
			
		||||
            g_log("squeek", G_LOG_LEVEL_DEBUG, "emit EekKey pressed");
 | 
			
		||||
            g_signal_emit_by_name (head->data, "released", level_keyboard_current(priv->keyboard));
 | 
			
		||||
        for (head = priv->keyboard->pressed_keys; head; head = g_list_next (head)) {
 | 
			
		||||
            eek_keyboard_release_key(priv->keyboard, head->data,
 | 
			
		||||
                                        gdk_event_get_time(NULL));
 | 
			
		||||
        }
 | 
			
		||||
        g_list_free (list);
 | 
			
		||||
 | 
			
		||||
        priv->keyboard = NULL;
 | 
			
		||||
    }
 | 
			
		||||
@ -385,8 +375,6 @@ eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass)
 | 
			
		||||
        eek_gtk_keyboard_real_button_release_event;
 | 
			
		||||
    widget_class->motion_notify_event =
 | 
			
		||||
        eek_gtk_keyboard_real_motion_notify_event;
 | 
			
		||||
    widget_class->query_tooltip =
 | 
			
		||||
        eek_gtk_keyboard_real_query_tooltip;
 | 
			
		||||
    widget_class->touch_event = handle_touch_event;
 | 
			
		||||
 | 
			
		||||
    gobject_class->set_property = eek_gtk_keyboard_set_property;
 | 
			
		||||
@ -467,9 +455,10 @@ render_locked_button (GtkWidget *widget, struct button_place *place)
 | 
			
		||||
    cairo_region_destroy (region);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: does it really redraw the entire keyboard?
 | 
			
		||||
static void
 | 
			
		||||
render_released_button (GtkWidget *widget,
 | 
			
		||||
                        struct squeek_button *button)
 | 
			
		||||
                        const struct squeek_button *button)
 | 
			
		||||
{
 | 
			
		||||
    (void)button;
 | 
			
		||||
    EekGtkKeyboard        *self = EEK_GTK_KEYBOARD (widget);
 | 
			
		||||
@ -489,8 +478,8 @@ render_released_button (GtkWidget *widget,
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_button_pressed (struct squeek_button *button,
 | 
			
		||||
                struct squeek_view *view,
 | 
			
		||||
                EekGtkKeyboard *self)
 | 
			
		||||
                   struct squeek_view *view,
 | 
			
		||||
                   EekGtkKeyboard *self)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
@ -518,9 +507,9 @@ on_button_pressed (struct squeek_button *button,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_button_released (struct squeek_button *button,
 | 
			
		||||
                 struct squeek_view *view,
 | 
			
		||||
                 EekGtkKeyboard *self)
 | 
			
		||||
on_button_released (const struct squeek_button *button,
 | 
			
		||||
                    struct squeek_view *view,
 | 
			
		||||
                    EekGtkKeyboard *self)
 | 
			
		||||
{
 | 
			
		||||
    (void)view;
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
@ -34,7 +34,6 @@
 | 
			
		||||
#include "eekboard/key-emitter.h"
 | 
			
		||||
#include "keymap.h"
 | 
			
		||||
#include "src/keyboard.h"
 | 
			
		||||
#include "src/symbol.h"
 | 
			
		||||
 | 
			
		||||
#include "eek-keyboard.h"
 | 
			
		||||
 | 
			
		||||
@ -50,76 +49,52 @@ eek_modifier_key_free (EekModifierKey *modkey)
 | 
			
		||||
    g_slice_free (EekModifierKey, modkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Updates the state of locked keys based on the key that was activated
 | 
			
		||||
/// FIXME: make independent of what the key are named,
 | 
			
		||||
/// and instead refer to the contained symbols
 | 
			
		||||
static guint
 | 
			
		||||
set_key_states (LevelKeyboard    *keyboard,
 | 
			
		||||
                struct squeek_button *button,
 | 
			
		||||
                guint new_level)
 | 
			
		||||
void
 | 
			
		||||
eek_keyboard_set_key_locked (LevelKeyboard    *keyboard,
 | 
			
		||||
                            struct squeek_key *key)
 | 
			
		||||
{
 | 
			
		||||
    struct squeek_key *key = squeek_button_get_key(button);
 | 
			
		||||
    // Keys locking rules hardcoded for the time being...
 | 
			
		||||
    const gchar *name = squeek_symbol_get_name(squeek_key_get_symbol(key));
 | 
			
		||||
    // Lock the shift whenever it's pressed on the baselevel
 | 
			
		||||
    // TODO: need to lock shift on the destination level
 | 
			
		||||
    if (g_strcmp0(name, "Shift_L") == 0 && keyboard->level == 0) {
 | 
			
		||||
        EekModifierKey *modifier_key = g_slice_new (EekModifierKey);
 | 
			
		||||
        modifier_key->modifiers = 0;
 | 
			
		||||
        modifier_key->button = button;
 | 
			
		||||
        keyboard->locked_buttons =
 | 
			
		||||
            g_list_prepend (keyboard->locked_buttons, modifier_key);
 | 
			
		||||
        squeek_key_set_locked(key, true);
 | 
			
		||||
    }
 | 
			
		||||
    if (keyboard->level == 1) {
 | 
			
		||||
        // Only shift is locked in this state, unlock on any key press
 | 
			
		||||
        for (GList *head = keyboard->locked_buttons; head; ) {
 | 
			
		||||
            EekModifierKey *modifier_key = head->data;
 | 
			
		||||
            GList *next = g_list_next (head);
 | 
			
		||||
            keyboard->locked_buttons =
 | 
			
		||||
                g_list_remove_link (keyboard->locked_buttons, head);
 | 
			
		||||
            squeek_key_set_locked(squeek_button_get_key(modifier_key->button), false);
 | 
			
		||||
            g_list_free1 (head);
 | 
			
		||||
            head = next;
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    return new_level;
 | 
			
		||||
    EekModifierKey *modifier_key = g_slice_new (EekModifierKey);
 | 
			
		||||
    modifier_key->modifiers = 0;
 | 
			
		||||
    modifier_key->key = key;
 | 
			
		||||
    keyboard->locked_keys =
 | 
			
		||||
            g_list_prepend (keyboard->locked_keys, modifier_key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Unlock all locked keys.
 | 
			
		||||
/// All locked keys will unlock at the next keypress (should be called "stuck")
 | 
			
		||||
/// Returns the number of handled keys
 | 
			
		||||
/// TODO: may need to check key type in order to chain locks
 | 
			
		||||
/// before pressing an "emitting" key
 | 
			
		||||
static int unlock_keys(LevelKeyboard *keyboard) {
 | 
			
		||||
    int handled = 0;
 | 
			
		||||
    for (GList *head = keyboard->locked_keys; head; ) {
 | 
			
		||||
        EekModifierKey *modifier_key = head->data;
 | 
			
		||||
        GList *next = g_list_next (head);
 | 
			
		||||
        keyboard->locked_keys =
 | 
			
		||||
                g_list_remove_link (keyboard->locked_keys, head);
 | 
			
		||||
        //squeek_key_set_locked(squeek_button_get_key(modifier_key->button), false);
 | 
			
		||||
 | 
			
		||||
        squeek_layout_set_state_from_press(keyboard->layout, keyboard, modifier_key->key);
 | 
			
		||||
        g_list_free1 (head);
 | 
			
		||||
        head = next;
 | 
			
		||||
        handled++;
 | 
			
		||||
    }
 | 
			
		||||
    return handled;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FIXME: unhardcode, parse some user information as to which key triggers which view (level)
 | 
			
		||||
static void
 | 
			
		||||
set_level_from_press (LevelKeyboard *keyboard, struct squeek_button *button)
 | 
			
		||||
set_level_from_press (LevelKeyboard *keyboard, struct squeek_key *key)
 | 
			
		||||
{
 | 
			
		||||
    /* The levels are: 0 Letters, 1 Upper case letters, 2 Numbers, 3 Symbols */
 | 
			
		||||
    guint level = keyboard->level;
 | 
			
		||||
    /* Handle non-emitting keys */
 | 
			
		||||
    if (button) {
 | 
			
		||||
        const gchar *name = squeek_symbol_get_name(squeek_key_get_symbol(squeek_button_get_key(button)));
 | 
			
		||||
        if (g_strcmp0(name, "show_numbers") == 0) {
 | 
			
		||||
            level = 2;
 | 
			
		||||
        } else if (g_strcmp0(name, "show_letters") == 0) {
 | 
			
		||||
            level = 0;
 | 
			
		||||
        } else if (g_strcmp0(name, "show_symbols") == 0) {
 | 
			
		||||
            level = 3;
 | 
			
		||||
        } else if (g_strcmp0(name, "Shift_L") == 0) {
 | 
			
		||||
            level ^= 1;
 | 
			
		||||
        }
 | 
			
		||||
    // If the currently locked key was already handled in the unlock phase,
 | 
			
		||||
    // then skip
 | 
			
		||||
    if (unlock_keys(keyboard) == 0) {
 | 
			
		||||
        squeek_layout_set_state_from_press(keyboard->layout, keyboard, key);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    keyboard->level = set_key_states(keyboard, button, level);
 | 
			
		||||
 | 
			
		||||
    eek_layout_update_layout(keyboard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void eek_keyboard_press_button(LevelKeyboard *keyboard, struct squeek_button *button, guint32 timestamp) {
 | 
			
		||||
    struct squeek_key *key = squeek_button_get_key(button);
 | 
			
		||||
void eek_keyboard_press_key(LevelKeyboard *keyboard, struct squeek_key *key, guint32 timestamp) {
 | 
			
		||||
    squeek_key_set_pressed(key, TRUE);
 | 
			
		||||
    keyboard->pressed_buttons = g_list_prepend (keyboard->pressed_buttons, button);
 | 
			
		||||
 | 
			
		||||
    struct squeek_symbol *symbol = squeek_key_get_symbol(key);
 | 
			
		||||
    if (!symbol)
 | 
			
		||||
        return;
 | 
			
		||||
    keyboard->pressed_keys = g_list_prepend (keyboard->pressed_keys, key);
 | 
			
		||||
 | 
			
		||||
    // Only take action about setting level *after* the key has taken effect, i.e. on release
 | 
			
		||||
    //set_level_from_press (keyboard, key);
 | 
			
		||||
@ -131,43 +106,28 @@ void eek_keyboard_press_button(LevelKeyboard *keyboard, struct squeek_button *bu
 | 
			
		||||
    emit_key_activated(keyboard->manager, keyboard, keycode, TRUE, timestamp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void eek_keyboard_release_button(LevelKeyboard *keyboard,
 | 
			
		||||
                              struct squeek_button *button,
 | 
			
		||||
                               guint32      timestamp) {
 | 
			
		||||
    for (GList *head = keyboard->pressed_buttons; head; head = g_list_next (head)) {
 | 
			
		||||
        if (head->data == button) {
 | 
			
		||||
            keyboard->pressed_buttons = g_list_remove_link (keyboard->pressed_buttons, head);
 | 
			
		||||
void eek_keyboard_release_key(LevelKeyboard *keyboard,
 | 
			
		||||
                              struct squeek_key *key,
 | 
			
		||||
                              guint32 timestamp) {
 | 
			
		||||
    for (GList *head = keyboard->pressed_keys; head; head = g_list_next (head)) {
 | 
			
		||||
        if (squeek_key_equal(head->data, key)) {
 | 
			
		||||
            keyboard->pressed_keys = g_list_remove_link (keyboard->pressed_keys, head);
 | 
			
		||||
            g_list_free1 (head);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct squeek_symbol *symbol = squeek_button_get_symbol(button);
 | 
			
		||||
    if (!symbol)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    set_level_from_press (keyboard, button);
 | 
			
		||||
    set_level_from_press (keyboard, key);
 | 
			
		||||
 | 
			
		||||
    // "Borrowed" from eek-context-service; doesn't influence the state but forwards the event
 | 
			
		||||
 | 
			
		||||
    guint keycode = squeek_key_get_keycode (squeek_button_get_key(button));
 | 
			
		||||
    guint keycode = squeek_key_get_keycode (key);
 | 
			
		||||
 | 
			
		||||
    emit_key_activated(keyboard->manager, keyboard, keycode, FALSE, timestamp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void level_keyboard_deinit(LevelKeyboard *self) {
 | 
			
		||||
    g_hash_table_destroy (self->names);
 | 
			
		||||
    for (guint i = 0; i < self->outline_array->len; i++) {
 | 
			
		||||
        EekOutline *outline = &g_array_index (self->outline_array,
 | 
			
		||||
                                              EekOutline,
 | 
			
		||||
                                              i);
 | 
			
		||||
        g_slice_free1 (sizeof (EekPoint) * outline->num_points,
 | 
			
		||||
                       outline->points);
 | 
			
		||||
    }
 | 
			
		||||
    g_array_free (self->outline_array, TRUE);
 | 
			
		||||
    for (guint i = 0; i < 4; i++) {
 | 
			
		||||
        // free self->view[i];
 | 
			
		||||
    }
 | 
			
		||||
    squeek_layout_free(self->layout);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void level_keyboard_free(LevelKeyboard *self) {
 | 
			
		||||
@ -175,115 +135,18 @@ void level_keyboard_free(LevelKeyboard *self) {
 | 
			
		||||
    g_free(self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void level_keyboard_init(LevelKeyboard *self) {
 | 
			
		||||
    self->outline_array = g_array_new (FALSE, TRUE, sizeof (EekOutline));
 | 
			
		||||
void level_keyboard_init(LevelKeyboard *self, struct squeek_layout *layout) {
 | 
			
		||||
    self->layout = layout;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_view *views[4], GHashTable *name_button_hash) {
 | 
			
		||||
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_layout *layout) {
 | 
			
		||||
    LevelKeyboard *keyboard = g_new0(LevelKeyboard, 1);
 | 
			
		||||
    level_keyboard_init(keyboard);
 | 
			
		||||
    for (uint i = 0; i < 4; i++) {
 | 
			
		||||
        keyboard->views[i] = views[i];
 | 
			
		||||
    }
 | 
			
		||||
    level_keyboard_init(keyboard, layout);
 | 
			
		||||
    keyboard->manager = manager;
 | 
			
		||||
    keyboard->names = name_button_hash;
 | 
			
		||||
    return keyboard;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * eek_keyboard_find_key_by_name:
 | 
			
		||||
 * @keyboard: an #EekKeyboard
 | 
			
		||||
 * @name: a key name
 | 
			
		||||
 *
 | 
			
		||||
 * Find an #EekKey whose name is @name.
 | 
			
		||||
 * Return value: (transfer none): #EekKey whose name is @name
 | 
			
		||||
 */
 | 
			
		||||
struct squeek_button*
 | 
			
		||||
eek_keyboard_find_button_by_name (LevelKeyboard *keyboard,
 | 
			
		||||
                               const gchar *name)
 | 
			
		||||
{
 | 
			
		||||
    return g_hash_table_lookup (keyboard->names, name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * eek_keyboard_get_outline:
 | 
			
		||||
 * @keyboard: an #EekKeyboard
 | 
			
		||||
 * @oref: ID of the outline
 | 
			
		||||
 *
 | 
			
		||||
 * Get an outline associated with @oref in @keyboard.
 | 
			
		||||
 * Returns: an #EekOutline, which should not be released
 | 
			
		||||
 */
 | 
			
		||||
EekOutline *
 | 
			
		||||
level_keyboard_get_outline (LevelKeyboard *keyboard,
 | 
			
		||||
                          guint        oref)
 | 
			
		||||
{
 | 
			
		||||
    if (oref > keyboard->outline_array->len)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    return &g_array_index (keyboard->outline_array, EekOutline, oref);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * eek_keyboard_get_keymap:
 | 
			
		||||
 * @keyboard: an #EekKeyboard
 | 
			
		||||
 *
 | 
			
		||||
 * Get the keymap for the keyboard.
 | 
			
		||||
 * Returns: a string containing the XKB keymap.
 | 
			
		||||
 */
 | 
			
		||||
gchar *
 | 
			
		||||
eek_keyboard_get_keymap(LevelKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
    /* Start the keycodes and symbols sections with their respective headers. */
 | 
			
		||||
    gchar *keycodes = g_strdup(keymap_keycodes_header);
 | 
			
		||||
    gchar *symbols = g_strdup(keymap_symbols_header);
 | 
			
		||||
 | 
			
		||||
    /* Iterate over the keys in the name-to-key hash table. */
 | 
			
		||||
    GHashTableIter iter;
 | 
			
		||||
    gchar *button_name;
 | 
			
		||||
    gpointer button_ptr;
 | 
			
		||||
    g_hash_table_iter_init(&iter, keyboard->names);
 | 
			
		||||
 | 
			
		||||
    while (g_hash_table_iter_next(&iter, (gpointer)&button_name, &button_ptr)) {
 | 
			
		||||
 | 
			
		||||
        gchar *current, *line;
 | 
			
		||||
        struct squeek_button *button = button_ptr;
 | 
			
		||||
        struct squeek_key *key = squeek_button_get_key(button);
 | 
			
		||||
        guint keycode = squeek_key_get_keycode(key);
 | 
			
		||||
 | 
			
		||||
        /* Don't include invalid keycodes in the keymap. */
 | 
			
		||||
        if (keycode == EEK_INVALID_KEYCODE)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        /* Append a key name-to-keycode definition to the keycodes section. */
 | 
			
		||||
        current = keycodes;
 | 
			
		||||
        line = g_strdup_printf("        <%s> = %i;\n", (char *)button_name, keycode);
 | 
			
		||||
 | 
			
		||||
        keycodes = g_strconcat(current, line, NULL);
 | 
			
		||||
        g_free(line);
 | 
			
		||||
        g_free(current);
 | 
			
		||||
 | 
			
		||||
        // FIXME: free
 | 
			
		||||
        const char *key_str = squeek_key_to_keymap_entry(
 | 
			
		||||
            (char*)button_name,
 | 
			
		||||
            key
 | 
			
		||||
        );
 | 
			
		||||
        current = symbols;
 | 
			
		||||
        symbols = g_strconcat(current, key_str, NULL);
 | 
			
		||||
        g_free(current);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Assemble the keymap file from the header, sections and footer. */
 | 
			
		||||
    gchar *keymap = g_strconcat(keymap_header,
 | 
			
		||||
                                keycodes, "    };\n\n",
 | 
			
		||||
                                symbols, "    };\n\n",
 | 
			
		||||
                                keymap_footer, NULL);
 | 
			
		||||
 | 
			
		||||
    g_free(keycodes);
 | 
			
		||||
    g_free(symbols);
 | 
			
		||||
    return keymap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct squeek_view *level_keyboard_current(LevelKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
    return keyboard->views[keyboard->level];
 | 
			
		||||
    return squeek_layout_get_current_view(keyboard->layout);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -36,24 +36,19 @@ G_BEGIN_DECLS
 | 
			
		||||
struct _EekModifierKey {
 | 
			
		||||
    /*< public >*/
 | 
			
		||||
    EekModifierType modifiers;
 | 
			
		||||
    struct squeek_button *button;
 | 
			
		||||
    struct squeek_key *key;
 | 
			
		||||
};
 | 
			
		||||
typedef struct _EekModifierKey EekModifierKey;
 | 
			
		||||
 | 
			
		||||
/// Keyboard state holder
 | 
			
		||||
struct _LevelKeyboard {
 | 
			
		||||
    struct squeek_view *views[4];
 | 
			
		||||
    guint level;
 | 
			
		||||
    struct squeek_layout *layout;
 | 
			
		||||
    struct xkb_keymap *keymap;
 | 
			
		||||
    int keymap_fd; // keymap formatted as XKB string
 | 
			
		||||
    size_t keymap_len; // length of the data inside keymap_fd
 | 
			
		||||
    GArray *outline_array;
 | 
			
		||||
 | 
			
		||||
    GList *pressed_buttons; // struct squeek_button*
 | 
			
		||||
    GList *locked_buttons; // struct squeek_button*
 | 
			
		||||
 | 
			
		||||
    /* Map button names to button objects: */
 | 
			
		||||
    GHashTable *names;
 | 
			
		||||
    GList *pressed_keys; // struct squeek_key*
 | 
			
		||||
    GList *locked_keys; // struct EekModifierKey*
 | 
			
		||||
 | 
			
		||||
    guint id; // as a key to layout choices
 | 
			
		||||
 | 
			
		||||
@ -61,31 +56,25 @@ struct _LevelKeyboard {
 | 
			
		||||
};
 | 
			
		||||
typedef struct _LevelKeyboard LevelKeyboard;
 | 
			
		||||
 | 
			
		||||
struct squeek_button *eek_keyboard_find_button_by_name(LevelKeyboard *keyboard,
 | 
			
		||||
                                      const gchar        *name);
 | 
			
		||||
 | 
			
		||||
/// Represents the path to the button within a view
 | 
			
		||||
struct button_place {
 | 
			
		||||
    const struct squeek_row *row;
 | 
			
		||||
    const struct squeek_button *button;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
EekOutline         *level_keyboard_get_outline
 | 
			
		||||
                                     (LevelKeyboard        *keyboard,
 | 
			
		||||
                                      guint               oref);
 | 
			
		||||
EekModifierKey     *eek_modifier_key_copy
 | 
			
		||||
                                     (EekModifierKey     *modkey);
 | 
			
		||||
void                eek_modifier_key_free
 | 
			
		||||
                                     (EekModifierKey      *modkey);
 | 
			
		||||
 | 
			
		||||
void eek_keyboard_press_button(LevelKeyboard *keyboard, struct squeek_button *button, guint32 timestamp);
 | 
			
		||||
void eek_keyboard_release_button(LevelKeyboard *keyboard, struct squeek_button *button, guint32 timestamp);
 | 
			
		||||
void eek_keyboard_press_key(LevelKeyboard *keyboard, struct squeek_key *key, guint32 timestamp);
 | 
			
		||||
void eek_keyboard_release_key(LevelKeyboard *keyboard, struct squeek_key *key, guint32 timestamp);
 | 
			
		||||
 | 
			
		||||
gchar *             eek_keyboard_get_keymap
 | 
			
		||||
                                     (LevelKeyboard *keyboard);
 | 
			
		||||
 | 
			
		||||
struct squeek_view *level_keyboard_current(LevelKeyboard *keyboard);
 | 
			
		||||
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_view *views[], GHashTable *name_button_hash);
 | 
			
		||||
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_layout *layout);
 | 
			
		||||
void level_keyboard_deinit(LevelKeyboard *self);
 | 
			
		||||
void level_keyboard_free(LevelKeyboard *self);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,65 +0,0 @@
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
 | 
			
		||||
 * Copyright (C) 2010-2011 Red Hat, Inc.
 | 
			
		||||
 * 
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public License
 | 
			
		||||
 * as published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 * the License, or (at your option) any later version.
 | 
			
		||||
 * 
 | 
			
		||||
 * This library is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 * 
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SECTION:eek-keysym
 | 
			
		||||
 * @short_description: an #EekSymbol represents an X keysym
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "eek-keysym.h"
 | 
			
		||||
 | 
			
		||||
/* modifier keys */
 | 
			
		||||
#define EEK_KEYSYM_Shift_L 0xffe1
 | 
			
		||||
#define EEK_KEYSYM_Shift_R 0xffe2
 | 
			
		||||
#define EEK_KEYSYM_ISO_Level3_Shift 0xfe03
 | 
			
		||||
#define EEK_KEYSYM_Caps_Lock 0xffe5
 | 
			
		||||
#define EEK_KEYSYM_Shift_Lock 0xffe6
 | 
			
		||||
#define EEK_KEYSYM_Control_L 0xffe3
 | 
			
		||||
#define EEK_KEYSYM_Control_R 0xffe4
 | 
			
		||||
#define EEK_KEYSYM_Alt_L 0xffe9
 | 
			
		||||
#define EEK_KEYSYM_Alt_R 0xffea
 | 
			
		||||
#define EEK_KEYSYM_Meta_L 0xffe7
 | 
			
		||||
#define EEK_KEYSYM_Meta_R 0xffe8
 | 
			
		||||
#define EEK_KEYSYM_Super_L 0xffeb
 | 
			
		||||
#define EEK_KEYSYM_Super_R 0xffec
 | 
			
		||||
#define EEK_KEYSYM_Hyper_L 0xffed
 | 
			
		||||
#define EEK_KEYSYM_Hyper_R 0xffee
 | 
			
		||||
 | 
			
		||||
struct _EekKeysymEntry {
 | 
			
		||||
    guint xkeysym;
 | 
			
		||||
    const gchar *name;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct _EekKeysymEntry EekKeysymEntry;
 | 
			
		||||
 | 
			
		||||
#include "eek-xkeysym-keysym-entries.h"
 | 
			
		||||
 | 
			
		||||
guint32
 | 
			
		||||
eek_keysym_from_name (const gchar *name)
 | 
			
		||||
{
 | 
			
		||||
    for (uint i = 0; i < G_N_ELEMENTS(xkeysym_keysym_entries); i++) {
 | 
			
		||||
        if (g_strcmp0 (xkeysym_keysym_entries[i].name, name) == 0) {
 | 
			
		||||
            return xkeysym_keysym_entries[i].xkeysym;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
@ -1,32 +0,0 @@
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
 | 
			
		||||
 * Copyright (C) 2010-2011 Red Hat, Inc.
 | 
			
		||||
 * 
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public License
 | 
			
		||||
 * as published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 * the License, or (at your option) any later version.
 | 
			
		||||
 * 
 | 
			
		||||
 * This library is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 * 
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if !defined(__EEK_H_INSIDE__) && !defined(EEK_COMPILATION)
 | 
			
		||||
#error "Only <eek/eek.h> can be included directly."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef EEK_KEYSYM_H
 | 
			
		||||
#define EEK_KEYSYM_H 1
 | 
			
		||||
 | 
			
		||||
#include "glib.h"
 | 
			
		||||
 | 
			
		||||
guint32    eek_keysym_from_name         (const gchar    *name);
 | 
			
		||||
 | 
			
		||||
#endif  /* EEK_KEYSYM_H */
 | 
			
		||||
@ -45,9 +45,3 @@ void
 | 
			
		||||
eek_layout_init (EekLayout *self)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eek_layout_update_layout(LevelKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
    squeek_view_place_contents(level_keyboard_current(keyboard), keyboard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -56,14 +56,5 @@ struct _EekLayoutClass
 | 
			
		||||
 | 
			
		||||
GType        eek_layout_get_type  (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
void         eek_layout_place_rows(LevelKeyboard *keyboard, struct squeek_view *level);
 | 
			
		||||
 | 
			
		||||
void         eek_layout_update_layout(LevelKeyboard *keyboard);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
LevelKeyboard *
 | 
			
		||||
level_keyboard_from_layout (EekLayout *layout,
 | 
			
		||||
                  gdouble    initial_width,
 | 
			
		||||
                  gdouble    initial_height);
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
#endif  /* EEK_LAYOUT_H */
 | 
			
		||||
 | 
			
		||||
@ -24,8 +24,6 @@
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <gdk-pixbuf/gdk-pixbuf.h>
 | 
			
		||||
 | 
			
		||||
#include "src/symbol.h"
 | 
			
		||||
 | 
			
		||||
#include "eek-renderer.h"
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
@ -131,8 +129,7 @@ create_keyboard_surface_row_callback (struct squeek_row *row,
 | 
			
		||||
    cairo_rotate (data->cr, angle * G_PI / 180);
 | 
			
		||||
 | 
			
		||||
    data->row = row;
 | 
			
		||||
    squeek_row_foreach(row, create_keyboard_surface_button_callback,
 | 
			
		||||
                                 data);
 | 
			
		||||
    squeek_row_foreach(row, create_keyboard_surface_button_callback, data);
 | 
			
		||||
 | 
			
		||||
    cairo_restore (data->cr);
 | 
			
		||||
}
 | 
			
		||||
@ -175,8 +172,8 @@ render_keyboard_surface (EekRenderer *renderer, struct squeek_view *view)
 | 
			
		||||
 | 
			
		||||
    /* draw rows */
 | 
			
		||||
    squeek_view_foreach(level_keyboard_current(priv->keyboard),
 | 
			
		||||
                                 create_keyboard_surface_row_callback,
 | 
			
		||||
                                 &data);
 | 
			
		||||
                        create_keyboard_surface_row_callback,
 | 
			
		||||
                        &data);
 | 
			
		||||
    cairo_restore (data.cr);
 | 
			
		||||
 | 
			
		||||
    cairo_destroy (data.cr);
 | 
			
		||||
@ -189,14 +186,20 @@ render_button_outline (EekRenderer *renderer,
 | 
			
		||||
                    gboolean     active)
 | 
			
		||||
{
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
 | 
			
		||||
    EekOutline *outline;
 | 
			
		||||
 | 
			
		||||
    guint oref = squeek_button_get_oref(button);
 | 
			
		||||
    outline = level_keyboard_get_outline (priv->keyboard, oref);
 | 
			
		||||
    if (outline == NULL)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    EekBounds bounds = squeek_button_get_bounds(button);
 | 
			
		||||
 | 
			
		||||
    /* Set the name of the button on the widget path, using the name obtained
 | 
			
		||||
       from the button's symbol. */
 | 
			
		||||
    g_autoptr (GtkWidgetPath) path = NULL;
 | 
			
		||||
    path = gtk_widget_path_copy (gtk_style_context_get_path (priv->key_context));
 | 
			
		||||
    const char *name = squeek_button_get_name(button);
 | 
			
		||||
    gtk_widget_path_iter_set_name (path, -1, name);
 | 
			
		||||
 | 
			
		||||
    /* Update the style context with the updated widget path. */
 | 
			
		||||
    gtk_style_context_set_path (priv->key_context, path);
 | 
			
		||||
 | 
			
		||||
    /* Set the state to take into account whether the button is active
 | 
			
		||||
       (pressed) or normal. */
 | 
			
		||||
    gtk_style_context_set_state(priv->key_context,
 | 
			
		||||
        active ? GTK_STATE_FLAG_ACTIVE : GTK_STATE_FLAG_NORMAL);
 | 
			
		||||
 | 
			
		||||
@ -215,18 +218,12 @@ render_button (EekRenderer *self,
 | 
			
		||||
            gboolean     active)
 | 
			
		||||
{
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
 | 
			
		||||
    EekOutline *outline;
 | 
			
		||||
    cairo_surface_t *outline_surface;
 | 
			
		||||
    GHashTable *outline_surface_cache;
 | 
			
		||||
    PangoLayout *layout;
 | 
			
		||||
    PangoRectangle extents = { 0, };
 | 
			
		||||
    EekColor foreground;
 | 
			
		||||
 | 
			
		||||
    guint oref = squeek_button_get_oref (place->button);
 | 
			
		||||
    outline = level_keyboard_get_outline (priv->keyboard, oref);
 | 
			
		||||
    if (outline == NULL)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    /* render outline */
 | 
			
		||||
    EekBounds bounds = squeek_button_get_bounds(place->button);
 | 
			
		||||
 | 
			
		||||
@ -235,7 +232,7 @@ render_button (EekRenderer *self,
 | 
			
		||||
    else
 | 
			
		||||
        outline_surface_cache = priv->outline_surface_cache;
 | 
			
		||||
 | 
			
		||||
    outline_surface = g_hash_table_lookup (outline_surface_cache, outline);
 | 
			
		||||
    outline_surface = g_hash_table_lookup (outline_surface_cache, place->button);
 | 
			
		||||
    if (!outline_surface) {
 | 
			
		||||
        cairo_t *cr;
 | 
			
		||||
 | 
			
		||||
@ -259,7 +256,7 @@ render_button (EekRenderer *self,
 | 
			
		||||
        cairo_destroy (cr);
 | 
			
		||||
 | 
			
		||||
        g_hash_table_insert (outline_surface_cache,
 | 
			
		||||
                             outline,
 | 
			
		||||
                             (gpointer)place->button,
 | 
			
		||||
                             outline_surface);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -268,16 +265,12 @@ render_button (EekRenderer *self,
 | 
			
		||||
 | 
			
		||||
    eek_renderer_get_foreground_color (self, priv->key_context, &foreground);
 | 
			
		||||
    /* render icon (if any) */
 | 
			
		||||
    struct squeek_symbol *symbol = squeek_button_get_symbol(place->button);
 | 
			
		||||
    if (!symbol)
 | 
			
		||||
        return;
 | 
			
		||||
    const char *icon_name = squeek_button_get_icon_name(place->button);
 | 
			
		||||
 | 
			
		||||
    if (squeek_symbol_get_icon_name (symbol)) {
 | 
			
		||||
    if (icon_name) {
 | 
			
		||||
        gint scale = priv->scale_factor;
 | 
			
		||||
        cairo_surface_t *icon_surface =
 | 
			
		||||
            eek_renderer_get_icon_surface (self,
 | 
			
		||||
                                           squeek_symbol_get_icon_name (symbol),
 | 
			
		||||
                                           16 / priv->scale,
 | 
			
		||||
            eek_renderer_get_icon_surface (self, icon_name, 16 / priv->scale,
 | 
			
		||||
                                           scale);
 | 
			
		||||
        if (icon_surface) {
 | 
			
		||||
            gint width = cairo_image_surface_get_width (icon_surface);
 | 
			
		||||
@ -372,18 +365,16 @@ eek_renderer_real_render_button_label (EekRenderer *self,
 | 
			
		||||
{
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
    const gchar *label;
 | 
			
		||||
    const gchar *label = squeek_button_get_label(button);
 | 
			
		||||
 | 
			
		||||
    if (!label) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    PangoFontDescription *font;
 | 
			
		||||
    PangoLayoutLine *line;
 | 
			
		||||
    gdouble scale;
 | 
			
		||||
 | 
			
		||||
    struct squeek_symbol *symbol = squeek_button_get_symbol(button);
 | 
			
		||||
    if (!symbol)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    label = squeek_symbol_get_label (symbol);
 | 
			
		||||
    if (!label)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (!priv->font) {
 | 
			
		||||
        const PangoFontDescription *base_font;
 | 
			
		||||
@ -481,7 +472,7 @@ eek_renderer_real_render_keyboard (EekRenderer *self,
 | 
			
		||||
        cairo_get_target (cr), 0, 0,
 | 
			
		||||
        priv->allocation_width, priv->allocation_height);
 | 
			
		||||
 | 
			
		||||
    render_keyboard_surface (self, priv->keyboard->views[priv->keyboard->level]);
 | 
			
		||||
    render_keyboard_surface (self, squeek_layout_get_current_view(priv->keyboard->layout));
 | 
			
		||||
 | 
			
		||||
    cairo_set_source_surface (cr, priv->keyboard_surface, 0.0, 0.0);
 | 
			
		||||
    source = cairo_get_source (cr);
 | 
			
		||||
@ -971,14 +962,15 @@ eek_are_bounds_inside (EekBounds bounds, EekPoint point, EekPoint origin, int32_
 | 
			
		||||
 **/
 | 
			
		||||
struct squeek_button *
 | 
			
		||||
eek_renderer_find_button_by_position (EekRenderer *renderer,
 | 
			
		||||
                                   struct squeek_view *view,
 | 
			
		||||
                                   gdouble      x,
 | 
			
		||||
                                   gdouble      y)
 | 
			
		||||
                                      struct squeek_view *view,
 | 
			
		||||
                                      gdouble      x,
 | 
			
		||||
                                      gdouble      y)
 | 
			
		||||
{
 | 
			
		||||
    g_return_val_if_fail (EEK_IS_RENDERER(renderer), NULL);
 | 
			
		||||
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
 | 
			
		||||
 | 
			
		||||
    /* Transform from widget coordinates to keyboard coordinates */
 | 
			
		||||
    EekPoint point = {
 | 
			
		||||
        .x = (x - priv->origin_x)/priv->scale,
 | 
			
		||||
        .y = (y - priv->origin_y)/priv->scale,
 | 
			
		||||
 | 
			
		||||
@ -1,56 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
 | 
			
		||||
 * Copyright (C) 2010-2011 Red Hat, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public License
 | 
			
		||||
 * as published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 * the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "eek-section.h"
 | 
			
		||||
 | 
			
		||||
EekBounds eek_get_outline_size(LevelKeyboard *keyboard, uint32_t oref) {
 | 
			
		||||
    EekOutline *outline = level_keyboard_get_outline (keyboard, oref);
 | 
			
		||||
    if (outline && outline->num_points > 0) {
 | 
			
		||||
        double minx = outline->points[0].x;
 | 
			
		||||
        double maxx = minx;
 | 
			
		||||
        double miny = outline->points[0].y;
 | 
			
		||||
        double maxy = miny;
 | 
			
		||||
        for (uint i = 1; i < outline->num_points; i++) {
 | 
			
		||||
            EekPoint p = outline->points[i];
 | 
			
		||||
            if (p.x < minx) {
 | 
			
		||||
                minx = p.x;
 | 
			
		||||
            } else if (p.x > maxx) {
 | 
			
		||||
                maxx = p.x;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (p.y < miny) {
 | 
			
		||||
                miny = p.y;
 | 
			
		||||
            } else if (p.y > maxy) {
 | 
			
		||||
                maxy = p.y;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        EekBounds key_bounds = {
 | 
			
		||||
            .height = maxy - miny,
 | 
			
		||||
            .width = maxx - minx,
 | 
			
		||||
            .x = 0,
 | 
			
		||||
            .y = 0,
 | 
			
		||||
        };
 | 
			
		||||
        return key_bounds;
 | 
			
		||||
    }
 | 
			
		||||
    EekBounds bounds = {0, 0, 0, 0};
 | 
			
		||||
    return bounds;
 | 
			
		||||
}
 | 
			
		||||
@ -1,34 +0,0 @@
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
 | 
			
		||||
 * Copyright (C) 2010-2011 Red Hat, Inc.
 | 
			
		||||
 * 
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public License
 | 
			
		||||
 * as published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 * the License, or (at your option) any later version.
 | 
			
		||||
 * 
 | 
			
		||||
 * This library is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 * 
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if !defined(__EEK_H_INSIDE__) && !defined(EEK_COMPILATION)
 | 
			
		||||
#error "Only <eek/eek.h> can be included directly."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef EEK_SECTION_H
 | 
			
		||||
#define EEK_SECTION_H 1
 | 
			
		||||
 | 
			
		||||
/* Contains row-related functions that couldn't be done in Rust easily. */
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
#include "eek-keyboard.h"
 | 
			
		||||
#include "src/layout.h"
 | 
			
		||||
 | 
			
		||||
#endif  /* EEK_SECTION_H */
 | 
			
		||||
							
								
								
									
										1399
									
								
								eek/eek-xml-layout.c
									
									
									
									
									
								
							
							
						
						
									
										1399
									
								
								eek/eek-xml-layout.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -23,47 +23,11 @@
 | 
			
		||||
#ifndef EEK_XML_LAYOUT_H
 | 
			
		||||
#define EEK_XML_LAYOUT_H 1
 | 
			
		||||
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
#include "eek-layout.h"
 | 
			
		||||
#include "eek-types.h"
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define EEK_TYPE_XML_LAYOUT (eek_xml_layout_get_type())
 | 
			
		||||
G_DECLARE_DERIVABLE_TYPE (EekXmlLayout, eek_xml_layout, EEK, XML_LAYOUT, EekLayout)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * EekXmlLayoutClass:
 | 
			
		||||
 */
 | 
			
		||||
struct _EekXmlLayoutClass
 | 
			
		||||
{
 | 
			
		||||
    /*< private >*/
 | 
			
		||||
    EekLayoutClass parent_class;
 | 
			
		||||
 | 
			
		||||
    /* padding */
 | 
			
		||||
    gpointer pdummy[24];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _EekXmlKeyboardDesc
 | 
			
		||||
{
 | 
			
		||||
    gchar *id;
 | 
			
		||||
    gchar *name;
 | 
			
		||||
    gchar *geometry;
 | 
			
		||||
    gchar *symbols;
 | 
			
		||||
    gchar *language;
 | 
			
		||||
    gchar *longname;
 | 
			
		||||
};
 | 
			
		||||
typedef struct _EekXmlKeyboardDesc EekXmlKeyboardDesc;
 | 
			
		||||
 | 
			
		||||
GType               eek_xml_layout_get_type    (void) G_GNUC_CONST;
 | 
			
		||||
EekLayout          *eek_xml_layout_new         (const gchar        *id,
 | 
			
		||||
                                                GError            **error);
 | 
			
		||||
GList              *eek_xml_list_keyboards     (void);
 | 
			
		||||
 | 
			
		||||
EekXmlKeyboardDesc *eek_xml_keyboard_desc_copy (EekXmlKeyboardDesc *desc);
 | 
			
		||||
void                eek_xml_keyboard_desc_free (EekXmlKeyboardDesc *desc);
 | 
			
		||||
 | 
			
		||||
LevelKeyboard *
 | 
			
		||||
eek_xml_layout_real_create_keyboard (EekLayout *self,
 | 
			
		||||
eek_xml_layout_real_create_keyboard (const char *keyboard_type,
 | 
			
		||||
                                     EekboardContextService *manager);
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
#endif  /* EEK_XML_LAYOUT_H */
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,6 @@
 | 
			
		||||
 | 
			
		||||
#include "eek-keyboard.h"
 | 
			
		||||
#include "eek-layout.h"
 | 
			
		||||
#include "eek-keysym.h"
 | 
			
		||||
 | 
			
		||||
void eek_init (void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,50 +0,0 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
# Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
 | 
			
		||||
# Copyright (C) 2010-2011 Red Hat, Inc.
 | 
			
		||||
# Copyright (C) 2019      Purism, SPC
 | 
			
		||||
 | 
			
		||||
# This library is free software; you can redistribute it and/or
 | 
			
		||||
# modify it under the terms of the GNU Lesser General Public License
 | 
			
		||||
# as published by the Free Software Foundation; either version 2 of
 | 
			
		||||
# the License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
# This library is distributed in the hope that it will be useful, but
 | 
			
		||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
# Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
# You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
# License along with this library; if not, write to the Free Software
 | 
			
		||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
			
		||||
# 02110-1301 USA
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
if len(sys.argv) > 3:
 | 
			
		||||
    print("Usage: %s TABLE-NAME [INPUT_FILE]" % sys.argv[0], file=sys.stderr)
 | 
			
		||||
    sys.exit(-1)
 | 
			
		||||
 | 
			
		||||
if len(sys.argv) < 3:
 | 
			
		||||
    in_stream = sys.stdin
 | 
			
		||||
else:
 | 
			
		||||
    in_stream = open(sys.argv[2])
 | 
			
		||||
 | 
			
		||||
table = dict()
 | 
			
		||||
for line in in_stream:
 | 
			
		||||
    match = re.match(r'\s*(0x[0-9A-F]+)\s+"(.*)"\s+(\S*)', line, re.I)
 | 
			
		||||
    if match:
 | 
			
		||||
        table[int(match.group(1), 16)] = (match.group(2), match.group(3))
 | 
			
		||||
 | 
			
		||||
sys.stdout.write("static const EekKeysymEntry %s[] = {\n" %
 | 
			
		||||
                 sys.argv[1])
 | 
			
		||||
 | 
			
		||||
for index, (keysym, (l, c)) in enumerate([(keysym, table[keysym])
 | 
			
		||||
                                          for keysym in sorted(table.keys())]):
 | 
			
		||||
    sys.stdout.write("    { 0x%X, \"%s\" }" %
 | 
			
		||||
                     (keysym, l))
 | 
			
		||||
    if index < len(table) - 1:
 | 
			
		||||
        sys.stdout.write(",")
 | 
			
		||||
    sys.stdout.write("\n")
 | 
			
		||||
sys.stdout.write("};\n")
 | 
			
		||||
							
								
								
									
										31
									
								
								eek/keymap.h
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								eek/keymap.h
									
									
									
									
									
								
							@ -6,34 +6,3 @@ squeek_keymap_get_entries_for_keyval (struct xkb_keymap     *xkb_keymap,
 | 
			
		||||
                                      guint          keyval,
 | 
			
		||||
                                      GdkKeymapKey **keys,
 | 
			
		||||
                                      guint          *n_keys);
 | 
			
		||||
 | 
			
		||||
static const char *keymap_header = "xkb_keymap {\n\
 | 
			
		||||
\n";
 | 
			
		||||
 | 
			
		||||
static const char *keymap_keycodes_header = "\
 | 
			
		||||
    xkb_keycodes \"squeekboard\" {\n\n\
 | 
			
		||||
        minimum = 8;\n\
 | 
			
		||||
        maximum = 255;\n\
 | 
			
		||||
\n";
 | 
			
		||||
 | 
			
		||||
static const char *keymap_symbols_header = "\
 | 
			
		||||
    xkb_symbols \"squeekboard\" {\n\
 | 
			
		||||
\n\
 | 
			
		||||
        name[Group1] = \"Letters\";\n\
 | 
			
		||||
        name[Group2] = \"Numbers/Symbols\";\n\
 | 
			
		||||
\n";
 | 
			
		||||
 | 
			
		||||
static const char *keymap_footer = "\
 | 
			
		||||
    xkb_types \"squeekboard\" {\n\
 | 
			
		||||
\n\
 | 
			
		||||
	type \"TWO_LEVEL\" {\n\
 | 
			
		||||
            modifiers = Shift;\n\
 | 
			
		||||
            map[Shift] = Level2;\n\
 | 
			
		||||
            level_name[Level1] = \"Base\";\n\
 | 
			
		||||
            level_name[Level2] = \"Shift\";\n\
 | 
			
		||||
	};\n\
 | 
			
		||||
    };\n\
 | 
			
		||||
\n\
 | 
			
		||||
    xkb_compatibility \"squeekboard\" {\n\
 | 
			
		||||
    };\n\
 | 
			
		||||
};";
 | 
			
		||||
 | 
			
		||||
@ -6,15 +6,3 @@ enum_headers = [
 | 
			
		||||
 | 
			
		||||
enums = gnome.mkenums_simple('eek-enumtypes', sources: enum_headers)
 | 
			
		||||
 | 
			
		||||
python = find_program('python3')
 | 
			
		||||
 | 
			
		||||
gen_keysym_entries_xkeysym = generator(
 | 
			
		||||
  python,
 | 
			
		||||
  arguments: ['@CURRENT_SOURCE_DIR@/gen-keysym-entries.py', 'xkeysym_keysym_entries', '@INPUT@'],
 | 
			
		||||
  capture: true,
 | 
			
		||||
  output: 'eek-@BASENAME@.h',
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
keysym_entries = [
 | 
			
		||||
  gen_keysym_entries_xkeysym.process('./xkeysym-keysym-entries.txt'),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -29,6 +29,7 @@
 | 
			
		||||
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#define _XOPEN_SOURCE 500
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <sys/random.h> // TODO: this is Linux-specific
 | 
			
		||||
@ -89,66 +90,17 @@ static LevelKeyboard *
 | 
			
		||||
eekboard_context_service_real_create_keyboard (EekboardContextService *self,
 | 
			
		||||
                                               const gchar            *keyboard_type)
 | 
			
		||||
{
 | 
			
		||||
    EekLayout *layout;
 | 
			
		||||
    GError *error;
 | 
			
		||||
 | 
			
		||||
    if (g_str_has_prefix (keyboard_type, "xkb:")) {
 | 
			
		||||
        /* TODO: Depends on xklavier
 | 
			
		||||
        XklConfigRec *rec =
 | 
			
		||||
            eekboard_xkl_config_rec_from_string (&keyboard_type[4]);
 | 
			
		||||
 | 
			
		||||
        if (display == NULL)
 | 
			
		||||
            //display = XOpenDisplay (NULL);
 | 
			
		||||
            return NULL; // FIXME: replace with wl display
 | 
			
		||||
 | 
			
		||||
        error = NULL;
 | 
			
		||||
        layout = eek_xkl_layout_new (display, &error);
 | 
			
		||||
        if (layout == NULL) {
 | 
			
		||||
            g_warning ("can't create keyboard %s: %s",
 | 
			
		||||
                       keyboard_type, error->message);
 | 
			
		||||
            g_error_free (error);
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!eek_xkl_layout_set_config (EEK_XKL_LAYOUT(layout), rec)) {
 | 
			
		||||
            g_object_unref (layout);
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
        */
 | 
			
		||||
        return NULL;
 | 
			
		||||
    } else {
 | 
			
		||||
        error = NULL;
 | 
			
		||||
        layout = eek_xml_layout_new (keyboard_type, &error);
 | 
			
		||||
        if (layout == NULL) {
 | 
			
		||||
            g_warning ("can't create keyboard %s: %s",
 | 
			
		||||
                       keyboard_type, error->message);
 | 
			
		||||
            g_error_free (error);
 | 
			
		||||
            keyboard_type = "us";
 | 
			
		||||
            error = NULL;
 | 
			
		||||
            layout = eek_xml_layout_new (keyboard_type, &error);
 | 
			
		||||
            if (layout == NULL) {
 | 
			
		||||
                g_error ("failed to create fallback layout: %s", error->message);
 | 
			
		||||
                g_error_free (error);
 | 
			
		||||
                return NULL;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    LevelKeyboard *keyboard = eek_xml_layout_real_create_keyboard(layout, self);
 | 
			
		||||
    LevelKeyboard *keyboard = eek_xml_layout_real_create_keyboard(keyboard_type, self);
 | 
			
		||||
    if (!keyboard) {
 | 
			
		||||
        g_error("Failed to create a keyboard");
 | 
			
		||||
    }
 | 
			
		||||
    g_object_unref (layout);
 | 
			
		||||
 | 
			
		||||
    struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
 | 
			
		||||
    if (!context) {
 | 
			
		||||
        g_error("No context created");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    gchar *keymap_str = eek_keyboard_get_keymap(keyboard);
 | 
			
		||||
 | 
			
		||||
    int f = open("maprs.map", O_CREAT | O_WRONLY, 0600);
 | 
			
		||||
    write(f, keymap_str, strlen(keymap_str));
 | 
			
		||||
    close(f);
 | 
			
		||||
    const gchar *keymap_str = squeek_layout_get_keymap(keyboard->layout);
 | 
			
		||||
 | 
			
		||||
    struct xkb_keymap *keymap = xkb_keymap_new_from_string(context, keymap_str,
 | 
			
		||||
        XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
 | 
			
		||||
@ -156,8 +108,6 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self,
 | 
			
		||||
    if (!keymap)
 | 
			
		||||
        g_error("Bad keymap:\n%s", keymap_str);
 | 
			
		||||
 | 
			
		||||
    free(keymap_str);
 | 
			
		||||
 | 
			
		||||
    xkb_context_unref(context);
 | 
			
		||||
    keyboard->keymap = keymap;
 | 
			
		||||
 | 
			
		||||
@ -167,7 +117,7 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self,
 | 
			
		||||
    g_autofree char *path = strdup("/eek_keymap-XXXXXX");
 | 
			
		||||
    char *r = &path[strlen(path) - 6];
 | 
			
		||||
    getrandom(r, 6, GRND_NONBLOCK);
 | 
			
		||||
    for (uint i = 0; i < 6; i++) {
 | 
			
		||||
    for (unsigned i = 0; i < 6; i++) {
 | 
			
		||||
        r[i] = (r[i] & 0b1111111) | 0b1000000; // A-z
 | 
			
		||||
        r[i] = r[i] > 'z' ? '?' : r[i]; // The randomizer doesn't need to be good...
 | 
			
		||||
    }
 | 
			
		||||
@ -185,9 +135,8 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self,
 | 
			
		||||
    if ((void*)ptr == (void*)-1) {
 | 
			
		||||
        g_error("Failed to set up mmap");
 | 
			
		||||
    }
 | 
			
		||||
    strcpy(ptr, keymap_str);
 | 
			
		||||
    strncpy(ptr, keymap_str, keyboard->keymap_len);
 | 
			
		||||
    munmap(ptr, keyboard->keymap_len);
 | 
			
		||||
    free(keymap_str);
 | 
			
		||||
 | 
			
		||||
    return keyboard;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -90,12 +90,9 @@ send_fake_key (SeatEmitter *emitter,
 | 
			
		||||
               gboolean pressed,
 | 
			
		||||
               uint32_t timestamp)
 | 
			
		||||
{
 | 
			
		||||
    guint level = keyboard->level;
 | 
			
		||||
    uint32_t group = (level / 2);
 | 
			
		||||
 | 
			
		||||
    zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, group);
 | 
			
		||||
    zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, 0);
 | 
			
		||||
    send_virtual_keyboard_key (emitter->virtual_keyboard, keycode - 8, (unsigned)pressed, timestamp);
 | 
			
		||||
    zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, group);
 | 
			
		||||
    zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										29
									
								
								examples/test_layout.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								examples/test_layout.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
extern crate rs;
 | 
			
		||||
extern crate xkbcommon;
 | 
			
		||||
 | 
			
		||||
use std::env;
 | 
			
		||||
 | 
			
		||||
use rs::data::{ load_layout_from_resource, LoadError };
 | 
			
		||||
 | 
			
		||||
use xkbcommon::xkb;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
fn check_layout(name: &str) {
 | 
			
		||||
    let layout = load_layout_from_resource(name)
 | 
			
		||||
        .and_then(|layout| layout.build().map_err(LoadError::BadKeyMap))
 | 
			
		||||
        .expect("layout broken");
 | 
			
		||||
    
 | 
			
		||||
    let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
 | 
			
		||||
    xkb::Keymap::new_from_string(
 | 
			
		||||
        &context,
 | 
			
		||||
        layout.keymap_str
 | 
			
		||||
            .clone()
 | 
			
		||||
            .into_string().expect("Failed to decode keymap string"),
 | 
			
		||||
        xkb::KEYMAP_FORMAT_TEXT_V1,
 | 
			
		||||
        xkb::KEYMAP_COMPILE_NO_FLAGS,
 | 
			
		||||
    ).expect("Failed to create keymap");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() -> () {
 | 
			
		||||
    check_layout(env::args().nth(1).expect("No argument given").as_str());
 | 
			
		||||
}
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
project(
 | 
			
		||||
    'squeekboard',
 | 
			
		||||
    'c', 'rust',
 | 
			
		||||
    version: '1.0.10',
 | 
			
		||||
    version: '1.2.0',
 | 
			
		||||
    license: 'GPLv3',
 | 
			
		||||
    meson_version: '>=0.49.0',
 | 
			
		||||
    meson_version: '>=0.51.0',
 | 
			
		||||
    default_options: [
 | 
			
		||||
        'warning_level=1',
 | 
			
		||||
        'buildtype=debugoptimized',
 | 
			
		||||
@ -53,6 +53,9 @@ summary = [
 | 
			
		||||
]
 | 
			
		||||
message('\n'.join(summary))
 | 
			
		||||
 | 
			
		||||
cargo = find_program('cargo')
 | 
			
		||||
cargo_script = find_program('cargo.sh')
 | 
			
		||||
 | 
			
		||||
subdir('data')
 | 
			
		||||
subdir('protocols')
 | 
			
		||||
subdir('eek')
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1350
									
								
								src/bitflags.rs
									
									
									
									
									
								
							
							
						
						
									
										1350
									
								
								src/bitflags.rs
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										640
									
								
								src/data.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										640
									
								
								src/data.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,640 @@
 | 
			
		||||
/**! The parsing of the data files for layouts */
 | 
			
		||||
 | 
			
		||||
use std::cell::RefCell;
 | 
			
		||||
use std::collections::{ HashMap, HashSet };
 | 
			
		||||
use std::env;
 | 
			
		||||
use std::ffi::CString;
 | 
			
		||||
use std::fmt;
 | 
			
		||||
use std::fs;
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::path::PathBuf;
 | 
			
		||||
use std::rc::Rc;
 | 
			
		||||
use std::vec::Vec;
 | 
			
		||||
 | 
			
		||||
use xkbcommon::xkb;
 | 
			
		||||
 | 
			
		||||
use ::keyboard::{
 | 
			
		||||
    KeyState,
 | 
			
		||||
    generate_keymap, generate_keycodes, FormattingError
 | 
			
		||||
};
 | 
			
		||||
use ::resources;
 | 
			
		||||
use ::util::c::as_str;
 | 
			
		||||
use ::xdg;
 | 
			
		||||
 | 
			
		||||
// traits, derives
 | 
			
		||||
use std::io::BufReader;
 | 
			
		||||
use std::iter::FromIterator;
 | 
			
		||||
 | 
			
		||||
use serde::Deserialize;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// Gathers stuff defined in C or called by C
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use std::os::raw::c_char;
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_load_layout(name: *const c_char) -> *mut ::layout::Layout {
 | 
			
		||||
        let name = as_str(&name)
 | 
			
		||||
            .expect("Bad layout name")
 | 
			
		||||
            .expect("Empty layout name");
 | 
			
		||||
 | 
			
		||||
        let layout = load_layout_with_fallback(name);
 | 
			
		||||
        Box::into_raw(Box::new(layout))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const FALLBACK_LAYOUT_NAME: &str = "us";
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum LoadError {
 | 
			
		||||
    BadData(Error),
 | 
			
		||||
    MissingResource,
 | 
			
		||||
    BadResource(serde_yaml::Error),
 | 
			
		||||
    BadKeyMap(FormattingError),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for LoadError {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        use self::LoadError::*;
 | 
			
		||||
        match self {
 | 
			
		||||
            BadData(e) => write!(f, "Bad data: {}", e),
 | 
			
		||||
            MissingResource => write!(f, "Missing resource"),
 | 
			
		||||
            BadResource(e) => write!(f, "Bad resource: {}", e),
 | 
			
		||||
            BadKeyMap(e) => write!(f, "Bad key map: {}", e),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn load_layout_from_resource(
 | 
			
		||||
    name: &str
 | 
			
		||||
) -> Result<Layout, LoadError> {
 | 
			
		||||
    let data = resources::get_keyboard(name)
 | 
			
		||||
                .ok_or(LoadError::MissingResource)?;
 | 
			
		||||
    serde_yaml::from_str(data)
 | 
			
		||||
                .map_err(|e| LoadError::BadResource(e))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum DataSource {
 | 
			
		||||
    File(PathBuf),
 | 
			
		||||
    Resource(String),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for DataSource {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            DataSource::File(path) => write!(f, "Path: {:?}", path.display()),
 | 
			
		||||
            DataSource::Resource(name) => write!(f, "Resource: {}", name),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Tries to load the layout from the first place where it's present.
 | 
			
		||||
/// If the layout exists, but is broken, fallback is activated.
 | 
			
		||||
fn load_layout(
 | 
			
		||||
    name: &str
 | 
			
		||||
) -> (Result<::layout::Layout, LoadError>, DataSource) {
 | 
			
		||||
    let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR")
 | 
			
		||||
        .map(PathBuf::from)
 | 
			
		||||
        .or_else(|| xdg::data_path("squeekboard/keyboards"))
 | 
			
		||||
        .map(|path| path.join(name).with_extension("yaml"));
 | 
			
		||||
 | 
			
		||||
    let (layout, source) = match path {
 | 
			
		||||
        Some(path) => {(
 | 
			
		||||
            Layout::from_yaml_stream(path.clone())
 | 
			
		||||
                .map_err(|e| LoadError::BadData(e)),
 | 
			
		||||
            DataSource::File(path)
 | 
			
		||||
        )},
 | 
			
		||||
        None => {(
 | 
			
		||||
            load_layout_from_resource(name),
 | 
			
		||||
            DataSource::Resource(name.into())
 | 
			
		||||
        )},
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    let layout = layout.and_then(
 | 
			
		||||
        |layout| layout.build().map_err(LoadError::BadKeyMap)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    (layout, source)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn load_layout_with_fallback(
 | 
			
		||||
    name: &str
 | 
			
		||||
) -> ::layout::Layout {
 | 
			
		||||
    let (layout, source) = load_layout(name);
 | 
			
		||||
    let (layout, source) = match (layout, source) {
 | 
			
		||||
        (Err(e), source) => {
 | 
			
		||||
            eprintln!(
 | 
			
		||||
                "Failed to load layout from {}: {}, using fallback",
 | 
			
		||||
                source, e
 | 
			
		||||
            );
 | 
			
		||||
            load_layout(FALLBACK_LAYOUT_NAME)
 | 
			
		||||
        },
 | 
			
		||||
        res => res,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let (layout, source) = match (layout, source) {
 | 
			
		||||
        (Err(e), source) => {
 | 
			
		||||
            eprintln!(
 | 
			
		||||
                "Failed to load fallback layout from {}: {}, using hardcoded",
 | 
			
		||||
                source, e
 | 
			
		||||
            );
 | 
			
		||||
            (
 | 
			
		||||
                load_layout_from_resource(FALLBACK_LAYOUT_NAME)
 | 
			
		||||
                    .and_then(
 | 
			
		||||
                        |layout| layout.build().map_err(LoadError::BadKeyMap)
 | 
			
		||||
                    ),
 | 
			
		||||
                DataSource::Resource(FALLBACK_LAYOUT_NAME.into()),
 | 
			
		||||
            )
 | 
			
		||||
        },
 | 
			
		||||
        res => res,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    match (layout, source) {
 | 
			
		||||
        (Err(e), source) => {
 | 
			
		||||
            panic!(
 | 
			
		||||
                format!("Failed to load hardcoded layout from {}: {:?}",
 | 
			
		||||
                    source, e
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
        },
 | 
			
		||||
        (Ok(layout), source) => {
 | 
			
		||||
            eprintln!("Loaded layout from {}", source);
 | 
			
		||||
            layout
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// The root element describing an entire keyboard
 | 
			
		||||
#[derive(Debug, Deserialize, PartialEq)]
 | 
			
		||||
#[serde(deny_unknown_fields)]
 | 
			
		||||
pub struct Layout {
 | 
			
		||||
    bounds: Bounds,
 | 
			
		||||
    views: HashMap<String, Vec<ButtonIds>>,
 | 
			
		||||
    #[serde(default)] 
 | 
			
		||||
    buttons: HashMap<String, ButtonMeta>,
 | 
			
		||||
    outlines: HashMap<String, Outline>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
 | 
			
		||||
#[serde(deny_unknown_fields)]
 | 
			
		||||
struct Bounds {
 | 
			
		||||
    x: f64,
 | 
			
		||||
    y: f64,
 | 
			
		||||
    width: f64,
 | 
			
		||||
    height: f64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Buttons are embedded in a single string
 | 
			
		||||
type ButtonIds = String;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Default, Deserialize, PartialEq)]
 | 
			
		||||
#[serde(deny_unknown_fields)]
 | 
			
		||||
struct ButtonMeta {
 | 
			
		||||
    /// Action other than keysym (conflicts with keysym)
 | 
			
		||||
    action: Option<Action>,
 | 
			
		||||
    /// The name of the outline. If not present, will be "default"
 | 
			
		||||
    outline: Option<String>,
 | 
			
		||||
    /// FIXME: start using it
 | 
			
		||||
    keysym: Option<String>,
 | 
			
		||||
    /// If not present, will be derived from the button ID
 | 
			
		||||
    label: Option<String>,
 | 
			
		||||
    /// Conflicts with label
 | 
			
		||||
    icon: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Deserialize, PartialEq)]
 | 
			
		||||
#[serde(deny_unknown_fields)]
 | 
			
		||||
enum Action {
 | 
			
		||||
    #[serde(rename="locking")]
 | 
			
		||||
    Locking { lock_view: String, unlock_view: String },
 | 
			
		||||
    #[serde(rename="set_view")]
 | 
			
		||||
    SetView(String),
 | 
			
		||||
    #[serde(rename="show_prefs")]
 | 
			
		||||
    ShowPrefs,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
 | 
			
		||||
#[serde(deny_unknown_fields)]
 | 
			
		||||
struct Outline {
 | 
			
		||||
    corner_radius: f64,
 | 
			
		||||
    bounds: Bounds,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum Error {
 | 
			
		||||
    Yaml(serde_yaml::Error),
 | 
			
		||||
    Io(io::Error),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for Error {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            Error::Yaml(e) => write!(f, "YAML: {}", e),
 | 
			
		||||
            Error::Io(e) => write!(f, "IO: {}", e),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Layout {
 | 
			
		||||
    fn from_yaml_stream(path: PathBuf) -> Result<Layout, Error> {
 | 
			
		||||
        let infile = BufReader::new(
 | 
			
		||||
            fs::OpenOptions::new()
 | 
			
		||||
                .read(true)
 | 
			
		||||
                .open(&path)
 | 
			
		||||
                .map_err(Error::Io)?
 | 
			
		||||
        );
 | 
			
		||||
        serde_yaml::from_reader(infile)
 | 
			
		||||
            .map_err(Error::Yaml)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn build(self) -> Result<::layout::Layout, FormattingError> {
 | 
			
		||||
        let button_names = self.views.values()
 | 
			
		||||
            .flat_map(|rows| {
 | 
			
		||||
                rows.iter()
 | 
			
		||||
                    .flat_map(|row| row.split_ascii_whitespace())
 | 
			
		||||
            });
 | 
			
		||||
        
 | 
			
		||||
        let button_names: HashSet<&str>
 | 
			
		||||
            = HashSet::from_iter(button_names);
 | 
			
		||||
 | 
			
		||||
        let keycodes = generate_keycodes(
 | 
			
		||||
            button_names.iter()
 | 
			
		||||
                .map(|name| *name)
 | 
			
		||||
                .filter(|name| {
 | 
			
		||||
                    match self.buttons.get(*name) {
 | 
			
		||||
                        // buttons with defined action can't emit keysyms
 | 
			
		||||
                        // and so don't need keycodes
 | 
			
		||||
                        Some(ButtonMeta { action: Some(_), .. }) => false,
 | 
			
		||||
                        _ => true,
 | 
			
		||||
                    }
 | 
			
		||||
                })
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let button_states = button_names.iter().map(|name| {(
 | 
			
		||||
            String::from(*name),
 | 
			
		||||
            Rc::new(RefCell::new(KeyState {
 | 
			
		||||
                pressed: false,
 | 
			
		||||
                locked: false,
 | 
			
		||||
                keycode: keycodes.get(*name).map(|k| *k),
 | 
			
		||||
                symbol: create_symbol(
 | 
			
		||||
                    &self.buttons,
 | 
			
		||||
                    name,
 | 
			
		||||
                    self.views.keys().collect()
 | 
			
		||||
                ),
 | 
			
		||||
            }))
 | 
			
		||||
        )});
 | 
			
		||||
 | 
			
		||||
        let button_states =
 | 
			
		||||
            HashMap::<String, Rc<RefCell<KeyState>>>::from_iter(
 | 
			
		||||
                button_states
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
        // TODO: generate from symbols
 | 
			
		||||
        let keymap_str = generate_keymap(&button_states)?;
 | 
			
		||||
 | 
			
		||||
        let views = HashMap::from_iter(
 | 
			
		||||
            self.views.iter().map(|(name, view)| {(
 | 
			
		||||
                name.clone(),
 | 
			
		||||
                Box::new(::layout::View {
 | 
			
		||||
                    bounds: ::layout::c::Bounds {
 | 
			
		||||
                        x: self.bounds.x,
 | 
			
		||||
                        y: self.bounds.y,
 | 
			
		||||
                        width: self.bounds.width,
 | 
			
		||||
                        height: self.bounds.height,
 | 
			
		||||
                    },
 | 
			
		||||
                    rows: view.iter().map(|row| {
 | 
			
		||||
                        Box::new(::layout::Row {
 | 
			
		||||
                            angle: 0,
 | 
			
		||||
                            bounds: None,
 | 
			
		||||
                            buttons: row.split_ascii_whitespace().map(|name| {
 | 
			
		||||
                                Box::new(create_button(
 | 
			
		||||
                                    &self.buttons,
 | 
			
		||||
                                    &self.outlines,
 | 
			
		||||
                                    name,
 | 
			
		||||
                                    button_states.get(name.into())
 | 
			
		||||
                                        .expect("Button state not created")
 | 
			
		||||
                                        .clone()
 | 
			
		||||
                                ))
 | 
			
		||||
                            }).collect(),
 | 
			
		||||
                        })
 | 
			
		||||
                    }).collect(),
 | 
			
		||||
                })
 | 
			
		||||
            )})
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        Ok(::layout::Layout {
 | 
			
		||||
            current_view: "base".into(),
 | 
			
		||||
            views: views,
 | 
			
		||||
            keymap_str: {
 | 
			
		||||
                CString::new(keymap_str)
 | 
			
		||||
                    .expect("Invalid keymap string generated")
 | 
			
		||||
            },
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn create_symbol(
 | 
			
		||||
    button_info: &HashMap<String, ButtonMeta>,
 | 
			
		||||
    name: &str,
 | 
			
		||||
    view_names: Vec<&String>,
 | 
			
		||||
) -> ::symbol::Symbol {
 | 
			
		||||
    let default_meta = ButtonMeta::default();
 | 
			
		||||
    let symbol_meta = button_info.get(name)
 | 
			
		||||
        .unwrap_or(&default_meta);
 | 
			
		||||
    
 | 
			
		||||
    fn filter_view_name(
 | 
			
		||||
        button_name: &str,
 | 
			
		||||
        view_name: String,
 | 
			
		||||
        view_names: &Vec<&String>
 | 
			
		||||
    ) -> String {
 | 
			
		||||
        if view_names.contains(&&view_name) {
 | 
			
		||||
            view_name
 | 
			
		||||
        } else {
 | 
			
		||||
            eprintln!(
 | 
			
		||||
                "Button {} switches to missing view {}",
 | 
			
		||||
                button_name,
 | 
			
		||||
                view_name
 | 
			
		||||
            );
 | 
			
		||||
            "base".into()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    fn keysym_valid(name: &str) -> bool {
 | 
			
		||||
        xkb::keysym_from_name(name, xkb::KEYSYM_NO_FLAGS) != xkb::KEY_NoSymbol
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    let keysym = match &symbol_meta.action {
 | 
			
		||||
        Some(_) => None,
 | 
			
		||||
        None => Some(match &symbol_meta.keysym {
 | 
			
		||||
            Some(keysym) => match keysym_valid(keysym.as_str()) {
 | 
			
		||||
                true => keysym.clone(),
 | 
			
		||||
                false => {
 | 
			
		||||
                    eprintln!("Keysym name invalid: {}", keysym);
 | 
			
		||||
                    "space".into() // placeholder
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            None => match keysym_valid(name) {
 | 
			
		||||
                true => String::from(name),
 | 
			
		||||
                false => match name.chars().count() {
 | 
			
		||||
                    1 => format!("U{:04X}", name.chars().next().unwrap() as u32),
 | 
			
		||||
                    // If the name is longer than 1 char,
 | 
			
		||||
                    // then it's not a single Unicode char,
 | 
			
		||||
                    // but was trying to be an identifier
 | 
			
		||||
                    _ => {
 | 
			
		||||
                        eprintln!(
 | 
			
		||||
                            "Could not derive a valid keysym for key {}",
 | 
			
		||||
                            name
 | 
			
		||||
                        );
 | 
			
		||||
                        "space".into() // placeholder
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
        }),
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    match &symbol_meta.action {
 | 
			
		||||
        Some(Action::SetView(view_name)) => ::symbol::Symbol {
 | 
			
		||||
            action: ::symbol::Action::SetLevel(
 | 
			
		||||
                filter_view_name(name, view_name.clone(), &view_names)
 | 
			
		||||
            ),
 | 
			
		||||
        },
 | 
			
		||||
        Some(Action::Locking { lock_view, unlock_view }) => ::symbol::Symbol {
 | 
			
		||||
            action: ::symbol::Action::LockLevel {
 | 
			
		||||
                lock: filter_view_name(name, lock_view.clone(), &view_names),
 | 
			
		||||
                unlock: filter_view_name(
 | 
			
		||||
                    name,
 | 
			
		||||
                    unlock_view.clone(),
 | 
			
		||||
                    &view_names
 | 
			
		||||
                ),
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
        Some(Action::ShowPrefs) => ::symbol::Symbol {
 | 
			
		||||
            action: ::symbol::Action::Submit {
 | 
			
		||||
                text: None,
 | 
			
		||||
                keys: Vec::new(),
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
        None => ::symbol::Symbol {
 | 
			
		||||
            action: ::symbol::Action::Submit {
 | 
			
		||||
                text: None,
 | 
			
		||||
                keys: vec!(
 | 
			
		||||
                    ::symbol::KeySym(keysym.unwrap()),
 | 
			
		||||
                ),
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// TODO: Since this will receive user-provided data,
 | 
			
		||||
/// all .expect() on them should be turned into soft fails
 | 
			
		||||
fn create_button(
 | 
			
		||||
    button_info: &HashMap<String, ButtonMeta>,
 | 
			
		||||
    outlines: &HashMap<String, Outline>,
 | 
			
		||||
    name: &str,
 | 
			
		||||
    state: Rc<RefCell<KeyState>>,
 | 
			
		||||
) -> ::layout::Button {
 | 
			
		||||
    let cname = CString::new(name.clone())
 | 
			
		||||
        .expect("Bad name");
 | 
			
		||||
    // don't remove, because multiple buttons with the same name are allowed
 | 
			
		||||
    let default_meta = ButtonMeta::default();
 | 
			
		||||
    let button_meta = button_info.get(name)
 | 
			
		||||
        .unwrap_or(&default_meta);
 | 
			
		||||
 | 
			
		||||
    // TODO: move conversion to the C/Rust boundary
 | 
			
		||||
    let label = if let Some(label) = &button_meta.label {
 | 
			
		||||
        ::layout::Label::Text(CString::new(label.as_str())
 | 
			
		||||
            .expect("Bad label"))
 | 
			
		||||
    } else if let Some(icon) = &button_meta.icon {
 | 
			
		||||
        ::layout::Label::IconName(CString::new(icon.as_str())
 | 
			
		||||
            .expect("Bad icon"))
 | 
			
		||||
    } else {
 | 
			
		||||
        ::layout::Label::Text(cname.clone())
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let outline_name = match &button_meta.outline {
 | 
			
		||||
        Some(outline) => {
 | 
			
		||||
            if outlines.contains_key(outline) {
 | 
			
		||||
                outline.clone()
 | 
			
		||||
            } else {
 | 
			
		||||
                eprintln!("Outline named {} does not exist! Using default for button {}", outline, name);
 | 
			
		||||
                "default".into()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        None => "default".into(),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let outline = outlines.get(&outline_name)
 | 
			
		||||
        .map(|outline| (*outline).clone())
 | 
			
		||||
        .unwrap_or_else(|| {
 | 
			
		||||
            eprintln!("No default outline defied Using 1x1!");
 | 
			
		||||
            Outline {
 | 
			
		||||
                corner_radius: 0f64,
 | 
			
		||||
                bounds: Bounds { x: 0f64, y: 0f64, width: 1f64, height: 1f64 },
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    ::layout::Button {
 | 
			
		||||
        name: cname,
 | 
			
		||||
        // TODO: do layout before creating buttons
 | 
			
		||||
        bounds: ::layout::c::Bounds {
 | 
			
		||||
            x: outline.bounds.x,
 | 
			
		||||
            y: outline.bounds.y,
 | 
			
		||||
            width: outline.bounds.width,
 | 
			
		||||
            height: outline.bounds.height,
 | 
			
		||||
        },
 | 
			
		||||
        corner_radius: outline.corner_radius,
 | 
			
		||||
        label: label,
 | 
			
		||||
        state: state,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    
 | 
			
		||||
    use std::error::Error as ErrorTrait;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_parse_path() {
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            Layout::from_yaml_stream(
 | 
			
		||||
                PathBuf::from("tests/layout.yaml")
 | 
			
		||||
            ).unwrap(),
 | 
			
		||||
            Layout {
 | 
			
		||||
                bounds: Bounds { x: 0f64, y: 0f64, width: 0f64, height: 0f64 },
 | 
			
		||||
                views: hashmap!(
 | 
			
		||||
                    "base".into() => vec!("test".into()),
 | 
			
		||||
                ),
 | 
			
		||||
                buttons: hashmap!{
 | 
			
		||||
                    "test".into() => ButtonMeta {
 | 
			
		||||
                        icon: None,
 | 
			
		||||
                        keysym: None,
 | 
			
		||||
                        action: None,
 | 
			
		||||
                        label: Some("test".into()),
 | 
			
		||||
                        outline: None,
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                outlines: hashmap!{
 | 
			
		||||
                    "default".into() => Outline {
 | 
			
		||||
                        corner_radius: 1f64,
 | 
			
		||||
                        bounds: Bounds {
 | 
			
		||||
                            x: 0f64, y: 0f64, width: 0f64, height: 0f64
 | 
			
		||||
                        }, 
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Check if the default protection works
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_empty_views() {
 | 
			
		||||
        let out = Layout::from_yaml_stream(PathBuf::from("tests/layout2.yaml"));
 | 
			
		||||
        match out {
 | 
			
		||||
            Ok(_) => assert!(false, "Data mistakenly accepted"),
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                let mut handled = false;
 | 
			
		||||
                if let Error::Yaml(ye) = &e {
 | 
			
		||||
                    handled = ye.description() == "missing field `views`";
 | 
			
		||||
                };
 | 
			
		||||
                if !handled {
 | 
			
		||||
                    println!("Unexpected error {:?}", e);
 | 
			
		||||
                    assert!(false)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_extra_field() {
 | 
			
		||||
        let out = Layout::from_yaml_stream(PathBuf::from("tests/layout3.yaml"));
 | 
			
		||||
        match out {
 | 
			
		||||
            Ok(_) => assert!(false, "Data mistakenly accepted"),
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                let mut handled = false;
 | 
			
		||||
                if let Error::Yaml(ye) = &e {
 | 
			
		||||
                    handled = ye.description()
 | 
			
		||||
                        .starts_with("unknown field `bad_field`");
 | 
			
		||||
                };
 | 
			
		||||
                if !handled {
 | 
			
		||||
                    println!("Unexpected error {:?}", e);
 | 
			
		||||
                    assert!(false)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_layout_punctuation() {
 | 
			
		||||
        let out = Layout::from_yaml_stream(PathBuf::from("tests/layout_key1.yaml"))
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .build()
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            out.views["base"]
 | 
			
		||||
                .rows[0]
 | 
			
		||||
                .buttons[0]
 | 
			
		||||
                .label,
 | 
			
		||||
            ::layout::Label::Text(CString::new("test").unwrap())
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_layout_unicode() {
 | 
			
		||||
        let out = Layout::from_yaml_stream(PathBuf::from("tests/layout_key2.yaml"))
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .build()
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            out.views["base"]
 | 
			
		||||
                .rows[0]
 | 
			
		||||
                .buttons[0]
 | 
			
		||||
                .label,
 | 
			
		||||
            ::layout::Label::Text(CString::new("test").unwrap())
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn parsing_fallback() {
 | 
			
		||||
        assert!(load_layout_from_resource(FALLBACK_LAYOUT_NAME)
 | 
			
		||||
            .and_then(|layout| layout.build().map_err(LoadError::BadKeyMap))
 | 
			
		||||
            .is_ok()
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn unicode_keysym() {
 | 
			
		||||
        let keysym = xkb::keysym_from_name(
 | 
			
		||||
            format!("U{:X}", "å".chars().next().unwrap() as u32).as_str(),
 | 
			
		||||
            xkb::KEYSYM_NO_FLAGS,
 | 
			
		||||
        );
 | 
			
		||||
        let keysym = xkb::keysym_to_utf8(keysym);
 | 
			
		||||
        assert_eq!(keysym, "å\0");
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_key_unicode() {
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            create_symbol(
 | 
			
		||||
                &hashmap!{
 | 
			
		||||
                    ".".into() => ButtonMeta {
 | 
			
		||||
                        icon: None,
 | 
			
		||||
                        keysym: None,
 | 
			
		||||
                        action: None,
 | 
			
		||||
                        label: Some("test".into()),
 | 
			
		||||
                        outline: None,
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                ".",
 | 
			
		||||
                Vec::new()
 | 
			
		||||
            ),
 | 
			
		||||
            ::symbol::Symbol {
 | 
			
		||||
                action: ::symbol::Action::Submit {
 | 
			
		||||
                    text: None,
 | 
			
		||||
                    keys: vec!(::symbol::KeySym("U002E".into())),
 | 
			
		||||
                },
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,6 +5,10 @@
 | 
			
		||||
/* Adapted from https://github.com/notriddle/rust-float-ord revision e995165f
 | 
			
		||||
 * maintained by Michael Howell <michael@notriddle.com>
 | 
			
		||||
 * licensed under MIT / Apache-2.0 licenses
 | 
			
		||||
 * 
 | 
			
		||||
 * This version drops any dependency on rand.
 | 
			
		||||
 * Caution: Don't pull the version from crates.io
 | 
			
		||||
 * before making sure rand is optional.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
extern crate core;
 | 
			
		||||
@ -67,6 +71,7 @@ float_ord_impl!(f64, u64, 64);
 | 
			
		||||
/// # Example
 | 
			
		||||
///
 | 
			
		||||
/// ```
 | 
			
		||||
/// use rs::float_ord;
 | 
			
		||||
/// let mut v = [-5.0, 4.0, 1.0, -3.0, 2.0];
 | 
			
		||||
///
 | 
			
		||||
/// float_ord::sort(&mut v);
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ use std::num::Wrapping;
 | 
			
		||||
use std::string::String;
 | 
			
		||||
 | 
			
		||||
use super::bitflags;
 | 
			
		||||
use ::util::c::into_cstring;
 | 
			
		||||
 | 
			
		||||
// Traits
 | 
			
		||||
use std::convert::TryFrom;
 | 
			
		||||
@ -13,15 +14,8 @@ use std::convert::TryFrom;
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    
 | 
			
		||||
    use std::ffi::CStr;
 | 
			
		||||
    use std::os::raw::{c_char, c_void};
 | 
			
		||||
 | 
			
		||||
    fn into_cstring(s: *const c_char) -> Result<CString, std::ffi::NulError> {
 | 
			
		||||
        CString::new(
 | 
			
		||||
            unsafe {CStr::from_ptr(s)}.to_bytes()
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // The following defined in C
 | 
			
		||||
        
 | 
			
		||||
    /// struct zwp_input_method_v2*
 | 
			
		||||
@ -91,7 +85,9 @@ pub mod c {
 | 
			
		||||
    {
 | 
			
		||||
        let imservice = check_imservice(imservice, im).unwrap();
 | 
			
		||||
        imservice.pending = IMProtocolState {
 | 
			
		||||
            surrounding_text: into_cstring(text).expect("Received invalid string"),
 | 
			
		||||
            surrounding_text: into_cstring(text)
 | 
			
		||||
                .expect("Received invalid string")
 | 
			
		||||
                .expect("Received null string"),
 | 
			
		||||
            surrounding_cursor: cursor,
 | 
			
		||||
            ..imservice.pending.clone()
 | 
			
		||||
        };
 | 
			
		||||
@ -230,7 +226,8 @@ bitflags!{
 | 
			
		||||
/// Map to `text_input_unstable_v3.content_purpose` values
 | 
			
		||||
///
 | 
			
		||||
/// ```
 | 
			
		||||
/// assert_eq!(ContentPurpose::Alpha as u32, 0);
 | 
			
		||||
/// use rs::imservice::ContentPurpose;
 | 
			
		||||
/// assert_eq!(ContentPurpose::Alpha as u32, 1);
 | 
			
		||||
/// ```
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub enum ContentPurpose {
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
#ifndef __KEYBOARD_H
 | 
			
		||||
#define __KYBOARD_H
 | 
			
		||||
#define __KEYBOARD_H
 | 
			
		||||
 | 
			
		||||
#include "stdbool.h"
 | 
			
		||||
#include "inttypes.h"
 | 
			
		||||
@ -19,6 +19,7 @@ uint32_t squeek_key_is_locked(struct squeek_key *key);
 | 
			
		||||
void squeek_key_set_locked(struct squeek_key *key, uint32_t pressed);
 | 
			
		||||
uint32_t squeek_key_get_keycode(struct squeek_key *key);
 | 
			
		||||
void squeek_key_set_keycode(struct squeek_key *key, uint32_t keycode);
 | 
			
		||||
uint32_t squeek_key_equal(struct squeek_key* key, struct squeek_key* key1);
 | 
			
		||||
 | 
			
		||||
struct squeek_symbol *squeek_key_get_symbol(struct squeek_key* key);
 | 
			
		||||
const char* squeek_key_to_keymap_entry(const char *key_name, struct squeek_key *key);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										363
									
								
								src/keyboard.rs
									
									
									
									
									
								
							
							
						
						
									
										363
									
								
								src/keyboard.rs
									
									
									
									
									
								
							@ -1,90 +1,41 @@
 | 
			
		||||
use std::vec::Vec;
 | 
			
		||||
/*! State of the emulated keyboard and keys */
 | 
			
		||||
 | 
			
		||||
use super::symbol;
 | 
			
		||||
use std::cell::RefCell;
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
use std::fmt;
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::rc::Rc;
 | 
			
		||||
use std::string::FromUtf8Error;
 | 
			
		||||
    
 | 
			
		||||
use ::symbol::{ Symbol, Action };
 | 
			
		||||
 | 
			
		||||
use std::io::Write;
 | 
			
		||||
use std::iter::{ FromIterator, IntoIterator };
 | 
			
		||||
 | 
			
		||||
/// Gathers stuff defined in C or called by C
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use ::util::c::{ as_cstr, into_cstring };
 | 
			
		||||
    use ::util::c;
 | 
			
		||||
    use ::util::c::as_cstr;
 | 
			
		||||
    
 | 
			
		||||
    use std::cell::RefCell;
 | 
			
		||||
    use std::ffi::CString;
 | 
			
		||||
    use std::os::raw::c_char;
 | 
			
		||||
    use std::ptr;
 | 
			
		||||
    use std::rc::Rc;
 | 
			
		||||
 | 
			
		||||
    // traits
 | 
			
		||||
    
 | 
			
		||||
    use std::borrow::ToOwned;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    // The following defined in C
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    extern "C" {
 | 
			
		||||
        fn eek_keysym_from_name(name: *const c_char) -> u32;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// The wrapped structure for KeyState suitable for handling in C
 | 
			
		||||
    /// Since C doesn't respect borrowing rules,
 | 
			
		||||
    /// RefCell will enforce them dynamically (only 1 writer/many readers)
 | 
			
		||||
    /// Rc is implied and will ensure timely dropping
 | 
			
		||||
    #[repr(transparent)]
 | 
			
		||||
    pub struct CKeyState(*const RefCell<KeyState>);
 | 
			
		||||
    
 | 
			
		||||
    impl Clone for CKeyState {
 | 
			
		||||
        fn clone(&self) -> Self {
 | 
			
		||||
            CKeyState(self.0.clone())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl CKeyState {
 | 
			
		||||
        pub fn wrap(state: Rc<RefCell<KeyState>>) -> CKeyState {
 | 
			
		||||
            CKeyState(Rc::into_raw(state))
 | 
			
		||||
        }
 | 
			
		||||
        pub fn unwrap(self) -> Rc<RefCell<KeyState>> {
 | 
			
		||||
            unsafe { Rc::from_raw(self.0) }
 | 
			
		||||
        }
 | 
			
		||||
        fn to_owned(self) -> KeyState {
 | 
			
		||||
            let rc = self.unwrap();
 | 
			
		||||
            let state = rc.borrow().to_owned();
 | 
			
		||||
            Rc::into_raw(rc); // Prevent dropping
 | 
			
		||||
            state
 | 
			
		||||
        }
 | 
			
		||||
        fn borrow_mut<F, T>(self, f: F) -> T where F: FnOnce(&mut KeyState) -> T {
 | 
			
		||||
            let rc = self.unwrap();
 | 
			
		||||
            let ret = {
 | 
			
		||||
                let mut state = rc.borrow_mut();
 | 
			
		||||
                f(&mut state)
 | 
			
		||||
            };
 | 
			
		||||
            Rc::into_raw(rc); // Prevent dropping
 | 
			
		||||
            ret
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO: unwrapping
 | 
			
		||||
    pub type CKeyState = c::Wrapped<KeyState>;
 | 
			
		||||
 | 
			
		||||
    // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
 | 
			
		||||
 | 
			
		||||
    // TODO: this will receive data from the filesystem,
 | 
			
		||||
    // so it should handle garbled strings in the future
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_new(keycode: u32) -> CKeyState {
 | 
			
		||||
        let state: Rc<RefCell<KeyState>> = Rc::new(RefCell::new(
 | 
			
		||||
            KeyState {
 | 
			
		||||
                pressed: false,
 | 
			
		||||
                locked: false,
 | 
			
		||||
                keycode: keycode,
 | 
			
		||||
                symbol: None,
 | 
			
		||||
            }
 | 
			
		||||
        ));
 | 
			
		||||
        CKeyState::wrap(state)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_free(key: CKeyState) {
 | 
			
		||||
        key.unwrap(); // reference dropped
 | 
			
		||||
        unsafe { key.unwrap() }; // reference dropped
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Compares pointers to the data
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_equal(key: CKeyState, key2: CKeyState) -> u32 {
 | 
			
		||||
        return Rc::ptr_eq(&key.clone_ref(), &key2.clone_ref()) as u32
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
@ -97,7 +48,9 @@ pub mod c {
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_set_pressed(key: CKeyState, pressed: u32) {
 | 
			
		||||
        key.borrow_mut(|key| key.pressed = pressed != 0);
 | 
			
		||||
        let key = key.clone_ref();
 | 
			
		||||
        let mut key = key.borrow_mut();
 | 
			
		||||
        key.pressed = pressed != 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
@ -109,109 +62,15 @@ pub mod c {
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_set_locked(key: CKeyState, locked: u32) {
 | 
			
		||||
        key.borrow_mut(|key| key.locked = locked != 0);
 | 
			
		||||
        let key = key.clone_ref();
 | 
			
		||||
        let mut key = key.borrow_mut();
 | 
			
		||||
        key.locked = locked != 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_get_keycode(key: CKeyState) -> u32 {
 | 
			
		||||
        return key.to_owned().keycode as u32;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_set_keycode(key: CKeyState, code: u32) {
 | 
			
		||||
        key.borrow_mut(|key| key.keycode = code);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // TODO: this will receive data from the filesystem,
 | 
			
		||||
    // so it should handle garbled strings in the future
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_add_symbol(
 | 
			
		||||
        key: CKeyState,
 | 
			
		||||
        element: *const c_char,
 | 
			
		||||
        text_raw: *const c_char, keyval: u32,
 | 
			
		||||
        label: *const c_char, icon: *const c_char,
 | 
			
		||||
        tooltip: *const c_char,
 | 
			
		||||
    ) {
 | 
			
		||||
        let element = as_cstr(&element)
 | 
			
		||||
            .expect("Missing element name");
 | 
			
		||||
 | 
			
		||||
        let text = into_cstring(text_raw)
 | 
			
		||||
            .unwrap_or_else(|e| {
 | 
			
		||||
                eprintln!("Text unreadable: {}", e);
 | 
			
		||||
                None
 | 
			
		||||
            })
 | 
			
		||||
            .and_then(|text| {
 | 
			
		||||
                if text.as_bytes() == b"" {
 | 
			
		||||
                    None
 | 
			
		||||
                } else {
 | 
			
		||||
                    Some(text)
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        let icon = into_cstring(icon)
 | 
			
		||||
            .unwrap_or_else(|e| {
 | 
			
		||||
                eprintln!("Icon name unreadable: {}", e);
 | 
			
		||||
                None
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        use symbol::*;
 | 
			
		||||
        // Only read label if there's no icon
 | 
			
		||||
        let label = match icon {
 | 
			
		||||
            Some(icon) => Label::IconName(icon),
 | 
			
		||||
            None => Label::Text(
 | 
			
		||||
                into_cstring(label)
 | 
			
		||||
                    .unwrap_or_else(|e| {
 | 
			
		||||
                        eprintln!("Label unreadable: {}", e);
 | 
			
		||||
                        Some(CString::new(" ").unwrap())
 | 
			
		||||
                    })
 | 
			
		||||
                    .unwrap_or_else(|| {
 | 
			
		||||
                        eprintln!("Label missing");
 | 
			
		||||
                        CString::new(" ").unwrap()
 | 
			
		||||
                    })
 | 
			
		||||
            ),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let tooltip = into_cstring(tooltip)
 | 
			
		||||
            .unwrap_or_else(|e| {
 | 
			
		||||
                eprintln!("Tooltip unreadable: {}", e);
 | 
			
		||||
                None
 | 
			
		||||
            });
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        key.borrow_mut(|key| {
 | 
			
		||||
            if let Some(_) = key.symbol {
 | 
			
		||||
                eprintln!("Key {:?} already has a symbol defined", text);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            key.symbol = Some(match element.to_bytes() {
 | 
			
		||||
                b"symbol" => Symbol {
 | 
			
		||||
                    action: Action::Submit {
 | 
			
		||||
                        text: text,
 | 
			
		||||
                        keys: Vec::new(),
 | 
			
		||||
                    },
 | 
			
		||||
                    label: label,
 | 
			
		||||
                    tooltip: tooltip,
 | 
			
		||||
                },
 | 
			
		||||
                _ => panic!("unsupported element type {:?}", element),
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_get_symbol(key: CKeyState) -> *const symbol::Symbol {
 | 
			
		||||
        key.borrow_mut(|key| {
 | 
			
		||||
            match key.symbol {
 | 
			
		||||
                // This pointer stays after the function exits,
 | 
			
		||||
                // so it must reference borrowed data and not any copy
 | 
			
		||||
                Some(ref symbol) => symbol as *const symbol::Symbol,
 | 
			
		||||
                None => ptr::null(),
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
        return key.to_owned().keycode.unwrap_or(0u32);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
@ -225,20 +84,14 @@ pub mod c {
 | 
			
		||||
            .to_str()
 | 
			
		||||
            .expect("Bad key name");
 | 
			
		||||
 | 
			
		||||
        let symbol_name = match key.to_owned().symbol {
 | 
			
		||||
            Some(ref symbol) => match &symbol.action {
 | 
			
		||||
                symbol::Action::Submit { text: Some(text), .. } => {
 | 
			
		||||
                    Some(
 | 
			
		||||
                        text.clone()
 | 
			
		||||
                            .into_string().expect("Bad symbol")
 | 
			
		||||
                    )
 | 
			
		||||
                },
 | 
			
		||||
                _ => None
 | 
			
		||||
            },
 | 
			
		||||
            None => {
 | 
			
		||||
                eprintln!("Key {} has no symbol", key_name);
 | 
			
		||||
                None
 | 
			
		||||
        let symbol_name = match key.to_owned().symbol.action {
 | 
			
		||||
            Action::Submit { text: Some(text), .. } => {
 | 
			
		||||
                Some(
 | 
			
		||||
                    text.clone()
 | 
			
		||||
                        .into_string().expect("Bad symbol")
 | 
			
		||||
                )
 | 
			
		||||
            },
 | 
			
		||||
            _ => None,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let inner = match symbol_name {
 | 
			
		||||
@ -251,7 +104,7 @@ pub mod c {
 | 
			
		||||
            .into_raw()
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
        #[no_mangle]
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_get_action_name(
 | 
			
		||||
        key_name: *const c_char,
 | 
			
		||||
@ -262,20 +115,14 @@ pub mod c {
 | 
			
		||||
            .to_str()
 | 
			
		||||
            .expect("Bad key name");
 | 
			
		||||
 | 
			
		||||
        let symbol_name = match key.to_owned().symbol {
 | 
			
		||||
            Some(ref symbol) => match &symbol.action {
 | 
			
		||||
                symbol::Action::Submit { text: Some(text), .. } => {
 | 
			
		||||
                    Some(
 | 
			
		||||
                        text.clone()
 | 
			
		||||
                            .into_string().expect("Bad symbol")
 | 
			
		||||
                    )
 | 
			
		||||
                },
 | 
			
		||||
                _ => None
 | 
			
		||||
            },
 | 
			
		||||
            None => {
 | 
			
		||||
                eprintln!("Key {} has no symbol", key_name);
 | 
			
		||||
                None
 | 
			
		||||
        let symbol_name = match key.to_owned().symbol.action {
 | 
			
		||||
            Action::Submit { text: Some(text), .. } => {
 | 
			
		||||
                Some(
 | 
			
		||||
                    text.clone()
 | 
			
		||||
                        .into_string().expect("Bad symbol text")
 | 
			
		||||
                )
 | 
			
		||||
            },
 | 
			
		||||
            _ => None
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let inner = match symbol_name {
 | 
			
		||||
@ -287,14 +134,126 @@ pub mod c {
 | 
			
		||||
            .expect("Couldn't convert string")
 | 
			
		||||
            .into_raw()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct KeyState {
 | 
			
		||||
    pub pressed: bool,
 | 
			
		||||
    pub locked: bool,
 | 
			
		||||
    pub keycode: u32,
 | 
			
		||||
    // TODO: remove the optionality of a symbol
 | 
			
		||||
    pub symbol: Option<symbol::Symbol>,
 | 
			
		||||
    pub keycode: Option<u32>,
 | 
			
		||||
    pub symbol: Symbol,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Generates a mapping where each key gets a keycode, starting from 8
 | 
			
		||||
pub fn generate_keycodes<'a, C: IntoIterator<Item=&'a str>>(
 | 
			
		||||
    key_names: C
 | 
			
		||||
) -> HashMap<String, u32> {
 | 
			
		||||
    HashMap::from_iter(
 | 
			
		||||
        key_names.into_iter()
 | 
			
		||||
            .map(|name| String::from(name))
 | 
			
		||||
            .zip(8..)
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum FormattingError {
 | 
			
		||||
    Utf(FromUtf8Error),
 | 
			
		||||
    Format(io::Error),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for FormattingError {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            FormattingError::Utf(e) => write!(f, "UTF: {}", e),
 | 
			
		||||
            FormattingError::Format(e) => write!(f, "Format: {}", e),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<io::Error> for FormattingError {
 | 
			
		||||
    fn from(e: io::Error) -> Self {
 | 
			
		||||
        FormattingError::Format(e)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Generates a de-facto single level keymap. TODO: actually drop second level
 | 
			
		||||
pub fn generate_keymap(
 | 
			
		||||
    keystates: &HashMap::<String, Rc<RefCell<KeyState>>>
 | 
			
		||||
) -> Result<String, FormattingError> {
 | 
			
		||||
    let mut buf: Vec<u8> = Vec::new();
 | 
			
		||||
    writeln!(
 | 
			
		||||
        buf,
 | 
			
		||||
        "xkb_keymap {{
 | 
			
		||||
 | 
			
		||||
    xkb_keycodes \"squeekboard\" {{
 | 
			
		||||
        minimum = 8;
 | 
			
		||||
        maximum = 255;"
 | 
			
		||||
    )?;
 | 
			
		||||
    
 | 
			
		||||
    for (name, state) in keystates.iter() {
 | 
			
		||||
        let state = state.borrow();
 | 
			
		||||
        if let ::symbol::Action::Submit { text: _, keys } = &state.symbol.action {
 | 
			
		||||
            match keys.len() {
 | 
			
		||||
                0 => eprintln!("Key {} has no keysyms", name),
 | 
			
		||||
                a => {
 | 
			
		||||
                    // TODO: don't ignore any keysyms
 | 
			
		||||
                    if a > 1 {
 | 
			
		||||
                        eprintln!("Key {} multiple keysyms", name);
 | 
			
		||||
                    }
 | 
			
		||||
                    write!(
 | 
			
		||||
                        buf,
 | 
			
		||||
                        "
 | 
			
		||||
        <{}> = {};",
 | 
			
		||||
                        keys[0].0,
 | 
			
		||||
                        state.keycode.unwrap()
 | 
			
		||||
                    )?;
 | 
			
		||||
                },
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    writeln!(
 | 
			
		||||
        buf,
 | 
			
		||||
        "
 | 
			
		||||
    }};
 | 
			
		||||
    
 | 
			
		||||
    xkb_symbols \"squeekboard\" {{
 | 
			
		||||
 | 
			
		||||
        name[Group1] = \"Letters\";
 | 
			
		||||
        name[Group2] = \"Numbers/Symbols\";"
 | 
			
		||||
    )?;
 | 
			
		||||
    
 | 
			
		||||
    for (name, state) in keystates.iter() {
 | 
			
		||||
        if let ::symbol::Action::Submit { text: _, keys } = &state.borrow().symbol.action {
 | 
			
		||||
            if let Some(keysym) = keys.iter().next() {
 | 
			
		||||
                write!(
 | 
			
		||||
                    buf,
 | 
			
		||||
                    "
 | 
			
		||||
        key <{}> {{ [ {0} ] }};",
 | 
			
		||||
                    keysym.0,
 | 
			
		||||
                )?;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    writeln!(
 | 
			
		||||
        buf,
 | 
			
		||||
        "
 | 
			
		||||
    }};
 | 
			
		||||
 | 
			
		||||
    xkb_types \"squeekboard\" {{
 | 
			
		||||
 | 
			
		||||
	type \"TWO_LEVEL\" {{
 | 
			
		||||
            modifiers = Shift;
 | 
			
		||||
            map[Shift] = Level2;
 | 
			
		||||
            level_name[Level1] = \"Base\";
 | 
			
		||||
            level_name[Level2] = \"Shift\";
 | 
			
		||||
	}};
 | 
			
		||||
    }};
 | 
			
		||||
 | 
			
		||||
    xkb_compatibility \"squeekboard\" {{
 | 
			
		||||
    }};
 | 
			
		||||
}};"
 | 
			
		||||
    )?;
 | 
			
		||||
    
 | 
			
		||||
    String::from_utf8(buf).map_err(FormattingError::Utf)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										40
									
								
								src/layout.h
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								src/layout.h
									
									
									
									
									
								
							@ -9,17 +9,11 @@
 | 
			
		||||
struct squeek_button;
 | 
			
		||||
struct squeek_row;
 | 
			
		||||
struct squeek_view;
 | 
			
		||||
struct squeek_layout;
 | 
			
		||||
 | 
			
		||||
struct squeek_row *squeek_row_new(int32_t angle);
 | 
			
		||||
struct squeek_button *squeek_row_create_button (struct squeek_row *row,
 | 
			
		||||
                                          guint keycode, guint oref);
 | 
			
		||||
struct squeek_button *squeek_row_create_button_with_state(struct squeek_row *row,
 | 
			
		||||
                                    struct squeek_button *source);
 | 
			
		||||
void squeek_row_set_angle(struct squeek_row *row, int32_t angle);
 | 
			
		||||
int32_t squeek_row_get_angle(const struct squeek_row*);
 | 
			
		||||
 | 
			
		||||
EekBounds squeek_row_get_bounds(const struct squeek_row*);
 | 
			
		||||
void squeek_row_set_bounds(struct squeek_row* row, EekBounds bounds);
 | 
			
		||||
 | 
			
		||||
uint32_t squeek_row_contains(struct squeek_row*, struct squeek_button *button);
 | 
			
		||||
 | 
			
		||||
@ -33,34 +27,19 @@ void squeek_row_foreach(struct squeek_row*,
 | 
			
		||||
 | 
			
		||||
void squeek_row_free(struct squeek_row*);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
struct squeek_button *squeek_buttons_find_by_position(
 | 
			
		||||
    const struct squeek_buttons *buttons,
 | 
			
		||||
    double x, double y,
 | 
			
		||||
    double origin_x, double origin_y,
 | 
			
		||||
    double angle);
 | 
			
		||||
void squeek_buttons_add(struct squeek_buttons*, const struct squeek_button* button);
 | 
			
		||||
void squeek_buttons_remove_key(struct squeek_buttons*, const struct squeek_key* key);
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
struct squeek_button *squeek_button_new(uint32_t keycode, uint32_t oref);
 | 
			
		||||
struct squeek_button *squeek_button_new_with_state(const struct squeek_button* source);
 | 
			
		||||
uint32_t squeek_button_get_oref(const struct squeek_button*);
 | 
			
		||||
EekBounds squeek_button_get_bounds(const struct squeek_button*);
 | 
			
		||||
void squeek_button_set_bounds(struct squeek_button* button, EekBounds bounds);
 | 
			
		||||
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*);
 | 
			
		||||
 | 
			
		||||
struct squeek_symbol *squeek_button_get_symbol (
 | 
			
		||||
    const struct squeek_button *button);
 | 
			
		||||
struct squeek_key *squeek_button_get_key(const struct squeek_button*);
 | 
			
		||||
uint32_t *squeek_button_has_key(const struct squeek_button* button,
 | 
			
		||||
                                const struct squeek_key *key);
 | 
			
		||||
void squeek_button_print(const struct squeek_button* button);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct squeek_view *squeek_view_new(EekBounds bounds);
 | 
			
		||||
struct squeek_row *squeek_view_create_row(struct squeek_view *, int32_t angle);
 | 
			
		||||
EekBounds squeek_view_get_bounds(const struct squeek_view*);
 | 
			
		||||
void squeek_view_set_bounds(const struct squeek_view*, EekBounds bounds);
 | 
			
		||||
 | 
			
		||||
typedef void (*RowCallback) (struct squeek_row *row, gpointer user_data);
 | 
			
		||||
void squeek_view_foreach(struct squeek_view*,
 | 
			
		||||
@ -70,9 +49,16 @@ void squeek_view_foreach(struct squeek_view*,
 | 
			
		||||
struct squeek_row *squeek_view_get_row(struct squeek_view *view,
 | 
			
		||||
                                       struct squeek_button *button);
 | 
			
		||||
 | 
			
		||||
struct squeek_button *squeek_view_find_button_by_position(struct squeek_view *view, EekPoint point);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
squeek_view_place_contents(struct squeek_view *view, LevelKeyboard *keyboard);
 | 
			
		||||
squeek_layout_place_contents(struct squeek_layout*);
 | 
			
		||||
struct squeek_view *squeek_layout_get_current_view(struct squeek_layout*);
 | 
			
		||||
void squeek_layout_set_state_from_press(struct squeek_layout* layout, LevelKeyboard *keyboard, struct squeek_key* key);
 | 
			
		||||
 | 
			
		||||
struct squeek_button *squeek_view_find_button_by_position(struct squeek_view *view, EekPoint point);
 | 
			
		||||
 | 
			
		||||
struct squeek_layout *squeek_load_layout(const char *type);
 | 
			
		||||
const char *squeek_layout_get_keymap(const struct squeek_layout*);
 | 
			
		||||
void squeek_layout_free(struct squeek_layout*);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										465
									
								
								src/layout.rs
									
									
									
									
									
								
							
							
						
						
									
										465
									
								
								src/layout.rs
									
									
									
									
									
								
							@ -1,4 +1,4 @@
 | 
			
		||||
/**
 | 
			
		||||
/*!
 | 
			
		||||
 * Layout-related data.
 | 
			
		||||
 * 
 | 
			
		||||
 * The `View` contains `Row`s and each `Row` contains `Button`s.
 | 
			
		||||
@ -18,6 +18,8 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
use std::cell::RefCell;
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
use std::ffi::CString;
 | 
			
		||||
use std::rc::Rc;
 | 
			
		||||
use std::vec::Vec;
 | 
			
		||||
 | 
			
		||||
@ -29,7 +31,8 @@ use ::symbol::*;
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    use std::os::raw::c_void;
 | 
			
		||||
    use std::ffi::CStr;
 | 
			
		||||
    use std::os::raw::{ c_char, c_void };
 | 
			
		||||
    use std::ptr;
 | 
			
		||||
 | 
			
		||||
    // The following defined in C
 | 
			
		||||
@ -60,26 +63,11 @@ pub mod c {
 | 
			
		||||
        pub height: f64
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    impl Bounds {
 | 
			
		||||
        pub fn zero() -> Bounds {
 | 
			
		||||
            Bounds { x: 0f64, y: 0f64, width: 0f64, height: 0f64 }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    type ButtonCallback = unsafe extern "C" fn(button: *mut ::layout::Button, data: *mut UserData);
 | 
			
		||||
    type RowCallback = unsafe extern "C" fn(row: *mut ::layout::Row, data: *mut UserData);
 | 
			
		||||
 | 
			
		||||
    // 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_view_new(bounds: Bounds) -> *mut ::layout::View {
 | 
			
		||||
        Box::into_raw(Box::new(::layout::View {
 | 
			
		||||
            rows: Vec::new(),
 | 
			
		||||
            bounds: bounds,
 | 
			
		||||
        }))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_view_get_bounds(view: *const ::layout::View) -> Bounds {
 | 
			
		||||
@ -88,30 +76,6 @@ pub mod c {
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_view_set_bounds(view: *mut ::layout::View, bounds: Bounds) {
 | 
			
		||||
        unsafe { &mut *view }.bounds = bounds;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Places a row into the view and returns a reference to it
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_view_create_row(
 | 
			
		||||
        view: *mut ::layout::View,
 | 
			
		||||
        angle: i32,
 | 
			
		||||
    ) -> *mut ::layout::Row {
 | 
			
		||||
        let view = unsafe { &mut *view };
 | 
			
		||||
 | 
			
		||||
        view.rows.push(Box::new(::layout::Row::new(angle)));
 | 
			
		||||
        // Return the reference directly instead of a Box, it's not on the stack
 | 
			
		||||
        // It will live as long as the Vec
 | 
			
		||||
        let last_idx = view.rows.len() - 1;
 | 
			
		||||
        // Caution: Box can't be returned directly,
 | 
			
		||||
        // so returning a reference to its innards
 | 
			
		||||
        view.rows[last_idx].as_mut() as *mut ::layout::Row
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
        #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_view_foreach(
 | 
			
		||||
        view: *mut ::layout::View,
 | 
			
		||||
        callback: RowCallback,
 | 
			
		||||
@ -124,68 +88,6 @@ pub mod c {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_row_new(angle: i32) -> *mut ::layout::Row {
 | 
			
		||||
        Box::into_raw(Box::new(::layout::Row::new(angle)))
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Places a button into the row and returns a reference to it
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_row_create_button(
 | 
			
		||||
        row: *mut ::layout::Row,
 | 
			
		||||
        keycode: u32, oref: u32
 | 
			
		||||
    ) -> *mut ::layout::Button {
 | 
			
		||||
        let row = unsafe { &mut *row };
 | 
			
		||||
        let state: Rc<RefCell<::keyboard::KeyState>> = Rc::new(RefCell::new(
 | 
			
		||||
            ::keyboard::KeyState {
 | 
			
		||||
                pressed: false,
 | 
			
		||||
                locked: false,
 | 
			
		||||
                keycode: keycode,
 | 
			
		||||
                symbol: None,
 | 
			
		||||
            }
 | 
			
		||||
        ));
 | 
			
		||||
        row.buttons.push(Box::new(::layout::Button {
 | 
			
		||||
            oref: OutlineRef(oref),
 | 
			
		||||
            bounds: None,
 | 
			
		||||
            state: state,
 | 
			
		||||
        }));
 | 
			
		||||
        // Return the reference directly instead of a Box, it's not on the stack
 | 
			
		||||
        // It will live as long as the Vec
 | 
			
		||||
        let last_idx = row.buttons.len() - 1;
 | 
			
		||||
        // Caution: Box can't be returned directly,
 | 
			
		||||
        // so returning a reference to its innards
 | 
			
		||||
        row.buttons[last_idx].as_mut() as *mut ::layout::Button
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Places a button into the row, copying its state,
 | 
			
		||||
    /// and returns a reference to it
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_row_create_button_with_state(
 | 
			
		||||
        row: *mut ::layout::Row,
 | 
			
		||||
        button: *const ::layout::Button,
 | 
			
		||||
    ) -> *mut ::layout::Button {
 | 
			
		||||
        let row = unsafe { &mut *row };
 | 
			
		||||
        let source = unsafe { &*button };
 | 
			
		||||
        row.buttons.push(Box::new(source.clone()));
 | 
			
		||||
        // Return the reference directly instead of a Box, it's not on the stack
 | 
			
		||||
        // It will live as long as the Vec
 | 
			
		||||
        let last_idx = row.buttons.len() - 1;
 | 
			
		||||
        // Caution: Box can't be returned directly,
 | 
			
		||||
        // so returning a reference to its innards directly
 | 
			
		||||
        row.buttons[last_idx].as_mut() as *mut ::layout::Button
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_row_set_angle(row: *mut ::layout::Row, angle: i32) {
 | 
			
		||||
        let row = unsafe { &mut *row };
 | 
			
		||||
        row.angle = angle;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_row_get_angle(row: *const ::layout::Row) -> i32 {
 | 
			
		||||
@ -231,57 +133,11 @@ pub mod c {
 | 
			
		||||
        unsafe { Box::from_raw(row) }; // gets dropped
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_button_new(keycode: u32, oref: u32) -> *mut ::layout::Button {
 | 
			
		||||
        let state: Rc<RefCell<::keyboard::KeyState>> = Rc::new(RefCell::new(
 | 
			
		||||
            ::keyboard::KeyState {
 | 
			
		||||
                pressed: false,
 | 
			
		||||
                locked: false,
 | 
			
		||||
                keycode: keycode,
 | 
			
		||||
                symbol: None,
 | 
			
		||||
            }
 | 
			
		||||
        ));
 | 
			
		||||
        Box::into_raw(Box::new(::layout::Button {
 | 
			
		||||
            oref: OutlineRef(oref),
 | 
			
		||||
            bounds: None,
 | 
			
		||||
            state: state,
 | 
			
		||||
        }))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_button_new_with_state(source: *mut ::layout::Button) -> *mut ::layout::Button {
 | 
			
		||||
        let source = unsafe { &*source };
 | 
			
		||||
        let button = Box::new(source.clone());
 | 
			
		||||
        Box::into_raw(button)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_button_get_oref(button: *const ::layout::Button) -> u32 {
 | 
			
		||||
        let button = unsafe { &*button };
 | 
			
		||||
        button.oref.0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Bounds transparently mapped to C, therefore no pointer needed
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_button_get_bounds(button: *const ::layout::Button) -> Bounds {
 | 
			
		||||
        let button = unsafe { &*button };
 | 
			
		||||
        match &button.bounds {
 | 
			
		||||
            Some(bounds) => bounds.clone(),
 | 
			
		||||
            None => panic!("Button doesn't have any bounds yet"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Set bounds by consuming the value
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_button_set_bounds(button: *mut ::layout::Button, bounds: Bounds) {
 | 
			
		||||
        let button = unsafe { &mut *button };
 | 
			
		||||
        button.bounds = Some(bounds);
 | 
			
		||||
        button.bounds.clone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Borrow a new reference to key state. Doesn't need freeing
 | 
			
		||||
@ -302,12 +158,43 @@ pub mod c {
 | 
			
		||||
    ) -> *const Symbol {
 | 
			
		||||
        let button = unsafe { &*button };
 | 
			
		||||
        let state = button.state.borrow();
 | 
			
		||||
        match state.symbol {
 | 
			
		||||
            Some(ref symbol) => symbol as *const Symbol,
 | 
			
		||||
            None => ptr::null(),
 | 
			
		||||
        &state.symbol as *const Symbol
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[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_has_key(
 | 
			
		||||
@ -315,9 +202,8 @@ pub mod c {
 | 
			
		||||
        state: ::keyboard::c::CKeyState,
 | 
			
		||||
    ) -> u32 {
 | 
			
		||||
        let button = unsafe { &*button };
 | 
			
		||||
        let state = state.unwrap();
 | 
			
		||||
        let state = state.clone_ref();
 | 
			
		||||
        let equal = Rc::ptr_eq(&button.state, &state);
 | 
			
		||||
        Rc::into_raw(state); // Prevent dropping
 | 
			
		||||
        equal as u32
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
@ -328,13 +214,34 @@ pub mod c {
 | 
			
		||||
        println!("{:?}", button);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_layout_get_current_view(layout: *const Layout) -> *const View {
 | 
			
		||||
        let layout = unsafe { &*layout };
 | 
			
		||||
        let view_name = layout.current_view.clone();
 | 
			
		||||
        layout.views.get(&view_name)
 | 
			
		||||
            .expect("Current view doesn't exist")
 | 
			
		||||
            .as_ref() as *const View
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_layout_get_keymap(layout: *const Layout) -> *const c_char {
 | 
			
		||||
        let layout = unsafe { &*layout };
 | 
			
		||||
        layout.keymap_str.as_ptr()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_layout_free(layout: *mut Layout) {
 | 
			
		||||
        unsafe { Box::from_raw(layout) };
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /// Entry points for more complex procedures and algoithms which span multiple modules
 | 
			
		||||
    pub mod procedures {
 | 
			
		||||
        use super::*;
 | 
			
		||||
 | 
			
		||||
        #[repr(transparent)]
 | 
			
		||||
        pub struct LevelKeyboard(*const c_void);
 | 
			
		||||
        
 | 
			
		||||
        #[repr(C)]
 | 
			
		||||
        #[derive(PartialEq, Debug)]
 | 
			
		||||
        pub struct ButtonPlace {
 | 
			
		||||
@ -342,13 +249,11 @@ pub mod c {
 | 
			
		||||
            button: *const Button,
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        #[repr(transparent)]
 | 
			
		||||
        pub struct LevelKeyboard(*const c_void);
 | 
			
		||||
 | 
			
		||||
        #[no_mangle]
 | 
			
		||||
        extern "C" {
 | 
			
		||||
            fn eek_get_outline_size(
 | 
			
		||||
                keyboard: *const LevelKeyboard,
 | 
			
		||||
                outline: u32
 | 
			
		||||
            ) -> Bounds;
 | 
			
		||||
 | 
			
		||||
            /// Checks if point falls within bounds,
 | 
			
		||||
            /// which are relative to origin and rotated by angle (I think)
 | 
			
		||||
            pub fn eek_are_bounds_inside (bounds: Bounds,
 | 
			
		||||
@ -356,15 +261,53 @@ pub mod c {
 | 
			
		||||
                origin: Point,
 | 
			
		||||
                angle: i32
 | 
			
		||||
            ) -> u32;
 | 
			
		||||
            
 | 
			
		||||
            pub fn eek_keyboard_set_key_locked(
 | 
			
		||||
                keyboard: *mut LevelKeyboard,
 | 
			
		||||
                key: ::keyboard::c::CKeyState,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        fn squeek_buttons_get_outlines(
 | 
			
		||||
            buttons: &Vec<Box<Button>>,
 | 
			
		||||
            keyboard: *const LevelKeyboard,
 | 
			
		||||
        ) -> Vec<Bounds> {
 | 
			
		||||
            buttons.iter().map(|button| {
 | 
			
		||||
                unsafe { eek_get_outline_size(keyboard, button.oref.0) }
 | 
			
		||||
            }).collect()
 | 
			
		||||
        #[no_mangle]
 | 
			
		||||
        pub extern "C"
 | 
			
		||||
        fn squeek_layout_set_state_from_press(
 | 
			
		||||
            layout: *mut Layout,
 | 
			
		||||
            keyboard: *mut LevelKeyboard,
 | 
			
		||||
            key: ::keyboard::c::CKeyState,
 | 
			
		||||
        ) {
 | 
			
		||||
            let layout = unsafe { &mut *layout };
 | 
			
		||||
 | 
			
		||||
            let view_name = match key.to_owned().symbol.action {
 | 
			
		||||
                ::symbol::Action::SetLevel(name) => {
 | 
			
		||||
                    Some(name.clone())
 | 
			
		||||
                },
 | 
			
		||||
                ::symbol::Action::LockLevel { lock, unlock } => {
 | 
			
		||||
                    let locked = {
 | 
			
		||||
                        let key = key.clone_ref();
 | 
			
		||||
                        let mut key = key.borrow_mut();
 | 
			
		||||
                        key.locked ^= true;
 | 
			
		||||
                        key.locked
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    if locked {
 | 
			
		||||
                        unsafe {
 | 
			
		||||
                            eek_keyboard_set_key_locked(
 | 
			
		||||
                                keyboard,
 | 
			
		||||
                                key
 | 
			
		||||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    Some(if locked { lock } else { unlock }.clone())
 | 
			
		||||
                },
 | 
			
		||||
                _ => None,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            if let Some(view_name) = view_name {
 | 
			
		||||
                if let Err(_e) = layout.set_view(view_name.clone()) {
 | 
			
		||||
                    eprintln!("No such view: {}, ignoring switch", view_name)
 | 
			
		||||
                };
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// Places each button in order, starting from 0 on the left,
 | 
			
		||||
@ -375,17 +318,19 @@ pub mod c {
 | 
			
		||||
        /// Sets button and row sizes according to their contents.
 | 
			
		||||
        #[no_mangle]
 | 
			
		||||
        pub extern "C"
 | 
			
		||||
        fn squeek_view_place_contents(
 | 
			
		||||
            view: *mut ::layout::View,
 | 
			
		||||
            keyboard: *const LevelKeyboard, // source of outlines
 | 
			
		||||
        fn squeek_layout_place_contents(
 | 
			
		||||
            layout: *mut Layout,
 | 
			
		||||
        ) {
 | 
			
		||||
            let view = unsafe { &mut *view };
 | 
			
		||||
            let layout = unsafe { &mut *layout };
 | 
			
		||||
            for view in layout.views.values_mut() {
 | 
			
		||||
                let sizes: Vec<Vec<Bounds>> = view.rows.iter().map(|row| {
 | 
			
		||||
                    row.buttons.iter()
 | 
			
		||||
                        .map(|button| button.bounds.clone())
 | 
			
		||||
                        .collect()
 | 
			
		||||
                }).collect();
 | 
			
		||||
 | 
			
		||||
            let sizes: Vec<Vec<Bounds>> = view.rows.iter().map(|row|
 | 
			
		||||
                squeek_buttons_get_outlines(&row.buttons, keyboard)
 | 
			
		||||
            ).collect();
 | 
			
		||||
 | 
			
		||||
            view.place_buttons_with_sizes(sizes);
 | 
			
		||||
                view.place_buttons_with_sizes(sizes);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn squeek_row_contains(row: &Row, needle: *const Button) -> bool {
 | 
			
		||||
@ -418,13 +363,10 @@ pub mod c {
 | 
			
		||||
            needle: ::keyboard::c::CKeyState,
 | 
			
		||||
        ) -> ButtonPlace {
 | 
			
		||||
            let view = unsafe { &*view };
 | 
			
		||||
            let state = needle.unwrap();
 | 
			
		||||
            let state = needle.clone_ref();
 | 
			
		||||
            
 | 
			
		||||
            let paths = ::layout::procedures::find_key_paths(view, &state);
 | 
			
		||||
 | 
			
		||||
            // Iterators used up, can turn the reference back into pointer
 | 
			
		||||
            Rc::into_raw(state);
 | 
			
		||||
 | 
			
		||||
            // Can only return 1 entry back to C
 | 
			
		||||
            let (row, button) = match paths.get(0) {
 | 
			
		||||
                Some((row, button)) => (
 | 
			
		||||
@ -454,35 +396,36 @@ pub mod c {
 | 
			
		||||
        mod test {
 | 
			
		||||
            use super::*;
 | 
			
		||||
 | 
			
		||||
            use super::super::test::*;
 | 
			
		||||
 | 
			
		||||
            #[test]
 | 
			
		||||
            fn row_has_button() {
 | 
			
		||||
                let mut row = Row::new(0);
 | 
			
		||||
                let button = squeek_row_create_button(&mut row as *mut Row, 0, 0);
 | 
			
		||||
                assert_eq!(squeek_row_contains(&row, button), true);
 | 
			
		||||
                let shared_button = squeek_row_create_button_with_state(
 | 
			
		||||
                    &mut row as *mut Row,
 | 
			
		||||
                    button
 | 
			
		||||
                let state = make_state();
 | 
			
		||||
                let button = make_button_with_state(
 | 
			
		||||
                    "test".into(),
 | 
			
		||||
                    state.clone()
 | 
			
		||||
                );
 | 
			
		||||
                assert_eq!(squeek_row_contains(&row, shared_button), true);
 | 
			
		||||
                let button_ptr = button_as_raw(&button);
 | 
			
		||||
                let mut row = Row::new(0);
 | 
			
		||||
                row.buttons.push(button);
 | 
			
		||||
                assert_eq!(squeek_row_contains(&row, button_ptr), true);
 | 
			
		||||
                let shared_button = make_button_with_state(
 | 
			
		||||
                    "test2".into(),
 | 
			
		||||
                    state
 | 
			
		||||
                );
 | 
			
		||||
                let shared_button_ptr = button_as_raw(&shared_button);
 | 
			
		||||
                row.buttons.push(shared_button);
 | 
			
		||||
                assert_eq!(squeek_row_contains(&row, shared_button_ptr), true);
 | 
			
		||||
                let row = Row::new(0);
 | 
			
		||||
                assert_eq!(squeek_row_contains(&row, button), false);
 | 
			
		||||
                assert_eq!(squeek_row_contains(&row, button_ptr), false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            #[test]
 | 
			
		||||
            fn view_has_button() {
 | 
			
		||||
                let state = Rc::new(RefCell::new(::keyboard::KeyState {
 | 
			
		||||
                    pressed: false,
 | 
			
		||||
                    locked: false,
 | 
			
		||||
                    keycode: 0,
 | 
			
		||||
                    symbol: None,
 | 
			
		||||
                }));
 | 
			
		||||
                let state = make_state();
 | 
			
		||||
                let state_clone = ::keyboard::c::CKeyState::wrap(state.clone());
 | 
			
		||||
 | 
			
		||||
                let button = Box::new(Button {
 | 
			
		||||
                    oref: OutlineRef(0),
 | 
			
		||||
                    bounds: None,
 | 
			
		||||
                    state: state,
 | 
			
		||||
                });
 | 
			
		||||
                let button = make_button_with_state("1".into(), state);
 | 
			
		||||
                let button_ptr = button.as_ref() as *const Button;
 | 
			
		||||
                
 | 
			
		||||
                let row = Box::new(Row {
 | 
			
		||||
@ -536,17 +479,63 @@ pub mod c {
 | 
			
		||||
    mod test {
 | 
			
		||||
        use super::*;
 | 
			
		||||
        
 | 
			
		||||
        use ::keyboard::c::CKeyState;
 | 
			
		||||
 | 
			
		||||
        pub fn make_state() -> Rc<RefCell<::keyboard::KeyState>> {
 | 
			
		||||
            Rc::new(RefCell::new(::keyboard::KeyState {
 | 
			
		||||
                pressed: false,
 | 
			
		||||
                locked: false,
 | 
			
		||||
                keycode: None,
 | 
			
		||||
                symbol: Symbol {
 | 
			
		||||
                    action: Action::SetLevel("default".into()),
 | 
			
		||||
                }
 | 
			
		||||
            }))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub fn make_button_with_state(
 | 
			
		||||
            name: String,
 | 
			
		||||
            state: Rc<RefCell<::keyboard::KeyState>>,
 | 
			
		||||
        ) -> Box<Button> {
 | 
			
		||||
            Box::new(Button {
 | 
			
		||||
                name: CString::new(name.clone()).unwrap(),
 | 
			
		||||
                corner_radius: 0f64,
 | 
			
		||||
                bounds: c::Bounds {
 | 
			
		||||
                    x: 0f64, y: 0f64, width: 0f64, height: 0f64
 | 
			
		||||
                },
 | 
			
		||||
                label: Label::Text(CString::new(name).unwrap()),
 | 
			
		||||
                state: state,
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub fn button_as_raw(button: &Box<Button>) -> *const Button {
 | 
			
		||||
            button.as_ref() as *const Button
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #[test]
 | 
			
		||||
        fn button_has_key() {
 | 
			
		||||
            let button = squeek_button_new(0, 0);
 | 
			
		||||
            let state = squeek_button_get_key(button);
 | 
			
		||||
            assert_eq!(squeek_button_has_key(button, state.clone()), 1);
 | 
			
		||||
            let other_button = squeek_button_new(0, 0);
 | 
			
		||||
            assert_eq!(squeek_button_has_key(other_button, state.clone()), 0);
 | 
			
		||||
            let other_state = ::keyboard::c::squeek_key_new(0);
 | 
			
		||||
            assert_eq!(squeek_button_has_key(button, other_state), 0);
 | 
			
		||||
            let shared_button = squeek_button_new_with_state(button);
 | 
			
		||||
            assert_eq!(squeek_button_has_key(shared_button, state), 1);
 | 
			
		||||
            let state = make_state();
 | 
			
		||||
            let button = make_button_with_state("1".into(), state.clone());
 | 
			
		||||
            assert_eq!(
 | 
			
		||||
                squeek_button_has_key(
 | 
			
		||||
                    button_as_raw(&button),
 | 
			
		||||
                    CKeyState::wrap(state.clone())
 | 
			
		||||
                ),
 | 
			
		||||
                1
 | 
			
		||||
            );
 | 
			
		||||
            let other_state = make_state();
 | 
			
		||||
            let other_button = make_button_with_state("1".into(), other_state);
 | 
			
		||||
            assert_eq!(
 | 
			
		||||
                squeek_button_has_key(
 | 
			
		||||
                    button_as_raw(&other_button),
 | 
			
		||||
                    CKeyState::wrap(state.clone())
 | 
			
		||||
                ),
 | 
			
		||||
                0
 | 
			
		||||
            );
 | 
			
		||||
            let orphan_state = CKeyState::wrap(make_state());
 | 
			
		||||
            assert_eq!(
 | 
			
		||||
                squeek_button_has_key(button_as_raw(&button), orphan_state),
 | 
			
		||||
                0
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -557,13 +546,25 @@ pub struct Size {
 | 
			
		||||
    pub height: f64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, PartialEq)]
 | 
			
		||||
pub enum Label {
 | 
			
		||||
    /// Text used to display the symbol
 | 
			
		||||
    Text(CString),
 | 
			
		||||
    /// Icon name used to render the symbol
 | 
			
		||||
    IconName(CString),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// The graphical representation of a button
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub struct Button {
 | 
			
		||||
    oref: c::OutlineRef,
 | 
			
		||||
    /// TODO: abolish Option, buttons should be created with bounds fully formed
 | 
			
		||||
    /// ID string, e.g. for CSS 
 | 
			
		||||
    pub name: CString,
 | 
			
		||||
    /// Label to display to the user
 | 
			
		||||
    pub label: Label,
 | 
			
		||||
    pub corner_radius: f64,
 | 
			
		||||
    /// TODO: position the buttons before they get initial bounds
 | 
			
		||||
    /// Position relative to some origin (i.e. parent/row)
 | 
			
		||||
    bounds: Option<c::Bounds>,
 | 
			
		||||
    pub bounds: c::Bounds,
 | 
			
		||||
    /// current state, shared with other buttons
 | 
			
		||||
    pub state: Rc<RefCell<KeyState>>,
 | 
			
		||||
}
 | 
			
		||||
@ -574,11 +575,11 @@ const ROW_SPACING: f64 = 7.0;
 | 
			
		||||
 | 
			
		||||
/// The graphical representation of a row of buttons
 | 
			
		||||
pub struct Row {
 | 
			
		||||
    buttons: Vec<Box<Button>>,
 | 
			
		||||
    pub buttons: Vec<Box<Button>>,
 | 
			
		||||
    /// Angle is not really used anywhere...
 | 
			
		||||
    angle: i32,
 | 
			
		||||
    pub angle: i32,
 | 
			
		||||
    /// Position relative to some origin (i.e. parent/view origin)
 | 
			
		||||
    bounds: Option<c::Bounds>,
 | 
			
		||||
    pub bounds: Option<c::Bounds>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Row {
 | 
			
		||||
@ -639,9 +640,7 @@ impl Row {
 | 
			
		||||
        };
 | 
			
		||||
        let angle = self.angle;
 | 
			
		||||
        self.buttons.iter_mut().find(|button| {
 | 
			
		||||
            let bounds = button.bounds
 | 
			
		||||
                .as_ref().expect("Missing bounds on button")
 | 
			
		||||
                .clone();
 | 
			
		||||
            let bounds = button.bounds.clone();
 | 
			
		||||
            let point = point.clone();
 | 
			
		||||
            let origin = origin.clone();
 | 
			
		||||
            procedures::is_point_inside(bounds, point, origin, angle)
 | 
			
		||||
@ -651,8 +650,8 @@ impl Row {
 | 
			
		||||
 | 
			
		||||
pub struct View {
 | 
			
		||||
    /// Position relative to keyboard origin
 | 
			
		||||
    bounds: c::Bounds,
 | 
			
		||||
    rows: Vec<Box<Row>>,
 | 
			
		||||
    pub bounds: c::Bounds,
 | 
			
		||||
    pub rows: Vec<Box<Row>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl View {
 | 
			
		||||
@ -704,7 +703,7 @@ impl View {
 | 
			
		||||
            for (mut button, button_position)
 | 
			
		||||
                in row.buttons.iter_mut()
 | 
			
		||||
                    .zip(button_positions) {
 | 
			
		||||
                button.bounds = Some(button_position);
 | 
			
		||||
                button.bounds = button_position;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -727,6 +726,26 @@ impl View {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Layout {
 | 
			
		||||
    pub current_view: String,
 | 
			
		||||
    pub views: HashMap<String, Box<View>>,
 | 
			
		||||
    // TODO: move to ::keyboard::Keyboard
 | 
			
		||||
    pub keymap_str: CString,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct NoSuchView;
 | 
			
		||||
 | 
			
		||||
impl Layout {
 | 
			
		||||
    fn set_view(&mut self, view: String) -> Result<(), NoSuchView> {
 | 
			
		||||
        if self.views.contains_key(&view) {
 | 
			
		||||
            self.current_view = view;
 | 
			
		||||
            Ok(())
 | 
			
		||||
        } else {
 | 
			
		||||
            Err(NoSuchView)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mod procedures {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/lib.rs
									
									
									
									
									
								
							@ -1,9 +1,16 @@
 | 
			
		||||
#[macro_use]
 | 
			
		||||
mod bitflags;
 | 
			
		||||
extern crate bitflags;
 | 
			
		||||
#[macro_use]
 | 
			
		||||
extern crate maplit;
 | 
			
		||||
extern crate serde;
 | 
			
		||||
extern crate xkbcommon;
 | 
			
		||||
 | 
			
		||||
mod float_ord;
 | 
			
		||||
mod imservice;
 | 
			
		||||
pub mod data;
 | 
			
		||||
pub mod float_ord;
 | 
			
		||||
pub mod imservice;
 | 
			
		||||
mod keyboard;
 | 
			
		||||
mod layout;
 | 
			
		||||
mod resources;
 | 
			
		||||
mod symbol;
 | 
			
		||||
mod util;
 | 
			
		||||
mod xdg;
 | 
			
		||||
 | 
			
		||||
@ -20,16 +20,13 @@ sources = [
 | 
			
		||||
  '../eek/eek-gtk-keyboard.c',
 | 
			
		||||
  '../eek/eek-keyboard.c',
 | 
			
		||||
  '../eek/eek-keyboard-drawing.c',
 | 
			
		||||
  '../eek/eek-keysym.c',
 | 
			
		||||
  '../eek/eek-layout.c',
 | 
			
		||||
  '../eek/eek-renderer.c',
 | 
			
		||||
  '../eek/eek-section.c',
 | 
			
		||||
  '../eek/eek-types.c',
 | 
			
		||||
  '../eek/eek-xml-layout.c',
 | 
			
		||||
  '../eek/layersurface.c',
 | 
			
		||||
  dbus_src,
 | 
			
		||||
  enums,
 | 
			
		||||
  keysym_entries,
 | 
			
		||||
  '../eekboard/key-emitter.c',
 | 
			
		||||
  '../eekboard/eekboard-context-service.c',
 | 
			
		||||
  '../eekboard/eekboard-context.c',
 | 
			
		||||
@ -56,25 +53,25 @@ deps = [
 | 
			
		||||
#  dependency('libxklavier'), # FIXME remove
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# Replacement for eekboard-server
 | 
			
		||||
rslib = static_library(
 | 
			
		||||
  'rslib',
 | 
			
		||||
  sources: ['lib.rs'],
 | 
			
		||||
  rust_crate_type: 'staticlib'
 | 
			
		||||
rslibs = custom_target(
 | 
			
		||||
    'rslibs',
 | 
			
		||||
    build_by_default: true,
 | 
			
		||||
    build_always_stale: true,
 | 
			
		||||
    output: ['librs.a'],
 | 
			
		||||
    install: false,
 | 
			
		||||
    console: true,
 | 
			
		||||
    command: [cargo_script, '@CURRENT_SOURCE_DIR@', '@OUTPUT@', 'build']
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
rstests = executable(
 | 
			
		||||
  'rstests',
 | 
			
		||||
  sources: ['lib.rs'],
 | 
			
		||||
  rust_args: ['--test'],
 | 
			
		||||
  install: false
 | 
			
		||||
test(
 | 
			
		||||
    'rstest',
 | 
			
		||||
    cargo_script,
 | 
			
		||||
    args: [meson.source_root(), '', 'test']
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
test('rstests', rstests)
 | 
			
		||||
 | 
			
		||||
libsqueekboard = static_library('libsqueekboard',
 | 
			
		||||
  sources,
 | 
			
		||||
  link_with: rslib,
 | 
			
		||||
  link_with: [rslibs],
 | 
			
		||||
  include_directories: [include_directories('..'), include_directories('../eek')],
 | 
			
		||||
  dependencies: deps,
 | 
			
		||||
  c_args: [
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										24
									
								
								src/resources.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/resources.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
/*! Statically linked resources.
 | 
			
		||||
 * This could be done using GResource, but that would need additional work.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const KEYBOARDS: &[(*const str, *const str)] = &[
 | 
			
		||||
    ("us", include_str!("../data/keyboards/us.yaml")),
 | 
			
		||||
    ("nb", include_str!("../data/keyboards/nb.yaml")),
 | 
			
		||||
    ("number", include_str!("../data/keyboards/number.yaml")),
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
pub fn get_keyboard(needle: &str) -> Option<&'static str> {
 | 
			
		||||
    // Need to dereference in unsafe code
 | 
			
		||||
    // comparing *const str to &str will compare pointers
 | 
			
		||||
    KEYBOARDS.iter()
 | 
			
		||||
        .find(|(name, _)| {
 | 
			
		||||
            let name: *const str = *name;
 | 
			
		||||
            (unsafe { &*name }) == needle
 | 
			
		||||
        })
 | 
			
		||||
        .map(|(_, value)| {
 | 
			
		||||
            let value: *const str = *value;
 | 
			
		||||
            unsafe { &*value }
 | 
			
		||||
        })
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								src/symbol.h
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								src/symbol.h
									
									
									
									
									
								
							@ -1,24 +0,0 @@
 | 
			
		||||
#ifndef __SYMBOL_H
 | 
			
		||||
#define __SYMBOL_H
 | 
			
		||||
 | 
			
		||||
#include "stdbool.h"
 | 
			
		||||
#include "inttypes.h"
 | 
			
		||||
// Defined in Rust
 | 
			
		||||
 | 
			
		||||
struct squeek_symbol;
 | 
			
		||||
struct squeek_symbols;
 | 
			
		||||
 | 
			
		||||
void squeek_symbols_add(struct squeek_symbols*,
 | 
			
		||||
                        const char *element_name,
 | 
			
		||||
                        const char *text, uint32_t keyval,
 | 
			
		||||
                        const char *label, const char *icon,
 | 
			
		||||
                        const char *tooltip);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const char *squeek_symbol_get_name(struct squeek_symbol* symbol);
 | 
			
		||||
const char *squeek_symbol_get_label(struct squeek_symbol* symbol);
 | 
			
		||||
const char *squeek_symbol_get_icon_name(struct squeek_symbol* symbol);
 | 
			
		||||
uint32_t squeek_symbol_get_modifier_mask(struct squeek_symbol* symbol);
 | 
			
		||||
 | 
			
		||||
void squeek_symbol_print(struct squeek_symbol* symbol);
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										128
									
								
								src/symbol.rs
									
									
									
									
									
								
							
							
						
						
									
										128
									
								
								src/symbol.rs
									
									
									
									
									
								
							@ -1,138 +1,46 @@
 | 
			
		||||
/*! The symbol object, defining actions that the key can do when activated */
 | 
			
		||||
 | 
			
		||||
use std::ffi::CString;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// Gathers stuff defined in C or called by C
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    
 | 
			
		||||
    use std::ffi::CStr;
 | 
			
		||||
    use std::os::raw::c_char;
 | 
			
		||||
    use std::ptr;
 | 
			
		||||
    
 | 
			
		||||
    // The following defined in C
 | 
			
		||||
    
 | 
			
		||||
    // Legacy; Will never be used in Rust as a bit field
 | 
			
		||||
    enum ModifierMask {
 | 
			
		||||
        Nothing = 0,
 | 
			
		||||
        Shift = 1,
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // The following defined in Rust.
 | 
			
		||||
    
 | 
			
		||||
    // TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
 | 
			
		||||
    // Symbols are owned by Rust and will move towards no C manipulation, so it may make sense not to wrap them
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_symbol_get_name(symbol: *const Symbol) -> *const c_char {
 | 
			
		||||
        let symbol = unsafe { &*symbol };
 | 
			
		||||
        match &symbol.action {
 | 
			
		||||
            Action::Submit { text: Some(text), .. } => text.as_ptr(),
 | 
			
		||||
            _ => ptr::null(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_symbol_get_label(symbol: *const Symbol) -> *const c_char {
 | 
			
		||||
        let symbol = unsafe { &*symbol };
 | 
			
		||||
        match &symbol.label {
 | 
			
		||||
            Label::Text(text) => text.as_ptr(),
 | 
			
		||||
            // returning static strings to C is a bit cumbersome
 | 
			
		||||
            Label::IconName(_) => unsafe {
 | 
			
		||||
                CStr::from_bytes_with_nul_unchecked(b"icon\0")
 | 
			
		||||
            }.as_ptr(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_symbol_get_icon_name(symbol: *const Symbol) -> *const c_char {
 | 
			
		||||
        let symbol = unsafe { &*symbol };
 | 
			
		||||
        match &symbol.label {
 | 
			
		||||
            Label::Text(_) => ptr::null(),
 | 
			
		||||
            Label::IconName(name) => name.as_ptr(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Legacy; throw away
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_symbol_get_modifier_mask(symbol: *const Symbol) -> u32 {
 | 
			
		||||
        let symbol = unsafe { &*symbol };
 | 
			
		||||
        (match &symbol.action {
 | 
			
		||||
            Action::SetLevel(1) => ModifierMask::Shift,
 | 
			
		||||
            _ => ModifierMask::Nothing,
 | 
			
		||||
        }) as u32
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_symbol_print(symbol: *const Symbol) {
 | 
			
		||||
        let symbol = unsafe { &*symbol };
 | 
			
		||||
        println!("{:?}", symbol);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Just defines some int->identifier mappings for convenience
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub enum KeySym {
 | 
			
		||||
    Unknown = 0,
 | 
			
		||||
    Shift = 0xffe1,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl KeySym {
 | 
			
		||||
    pub fn from_u32(num: u32) -> KeySym {
 | 
			
		||||
        match num {
 | 
			
		||||
            0xffe1 => KeySym::Shift,
 | 
			
		||||
            _ => KeySym::Unknown,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct XKeySym(pub u32);
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub enum Label {
 | 
			
		||||
    /// Text used to display the symbol
 | 
			
		||||
    Text(CString),
 | 
			
		||||
    /// Icon name used to render the symbol
 | 
			
		||||
    IconName(CString),
 | 
			
		||||
}
 | 
			
		||||
/// Name of the keysym
 | 
			
		||||
#[derive(Debug, Clone, PartialEq)]
 | 
			
		||||
pub struct KeySym(pub String);
 | 
			
		||||
 | 
			
		||||
/// Use to switch layouts
 | 
			
		||||
type Level = u8;
 | 
			
		||||
type Level = String;
 | 
			
		||||
 | 
			
		||||
/// Use to send modified keypresses
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
#[derive(Debug, Clone, PartialEq)]
 | 
			
		||||
pub enum Modifier {
 | 
			
		||||
    Control,
 | 
			
		||||
    Alt,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Action to perform on the keypress and, in reverse, on keyrelease
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
#[derive(Debug, Clone, PartialEq)]
 | 
			
		||||
pub enum Action {
 | 
			
		||||
    /// Switch to this level TODO: reverse?
 | 
			
		||||
    /// Switch to this view
 | 
			
		||||
    SetLevel(Level),
 | 
			
		||||
    /// Switch to a view and latch
 | 
			
		||||
    LockLevel {
 | 
			
		||||
        lock: Level,
 | 
			
		||||
        /// When unlocked by pressing it or emitting a key
 | 
			
		||||
        unlock: Level,
 | 
			
		||||
    },
 | 
			
		||||
    /// Set this modifier TODO: release?
 | 
			
		||||
    SetModifier(Modifier),
 | 
			
		||||
    /// Submit some text
 | 
			
		||||
    Submit {
 | 
			
		||||
        /// orig: Canonical name of the symbol
 | 
			
		||||
        /// Text to submit with input-method
 | 
			
		||||
        text: Option<CString>,
 | 
			
		||||
        /// The key events this symbol submits when submitting text is not possible
 | 
			
		||||
        keys: Vec<XKeySym>,
 | 
			
		||||
        keys: Vec<KeySym>,
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Contains a static description of a particular key's actions
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
#[derive(Debug, Clone, PartialEq)]
 | 
			
		||||
pub struct Symbol {
 | 
			
		||||
    /// The action that this key performs
 | 
			
		||||
    pub action: Action,
 | 
			
		||||
    /// Label to display to the user
 | 
			
		||||
    pub label: Label,
 | 
			
		||||
    // FIXME: is it used?
 | 
			
		||||
    pub tooltip: Option<CString>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										55
									
								
								src/util.rs
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								src/util.rs
									
									
									
									
									
								
							@ -1,9 +1,14 @@
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use std::cell::RefCell;
 | 
			
		||||
    use std::ffi::{ CStr, CString };
 | 
			
		||||
    use std::os::raw::c_char;
 | 
			
		||||
    use std::rc::Rc;
 | 
			
		||||
    use std::str::Utf8Error;
 | 
			
		||||
 | 
			
		||||
    #[allow(dead_code)]
 | 
			
		||||
    // traits
 | 
			
		||||
    
 | 
			
		||||
    use std::borrow::ToOwned;
 | 
			
		||||
    
 | 
			
		||||
    pub fn as_str(s: &*const c_char) -> Result<Option<&str>, Utf8Error> {
 | 
			
		||||
        if s.is_null() {
 | 
			
		||||
            Ok(None)
 | 
			
		||||
@ -47,4 +52,52 @@ pub mod c {
 | 
			
		||||
            assert_eq!(as_str(&ptr::null()), Ok(None))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Wraps structures to pass them safely to/from C
 | 
			
		||||
    /// Since C doesn't respect borrowing rules,
 | 
			
		||||
    /// RefCell will enforce them dynamically (only 1 writer/many readers)
 | 
			
		||||
    /// Rc is implied and will ensure timely dropping
 | 
			
		||||
    #[repr(transparent)]
 | 
			
		||||
    pub struct Wrapped<T: Clone>(*const RefCell<T>);
 | 
			
		||||
 | 
			
		||||
    // It would be nice to implement `Borrow`
 | 
			
		||||
    // directly on the raw pointer to avoid one conversion call,
 | 
			
		||||
    // but the `borrow()` call needs to extract a `Rc`,
 | 
			
		||||
    // and at the same time return a reference to it (`std::cell::Ref`)
 | 
			
		||||
    // to take advantage of `Rc<RefCell>::borrow()` runtime checks.
 | 
			
		||||
    // Unfortunately, that needs a `Ref` struct with self-referential fields,
 | 
			
		||||
    // which is a bit too complex for now.
 | 
			
		||||
 | 
			
		||||
    impl<T: Clone> Wrapped<T> {
 | 
			
		||||
        pub fn wrap(state: Rc<RefCell<T>>) -> Wrapped<T> {
 | 
			
		||||
            Wrapped(Rc::into_raw(state))
 | 
			
		||||
        }
 | 
			
		||||
        /// Extracts the reference to the data.
 | 
			
		||||
        /// It may cause problems if attempted in more than one place
 | 
			
		||||
        pub unsafe fn unwrap(self) -> Rc<RefCell<T>> {
 | 
			
		||||
            Rc::from_raw(self.0)
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /// Creates a new Rc reference to the same data
 | 
			
		||||
        pub fn clone_ref(&self) -> Rc<RefCell<T>> {
 | 
			
		||||
            // A bit dangerous: the Rc may be in use elsewhere
 | 
			
		||||
            let used_rc = unsafe { Rc::from_raw(self.0) };
 | 
			
		||||
            let rc = used_rc.clone();
 | 
			
		||||
            Rc::into_raw(used_rc); // prevent dropping the original reference
 | 
			
		||||
            rc
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// Create a copy of the underlying data
 | 
			
		||||
        pub fn to_owned(&self) -> T {
 | 
			
		||||
            let rc = self.clone_ref();
 | 
			
		||||
            let r = rc.borrow();
 | 
			
		||||
            r.to_owned()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    impl<T: Clone> Clone for Wrapped<T> {
 | 
			
		||||
        fn clone(&self) -> Wrapped<T> {
 | 
			
		||||
            Wrapped::wrap(self.clone_ref())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										63
									
								
								src/xdg.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/xdg.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,63 @@
 | 
			
		||||
/*! XDG directory handling. */
 | 
			
		||||
 | 
			
		||||
/* Based on dirs-sys https://github.com/soc/dirs-sys-rs
 | 
			
		||||
 * by "Simon Ochsenreither <simon@ochsenreither.de>",
 | 
			
		||||
 * Licensed under either of
 | 
			
		||||
 | 
			
		||||
    Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
 | 
			
		||||
    MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
 | 
			
		||||
 | 
			
		||||
at your option.
 | 
			
		||||
 * 
 | 
			
		||||
 * Based on dirs https://github.com/soc/dirs-rs
 | 
			
		||||
 * by "Simon Ochsenreither <simon@ochsenreither.de>",
 | 
			
		||||
 * Licensed under either of
 | 
			
		||||
 | 
			
		||||
    Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
 | 
			
		||||
    MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
 | 
			
		||||
 | 
			
		||||
at your option.
 | 
			
		||||
 * 
 | 
			
		||||
 * Based on xdg https://github.com/whitequark/rust-xdg
 | 
			
		||||
 * by "Ben Longbons <b.r.longbons@gmail.com>",
 | 
			
		||||
 *    "whitequark <whitequark@whitequark.org>",
 | 
			
		||||
rust-xdg is distributed under the terms of both the MIT license and the Apache License (Version 2.0).
 | 
			
		||||
 * 
 | 
			
		||||
 * The above crates were used to get
 | 
			
		||||
 * a version without all the excessive dependencies.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
use std::env;
 | 
			
		||||
use std::ffi::OsString;
 | 
			
		||||
use std::path::{ Path, PathBuf };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
fn is_absolute_path(path: OsString) -> Option<PathBuf> {
 | 
			
		||||
    let path = PathBuf::from(path);
 | 
			
		||||
    if path.is_absolute() {
 | 
			
		||||
        Some(path)
 | 
			
		||||
    } else {
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn home_dir() -> Option<PathBuf> {
 | 
			
		||||
    return env::var_os("HOME")
 | 
			
		||||
        .and_then(|h| if h.is_empty() { None } else { Some(h) })
 | 
			
		||||
        .map(PathBuf::from);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn data_dir() -> Option<PathBuf> {
 | 
			
		||||
    env::var_os("XDG_DATA_HOME")
 | 
			
		||||
        .and_then(is_absolute_path)
 | 
			
		||||
        .or_else(|| home_dir().map(|h| h.join(".local/share")))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Returns the path to the directory within the data dir
 | 
			
		||||
pub fn data_path<P>(path: P) -> Option<PathBuf>
 | 
			
		||||
    where P: AsRef<Path>
 | 
			
		||||
{
 | 
			
		||||
    data_dir().map(|dir| {
 | 
			
		||||
        dir.join(path.as_ref())
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
@ -1,45 +0,0 @@
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
 | 
			
		||||
 * Copyright (C) 2010-2011 Red Hat, Inc.
 | 
			
		||||
 * 
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public License
 | 
			
		||||
 * as published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 * the License, or (at your option) any later version.
 | 
			
		||||
 * 
 | 
			
		||||
 * This library is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 * 
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
#include "eek/eek.h"
 | 
			
		||||
 | 
			
		||||
#include <gtk/gtk.h>
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
test_create (void)
 | 
			
		||||
{
 | 
			
		||||
    EekBounds bounds = {0};
 | 
			
		||||
    struct squeek_view *view = squeek_view_new(bounds);
 | 
			
		||||
    struct squeek_button *button0, *button1;
 | 
			
		||||
 | 
			
		||||
    struct squeek_row *row = squeek_view_create_row (view, 0);
 | 
			
		||||
    g_assert (row);
 | 
			
		||||
    button0 = squeek_row_create_button (row, 1, 0);
 | 
			
		||||
    g_assert (button0);
 | 
			
		||||
    button1 = squeek_row_create_button (row, 2, 0);
 | 
			
		||||
    g_assert (button1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main (int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
    g_test_init (&argc, &argv, NULL);
 | 
			
		||||
    g_test_add_func ("/eek-simple-test/create", test_create);
 | 
			
		||||
    return g_test_run ();
 | 
			
		||||
}
 | 
			
		||||
@ -1,55 +0,0 @@
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
 | 
			
		||||
 * Copyright (C) 2010-2011 Red Hat, Inc.
 | 
			
		||||
 * 
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public License
 | 
			
		||||
 * as published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 * the License, or (at your option) any later version.
 | 
			
		||||
 * 
 | 
			
		||||
 * This library is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 * 
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* For gdk_x11_display_get_xdisplay().  See main(). */
 | 
			
		||||
#include <gtk/gtk.h>
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "eek/eek.h"
 | 
			
		||||
#include "eek/eek-xml-layout.h"
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
test_output_parse (void)
 | 
			
		||||
{
 | 
			
		||||
    EekLayout *layout;
 | 
			
		||||
    LevelKeyboard *keyboard;
 | 
			
		||||
    GError *error;
 | 
			
		||||
 | 
			
		||||
    error = NULL;
 | 
			
		||||
    layout = eek_xml_layout_new ("us", &error);
 | 
			
		||||
    g_assert_no_error (error);
 | 
			
		||||
 | 
			
		||||
    /* We don't need the context service to parse an XML file, so we can pass
 | 
			
		||||
       NULL when creating a keyboard. */
 | 
			
		||||
    keyboard = eek_xml_layout_real_create_keyboard(layout, NULL);
 | 
			
		||||
    g_object_unref (layout);
 | 
			
		||||
    level_keyboard_free(keyboard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main (int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
    g_test_init (&argc, &argv, NULL);
 | 
			
		||||
 | 
			
		||||
    g_test_add_func ("/eek-xml-test/output-parse", test_output_parse);
 | 
			
		||||
 | 
			
		||||
    return g_test_run ();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								tests/entry.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								tests/entry.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
import gi
 | 
			
		||||
import sys
 | 
			
		||||
gi.require_version('Gtk', '3.0')
 | 
			
		||||
 | 
			
		||||
from gi.repository import Gtk
 | 
			
		||||
 | 
			
		||||
class App(Gtk.Application):
 | 
			
		||||
 | 
			
		||||
    purposes = [
 | 
			
		||||
        ("Free form", Gtk.InputPurpose.FREE_FORM),
 | 
			
		||||
        ("Alphabetical", Gtk.InputPurpose.ALPHA),
 | 
			
		||||
        ("Digits", Gtk.InputPurpose.DIGITS),
 | 
			
		||||
        ("Number", Gtk.InputPurpose.NUMBER),
 | 
			
		||||
        ("Phone", Gtk.InputPurpose.PHONE),
 | 
			
		||||
        ("URL", Gtk.InputPurpose.URL),
 | 
			
		||||
        ("E-mail", Gtk.InputPurpose.EMAIL),
 | 
			
		||||
        ("Name", Gtk.InputPurpose.NAME),
 | 
			
		||||
        ("Password", Gtk.InputPurpose.PASSWORD),
 | 
			
		||||
        ("PIN", Gtk.InputPurpose.PIN)
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def do_activate(self):
 | 
			
		||||
        w = Gtk.ApplicationWindow(application=self)
 | 
			
		||||
        grid = Gtk.Grid(orientation='vertical', column_spacing=8, row_spacing=8)
 | 
			
		||||
        i = 0
 | 
			
		||||
        for text, purpose in self.purposes:
 | 
			
		||||
 | 
			
		||||
            l = Gtk.Label(label=text)
 | 
			
		||||
            e = Gtk.Entry(hexpand=True)
 | 
			
		||||
            e.set_input_purpose(purpose)
 | 
			
		||||
            grid.attach(l, 0, i, 1, 1)
 | 
			
		||||
            grid.attach(e, 1, i, 1, 1)
 | 
			
		||||
            i += 1
 | 
			
		||||
 | 
			
		||||
        w.add(grid)
 | 
			
		||||
        w.show_all()
 | 
			
		||||
 | 
			
		||||
app = App()
 | 
			
		||||
app.run(sys.argv)
 | 
			
		||||
							
								
								
									
										17
									
								
								tests/layout.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								tests/layout.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
---
 | 
			
		||||
bounds:
 | 
			
		||||
    x: 0
 | 
			
		||||
    y: 0
 | 
			
		||||
    width: 0
 | 
			
		||||
    height: 0
 | 
			
		||||
views:
 | 
			
		||||
    base:
 | 
			
		||||
        - "test"
 | 
			
		||||
outlines:
 | 
			
		||||
    default:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 0, height: 0 }
 | 
			
		||||
 | 
			
		||||
buttons:
 | 
			
		||||
    test:
 | 
			
		||||
        label: "test"
 | 
			
		||||
							
								
								
									
										12
									
								
								tests/layout2.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								tests/layout2.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
---
 | 
			
		||||
# missing views
 | 
			
		||||
bounds:
 | 
			
		||||
    x: 0
 | 
			
		||||
    y: 0
 | 
			
		||||
    width: 0
 | 
			
		||||
    height: 0
 | 
			
		||||
outlines:
 | 
			
		||||
    default:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 0, height: 0 }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								tests/layout3.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								tests/layout3.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
---
 | 
			
		||||
# extra field
 | 
			
		||||
bounds:
 | 
			
		||||
    x: 0
 | 
			
		||||
    y: 0
 | 
			
		||||
    width: 0
 | 
			
		||||
    height: 0
 | 
			
		||||
views:
 | 
			
		||||
    base:
 | 
			
		||||
        - "test"
 | 
			
		||||
outlines:
 | 
			
		||||
    default:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 0, height: 0 }
 | 
			
		||||
 | 
			
		||||
bad_field: false
 | 
			
		||||
							
								
								
									
										18
									
								
								tests/layout_key1.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								tests/layout_key1.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
---
 | 
			
		||||
# punctuation
 | 
			
		||||
bounds:
 | 
			
		||||
    x: 0
 | 
			
		||||
    y: 0
 | 
			
		||||
    width: 0
 | 
			
		||||
    height: 0
 | 
			
		||||
views:
 | 
			
		||||
    base:
 | 
			
		||||
        - "."
 | 
			
		||||
outlines:
 | 
			
		||||
    default:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 0, height: 0 }
 | 
			
		||||
 | 
			
		||||
buttons:
 | 
			
		||||
    ".":
 | 
			
		||||
        label: "test"
 | 
			
		||||
							
								
								
									
										18
									
								
								tests/layout_key2.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								tests/layout_key2.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
---
 | 
			
		||||
# punctuation
 | 
			
		||||
bounds:
 | 
			
		||||
    x: 0
 | 
			
		||||
    y: 0
 | 
			
		||||
    width: 0
 | 
			
		||||
    height: 0
 | 
			
		||||
views:
 | 
			
		||||
    base:
 | 
			
		||||
        - "å"
 | 
			
		||||
outlines:
 | 
			
		||||
    default:
 | 
			
		||||
        corner_radius: 1
 | 
			
		||||
        bounds: { x: 0, y: 0, width: 0, height: 0 }
 | 
			
		||||
 | 
			
		||||
buttons:
 | 
			
		||||
    å:
 | 
			
		||||
        label: "test"
 | 
			
		||||
@ -19,13 +19,10 @@ test_link_args = [
 | 
			
		||||
  '-fPIC',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
tests = [
 | 
			
		||||
  'eek-simple-test',
 | 
			
		||||
  'eek-xml-test',
 | 
			
		||||
  'test-keymap-generation'
 | 
			
		||||
c_tests = [
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
foreach name : tests
 | 
			
		||||
foreach name : c_tests
 | 
			
		||||
 | 
			
		||||
    test_sources = [name + '.c']
 | 
			
		||||
 | 
			
		||||
@ -47,4 +44,15 @@ foreach name : tests
 | 
			
		||||
 | 
			
		||||
endforeach
 | 
			
		||||
 | 
			
		||||
# The layout test is in the examples directory
 | 
			
		||||
# due to the way Cargo builds executables
 | 
			
		||||
# and the need to call it manually
 | 
			
		||||
foreach layout : ['us', 'nb', 'number']
 | 
			
		||||
    test(
 | 
			
		||||
        'test_layout_' + layout,
 | 
			
		||||
        cargo_script,
 | 
			
		||||
        args: [meson.source_root(), '', 'run', '--example', 'test_layout', layout]
 | 
			
		||||
    )
 | 
			
		||||
endforeach
 | 
			
		||||
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
@ -1,72 +0,0 @@
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
 | 
			
		||||
 * Copyright (C) 2010-2011 Red Hat, Inc.
 | 
			
		||||
 * Copyright (C) 2019 Purism SPC
 | 
			
		||||
 * 
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public License
 | 
			
		||||
 * as published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 * the License, or (at your option) any later version.
 | 
			
		||||
 * 
 | 
			
		||||
 * This library is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 * 
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* For gdk_x11_display_get_xdisplay().  See main(). */
 | 
			
		||||
#include <gtk/gtk.h>
 | 
			
		||||
#include <xkbcommon/xkbcommon.h>
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "eek/eek.h"
 | 
			
		||||
#include "eek/eek-xml-layout.h"
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
test_check_xkb (void)
 | 
			
		||||
{
 | 
			
		||||
    EekLayout *layout;
 | 
			
		||||
    LevelKeyboard *keyboard;
 | 
			
		||||
    GError *error;
 | 
			
		||||
 | 
			
		||||
    error = NULL;
 | 
			
		||||
    layout = eek_xml_layout_new ("us", &error);
 | 
			
		||||
    g_assert_no_error (error);
 | 
			
		||||
 | 
			
		||||
    keyboard = eek_xml_layout_real_create_keyboard(layout, NULL);
 | 
			
		||||
    gchar *keymap_str = eek_keyboard_get_keymap(keyboard);
 | 
			
		||||
 | 
			
		||||
    struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
 | 
			
		||||
    if (!context) {
 | 
			
		||||
        g_error("No context created");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct xkb_keymap *keymap = xkb_keymap_new_from_string(context, keymap_str,
 | 
			
		||||
        XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
 | 
			
		||||
 | 
			
		||||
    free(keymap_str);
 | 
			
		||||
 | 
			
		||||
    xkb_context_unref(context);
 | 
			
		||||
    if (!keymap) {
 | 
			
		||||
        g_error("Bad keymap");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_object_unref (layout);
 | 
			
		||||
    level_keyboard_free(keyboard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main (int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
    g_test_init (&argc, &argv, NULL);
 | 
			
		||||
 | 
			
		||||
    g_test_add_func ("/test-keymap-generation/check-xkb", test_check_xkb);
 | 
			
		||||
 | 
			
		||||
    return g_test_run ();
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user