Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0e2def7069 | |||
| aa5e1d87dd | |||
| 0a0f7a09a4 | |||
| 9ef38ecf30 |
@ -9,10 +9,6 @@ stages:
|
|||||||
- librem5
|
- librem5
|
||||||
|
|
||||||
before_script:
|
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 update
|
||||||
- apt-get -y build-dep .
|
- apt-get -y build-dep .
|
||||||
|
|
||||||
@ -26,26 +22,6 @@ build_meson:
|
|||||||
- meson . _build/ -Ddepdatadir=/usr/share
|
- meson . _build/ -Ddepdatadir=/usr/share
|
||||||
- ninja -C _build install
|
- 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:
|
test:
|
||||||
<<: *tags
|
<<: *tags
|
||||||
stage: test
|
stage: test
|
||||||
|
|||||||
162
Cargo.lock
generated
162
Cargo.lock
generated
@ -1,162 +0,0 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.0.4"
|
|
||||||
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.0.4 (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.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
|
||||||
"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
15
Cargo.toml
@ -1,15 +0,0 @@
|
|||||||
[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
58
HACKING.md
@ -1,58 +0,0 @@
|
|||||||
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 '' 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 '' update
|
|
||||||
ninja test
|
|
||||||
```
|
|
||||||
29
README.md
29
README.md
@ -3,18 +3,14 @@
|
|||||||
|
|
||||||
*Squeekboard* is a virtual keyboard supporting Wayland, built primarily for the *Librem 5* phone.
|
*Squeekboard* is a virtual keyboard supporting Wayland, built primarily for the *Librem 5* phone.
|
||||||
|
|
||||||
It squeaks because some Rust got inside.
|
|
||||||
|
|
||||||
Features
|
Features
|
||||||
--------
|
--------
|
||||||
|
|
||||||
### Present
|
### Present
|
||||||
|
|
||||||
- GTK3
|
- GTK3
|
||||||
- Custom yaml-defined keyboards
|
- Custom xml-defined keyboards
|
||||||
- DBus interface to show and hide
|
- DBus interface to show and hide
|
||||||
- Use Wayland input method protocol to show and hide
|
|
||||||
- Use Wayland virtual keyboard protocol
|
|
||||||
|
|
||||||
### Temporarily dropped
|
### Temporarily dropped
|
||||||
|
|
||||||
@ -22,6 +18,8 @@ Features
|
|||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
|
|
||||||
|
- Use Wayland virtual keyboard protocol
|
||||||
|
- Use Wayland text input protocol
|
||||||
- Use Wayland input method protocol
|
- Use Wayland input method protocol
|
||||||
- Pick up DBus interface files from /usr/share
|
- Pick up DBus interface files from /usr/share
|
||||||
|
|
||||||
@ -40,20 +38,31 @@ $ cd squeekboard
|
|||||||
$ mkdir ../build
|
$ mkdir ../build
|
||||||
$ meson ../build/
|
$ meson ../build/
|
||||||
$ cd ../build
|
$ cd ../build
|
||||||
$ ninja test
|
|
||||||
$ ninja install
|
$ 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
|
Running
|
||||||
-------
|
-------
|
||||||
|
|
||||||
```
|
```
|
||||||
$ phoc # if no compatible Wayland compositor is running yet
|
$ rootston
|
||||||
$ cd ../build/
|
$ cd ../build/
|
||||||
$ src/squeekboard
|
$ src/squeekboard
|
||||||
```
|
```
|
||||||
|
|
||||||
Developing
|
### Testing
|
||||||
----------
|
|
||||||
|
|
||||||
See `HACKING.md`
|
```
|
||||||
|
$ 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
|
||||||
|
```
|
||||||
|
|||||||
1
bindings/vala/Eek-0.90.metadata
Normal file
1
bindings/vala/Eek-0.90.metadata
Normal file
@ -0,0 +1 @@
|
|||||||
|
Eek cheader_filename="eek/eek.h"
|
||||||
1
bindings/vala/EekGtk-0.90.metadata
Normal file
1
bindings/vala/EekGtk-0.90.metadata
Normal file
@ -0,0 +1 @@
|
|||||||
|
EekGtk cheader_filename="eek/eek-gtk.h"
|
||||||
1
bindings/vala/EekXkl-0.90.metadata
Normal file
1
bindings/vala/EekXkl-0.90.metadata
Normal file
@ -0,0 +1 @@
|
|||||||
|
EekXkl cheader_filename="eek/eek-xkl.h"
|
||||||
1
bindings/vala/eek-0.90.deps
Normal file
1
bindings/vala/eek-0.90.deps
Normal file
@ -0,0 +1 @@
|
|||||||
|
gio-2.0
|
||||||
1
bindings/vala/eek-gtk-0.90.deps
Normal file
1
bindings/vala/eek-gtk-0.90.deps
Normal file
@ -0,0 +1 @@
|
|||||||
|
eek-0.90
|
||||||
2
bindings/vala/eek-xkl-0.90.deps
Normal file
2
bindings/vala/eek-xkl-0.90.deps
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
eek-0.90
|
||||||
|
x11
|
||||||
24
cargo.sh
24
cargo.sh
@ -1,24 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# This script manages Cargo operations
|
|
||||||
# while keeping the artifact directory within the build tree
|
|
||||||
# instead of the source tree
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
SCRIPT_PATH="$(realpath "$0")"
|
|
||||||
SOURCE_DIR="$(dirname "$SCRIPT_PATH")"
|
|
||||||
|
|
||||||
CARGO_TARGET_DIR="$(pwd)"
|
|
||||||
export CARGO_TARGET_DIR
|
|
||||||
if [ -n "${1}" ]; then
|
|
||||||
OUT_PATH="$(realpath "$1")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$SOURCE_DIR"
|
|
||||||
shift
|
|
||||||
cargo "$@"
|
|
||||||
|
|
||||||
if [ -n "${OUT_PATH}" ]; then
|
|
||||||
cp "${CARGO_TARGET_DIR}"/debug/librs.a "${OUT_PATH}"
|
|
||||||
fi
|
|
||||||
@ -1,197 +0,0 @@
|
|||||||
# Greek layout created by Antonis Tsolomitis
|
|
||||||
# University of the Aegean, Department of Mathematics, atsol@aegean.gr
|
|
||||||
# Sep 2019
|
|
||||||
---
|
|
||||||
row_spacing: 11.33
|
|
||||||
button_spacing: 4.67
|
|
||||||
|
|
||||||
bounds: { x: 0, y: 6.33, width: 426, height: 250 }
|
|
||||||
|
|
||||||
outlines:
|
|
||||||
default:
|
|
||||||
bounds: { x: 0, y: 0, width: 32, height: 52 }
|
|
||||||
altline:
|
|
||||||
bounds: { x: 0, y: 0, width: 48.39024, height: 52 }
|
|
||||||
outline7:
|
|
||||||
bounds: { x: 0, y: 0, width: 88.97561, height: 52 }
|
|
||||||
spaceline:
|
|
||||||
bounds: { x: 0, y: 0, width: 150.5853, height: 52 }
|
|
||||||
|
|
||||||
views:
|
|
||||||
base:
|
|
||||||
- "; ς ε ρ τ υ θ ι ο π !"
|
|
||||||
- "α σ δ φ γ η ξ κ λ show_accented"
|
|
||||||
- "Shift_L ζ χ ψ ω β ν μ , BackSpace"
|
|
||||||
- "show_numbers preferences space . Return"
|
|
||||||
upper:
|
|
||||||
- ": EuroSign Ε Ρ Τ Υ Θ Ι Ο Π"
|
|
||||||
- "Α Σ Δ Φ Γ Η Ξ Κ Λ show_accented"
|
|
||||||
- "Shift_L Ζ Χ Ψ Ω Β Ν Μ · BackSpace"
|
|
||||||
- "show_numbers preferences space « » Return"
|
|
||||||
accented:
|
|
||||||
- "ά έ ή ί ό ύ ώ ϊ ϋ ΐ"
|
|
||||||
- "ΰ Ά Έ Ή Ί Ό Ύ Ώ Ϊ show_base"
|
|
||||||
- "Ϋ Ϗ ϐ ϑ ϕ ϖ ϗ – — BackSpace"
|
|
||||||
- "show_numbers preferences space quoteleft quoteright 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: "ΑΒΓ"
|
|
||||||
show_symbols:
|
|
||||||
action:
|
|
||||||
set_view: "symbols"
|
|
||||||
outline: "altline"
|
|
||||||
label: "*/="
|
|
||||||
show_accented:
|
|
||||||
action:
|
|
||||||
locking:
|
|
||||||
lock_view: "accented"
|
|
||||||
unlock_view: "base"
|
|
||||||
outline: "altline"
|
|
||||||
label: "άΐ"
|
|
||||||
show_base:
|
|
||||||
action:
|
|
||||||
set_view: "base"
|
|
||||||
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: "]"
|
|
||||||
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
---
|
|
||||||
row_spacing: 11.33
|
|
||||||
button_spacing: 4.67
|
|
||||||
|
|
||||||
bounds: { x: 0, y: 1, width: 360, height: 198 }
|
|
||||||
|
|
||||||
outlines:
|
|
||||||
default:
|
|
||||||
bounds: { x: 0, y: 0, width: 30.67, height: 40.67 }
|
|
||||||
altline:
|
|
||||||
bounds: { x: 0, y: 0, width: 48, height: 40.67 }
|
|
||||||
wide:
|
|
||||||
bounds: { x: 0, y: 0, width: 57.33, height: 40.67 }
|
|
||||||
spaceline:
|
|
||||||
bounds: { x: 0, y: 0, width: 95.00, height: 40.67 }
|
|
||||||
special:
|
|
||||||
bounds: { x: 0, y: 0, width: 39.33, height: 40.67 }
|
|
||||||
|
|
||||||
views:
|
|
||||||
base:
|
|
||||||
- "q w e r t y u i o p"
|
|
||||||
- "a s d f g h j k l ñ"
|
|
||||||
- "Shift_L z x c v b n m BackSpace"
|
|
||||||
- "show_numbers show_eschars preferences space ? period Return"
|
|
||||||
upper:
|
|
||||||
- "Q W E R T Y U I O P"
|
|
||||||
- "A S D F G H J K L Ñ"
|
|
||||||
- "Shift_L Z X C V B N M BackSpace"
|
|
||||||
- "show_numbers show_eschars preferences space ¿ period Return"
|
|
||||||
numbers:
|
|
||||||
- "1 2 3 4 5 6 7 8 9 0"
|
|
||||||
- "@ # € % & - _ + ( )"
|
|
||||||
- "show_symbols , \" ' colon ; ! = BackSpace"
|
|
||||||
- "show_letters show_eschars preferences space ? period Return"
|
|
||||||
symbols:
|
|
||||||
- "~ ` | · √ π τ ÷ × ¶"
|
|
||||||
- "© ® £ $ ¥ ^ ° * { }"
|
|
||||||
- "show_numbers \\ / < > = [ ] BackSpace"
|
|
||||||
- "show_letters show_eschars preferences space ? period Return"
|
|
||||||
eschars:
|
|
||||||
- "á é í ó ú Á É Í Ó Ú"
|
|
||||||
- "à è ì ò ù À È Ì Ò Ù"
|
|
||||||
- "show_numbers ü ç ï Ü Ç Ï ¡ BackSpace"
|
|
||||||
- "show_letters show_eschars preferences space « » Return"
|
|
||||||
|
|
||||||
buttons:
|
|
||||||
Shift_L:
|
|
||||||
action:
|
|
||||||
locking:
|
|
||||||
lock_view: "upper"
|
|
||||||
unlock_view: "base"
|
|
||||||
outline: "altline"
|
|
||||||
icon: "key-shift"
|
|
||||||
BackSpace:
|
|
||||||
outline: "altline"
|
|
||||||
icon: "edit-clear-symbolic"
|
|
||||||
preferences:
|
|
||||||
action: "show_prefs"
|
|
||||||
outline: "default"
|
|
||||||
icon: "keyboard-mode-symbolic"
|
|
||||||
show_numbers:
|
|
||||||
action:
|
|
||||||
set_view: "numbers"
|
|
||||||
outline: "altline"
|
|
||||||
label: "123"
|
|
||||||
show_letters:
|
|
||||||
action:
|
|
||||||
set_view: "base"
|
|
||||||
outline: "altline"
|
|
||||||
label: "abc"
|
|
||||||
show_symbols:
|
|
||||||
action:
|
|
||||||
set_view: "symbols"
|
|
||||||
outline: "altline"
|
|
||||||
label: "*/="
|
|
||||||
show_eschars:
|
|
||||||
action:
|
|
||||||
locking:
|
|
||||||
lock_view: "eschars"
|
|
||||||
unlock_view: "base"
|
|
||||||
outline: "altline"
|
|
||||||
label: "áÁ"
|
|
||||||
|
|
||||||
period:
|
|
||||||
outline: "default"
|
|
||||||
label: "."
|
|
||||||
space:
|
|
||||||
outline: "spaceline"
|
|
||||||
label: " "
|
|
||||||
Return:
|
|
||||||
outline: "altline"
|
|
||||||
icon: "key-enter"
|
|
||||||
colon:
|
|
||||||
label: ":"
|
|
||||||
"\"":
|
|
||||||
keysym: "quotedbl"
|
|
||||||
64
data/keyboards/geometry/compact.xml
Normal file
64
data/keyboards/geometry/compact.xml
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?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>
|
||||||
105
data/keyboards/geometry/extended.xml
Normal file
105
data/keyboards/geometry/extended.xml
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?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>
|
||||||
40
data/keyboards/geometry/number-keypad.xml
Normal file
40
data/keyboards/geometry/number-keypad.xml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?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,98 +0,0 @@
|
|||||||
---
|
|
||||||
row_spacing: 11.33
|
|
||||||
button_spacing: 4.67
|
|
||||||
|
|
||||||
bounds: { x: 0, y: 1, width: 360, height: 198 }
|
|
||||||
|
|
||||||
outlines:
|
|
||||||
default:
|
|
||||||
bounds: { x: 0, y: 0, width: 30.67, height: 40.67 }
|
|
||||||
altline:
|
|
||||||
bounds: { x: 0, y: 0, width: 48, height: 40.67 }
|
|
||||||
wide:
|
|
||||||
bounds: { x: 0, y: 0, width: 57.33, height: 40.67 }
|
|
||||||
spaceline:
|
|
||||||
bounds: { x: 0, y: 0, width: 95.00, height: 40.67 }
|
|
||||||
special:
|
|
||||||
bounds: { x: 0, y: 0, width: 39.33, height: 40.67 }
|
|
||||||
|
|
||||||
views:
|
|
||||||
base:
|
|
||||||
- "q w e r t y u i o p"
|
|
||||||
- "a s d f g h j k l n"
|
|
||||||
- "Shift_L z x c v b n m BackSpace"
|
|
||||||
- "show_numbers show_eschar preferences space ? period Return"
|
|
||||||
upper:
|
|
||||||
- "Q W E R T Y U I O P"
|
|
||||||
- "A S D F G H J K L Ñ"
|
|
||||||
- "Shift_L Z X C V B N M BackSpace"
|
|
||||||
- "show_numbers show_eschar preferences space ? period Return"
|
|
||||||
numbers:
|
|
||||||
- "1 2 3 4 5 6 7 8 9 0"
|
|
||||||
- "@ # € % & - _ + ( )"
|
|
||||||
- "show_symbols , \" ' colon ; ! ? BackSpace"
|
|
||||||
- "show_letters show_eschar preferences space ? period Return"
|
|
||||||
symbols:
|
|
||||||
- "~ ` | · √ π τ ÷ × ¶"
|
|
||||||
- "© ® £ $ ¥ ^ ° * { }"
|
|
||||||
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
|
|
||||||
- "show_letters show_eschar preferences space ? period Return"
|
|
||||||
eschar:
|
|
||||||
- "á é í ó ú Á É Í Ó Ú"
|
|
||||||
- "à è ì ò « » ù ! { }"
|
|
||||||
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
|
|
||||||
- "show_letters show_symbols 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: "default"
|
|
||||||
icon: "keyboard-mode-symbolic"
|
|
||||||
show_numbers:
|
|
||||||
action:
|
|
||||||
set_view: "numbers"
|
|
||||||
outline: "altline"
|
|
||||||
label: "123"
|
|
||||||
show_numbers_from_symbols:
|
|
||||||
action:
|
|
||||||
set_view: "numbers"
|
|
||||||
outline: "altline"
|
|
||||||
label: "123"
|
|
||||||
show_letters:
|
|
||||||
action:
|
|
||||||
set_view: "base"
|
|
||||||
outline: "altline"
|
|
||||||
label: "ABC"
|
|
||||||
show_symbols:
|
|
||||||
action:
|
|
||||||
set_view: "symbols"
|
|
||||||
outline: "altline"
|
|
||||||
label: "*/="
|
|
||||||
show_eschar:
|
|
||||||
action:
|
|
||||||
set_view: "eschar"
|
|
||||||
outline: "altline"
|
|
||||||
label: "àè"
|
|
||||||
period:
|
|
||||||
outline: "default"
|
|
||||||
label: "."
|
|
||||||
space:
|
|
||||||
outline: "spaceline"
|
|
||||||
label: " "
|
|
||||||
Return:
|
|
||||||
outline: "altline"
|
|
||||||
icon: "key-enter"
|
|
||||||
colon:
|
|
||||||
label: ":"
|
|
||||||
"\"":
|
|
||||||
keysym: "quotedbl"
|
|
||||||
100
data/keyboards/keyboards.xml
Normal file
100
data/keyboards/keyboards.xml
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?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>
|
||||||
@ -1,178 +0,0 @@
|
|||||||
---
|
|
||||||
row_spacing: 11.33
|
|
||||||
button_spacing: 4.67
|
|
||||||
|
|
||||||
bounds: { x: 0, y: 6.33, width: 426, height: 250 }
|
|
||||||
|
|
||||||
outlines:
|
|
||||||
default:
|
|
||||||
bounds: { x: 0, y: 0, width: 32, height: 52 }
|
|
||||||
altline:
|
|
||||||
bounds: { x: 0, y: 0, width: 48.39024, height: 52 }
|
|
||||||
outline7:
|
|
||||||
bounds: { x: 0, y: 0, width: 88.97561, height: 52 }
|
|
||||||
spaceline:
|
|
||||||
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: "]"
|
|
||||||
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
---
|
|
||||||
row_spacing: 11.33
|
|
||||||
button_spacing: 4.67
|
|
||||||
|
|
||||||
bounds: { x: 0, y: 6.33, width: 410, height: 250 }
|
|
||||||
|
|
||||||
outlines:
|
|
||||||
default:
|
|
||||||
bounds: { x: 0, y: 0, width: 37.46341, height: 52 }
|
|
||||||
altline:
|
|
||||||
bounds: { x: 0, y: 0, width: 48.39024, height: 52 }
|
|
||||||
outline7:
|
|
||||||
bounds: { x: 0, y: 0, width: 88.97561, height: 52 }
|
|
||||||
spaceline:
|
|
||||||
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: ")"
|
|
||||||
|
|
||||||
132
data/keyboards/symbols/nb.xml
Normal file
132
data/keyboards/symbols/nb.xml
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
<?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>
|
||||||
22
data/keyboards/symbols/special/number.xml
Normal file
22
data/keyboards/symbols/special/number.xml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?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>
|
||||||
118
data/keyboards/symbols/us.xml
Normal file
118
data/keyboards/symbols/us.xml
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<?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>
|
||||||
@ -1,88 +0,0 @@
|
|||||||
---
|
|
||||||
row_spacing: 11.33
|
|
||||||
button_spacing: 4.67
|
|
||||||
|
|
||||||
bounds: { x: 0, y: 1, width: 360, height: 198 }
|
|
||||||
|
|
||||||
outlines:
|
|
||||||
default:
|
|
||||||
bounds: { x: 0, y: 0, width: 30.67, height: 40.67 }
|
|
||||||
altline:
|
|
||||||
bounds: { x: 0, y: 0, width: 48, height: 40.67 }
|
|
||||||
wide:
|
|
||||||
bounds: { x: 0, y: 0, width: 57.33, height: 40.67 }
|
|
||||||
spaceline:
|
|
||||||
bounds: { x: 0, y: 0, width: 137.33, height: 40.67 }
|
|
||||||
special:
|
|
||||||
bounds: { x: 0, y: 0, width: 39.33, height: 40.67 }
|
|
||||||
|
|
||||||
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 period Return"
|
|
||||||
upper:
|
|
||||||
- "Q W E R T Y U I O P"
|
|
||||||
- "A S D F G H J K L"
|
|
||||||
- "Shift_L Z X C V B N M BackSpace"
|
|
||||||
- "show_numbers preferences space period Return"
|
|
||||||
numbers:
|
|
||||||
- "1 2 3 4 5 6 7 8 9 0"
|
|
||||||
- "@ # $ % & - _ + ( )"
|
|
||||||
- "show_symbols , \" ' colon ; ! ? BackSpace"
|
|
||||||
- "show_letters preferences space period Return"
|
|
||||||
symbols:
|
|
||||||
- "~ ` | · √ π τ ÷ × ¶"
|
|
||||||
- "© ® £ € ¥ ^ ° * { }"
|
|
||||||
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
|
|
||||||
- "show_letters preferences space period Return"
|
|
||||||
|
|
||||||
buttons:
|
|
||||||
Shift_L:
|
|
||||||
action:
|
|
||||||
locking:
|
|
||||||
lock_view: "upper"
|
|
||||||
unlock_view: "base"
|
|
||||||
outline: "altline"
|
|
||||||
icon: "key-shift"
|
|
||||||
BackSpace:
|
|
||||||
outline: "altline"
|
|
||||||
icon: "edit-clear-symbolic"
|
|
||||||
preferences:
|
|
||||||
action: "show_prefs"
|
|
||||||
outline: "special"
|
|
||||||
icon: "keyboard-mode-symbolic"
|
|
||||||
show_numbers:
|
|
||||||
action:
|
|
||||||
set_view: "numbers"
|
|
||||||
outline: "wide"
|
|
||||||
label: "123"
|
|
||||||
show_numbers_from_symbols:
|
|
||||||
action:
|
|
||||||
set_view: "numbers"
|
|
||||||
outline: "altline"
|
|
||||||
label: "123"
|
|
||||||
show_letters:
|
|
||||||
action:
|
|
||||||
set_view: "base"
|
|
||||||
outline: "wide"
|
|
||||||
label: "ABC"
|
|
||||||
show_symbols:
|
|
||||||
action:
|
|
||||||
set_view: "symbols"
|
|
||||||
outline: "altline"
|
|
||||||
label: "*/="
|
|
||||||
period:
|
|
||||||
outline: "special"
|
|
||||||
label: "."
|
|
||||||
space:
|
|
||||||
outline: "spaceline"
|
|
||||||
label: " "
|
|
||||||
Return:
|
|
||||||
outline: "wide"
|
|
||||||
icon: "key-enter"
|
|
||||||
colon:
|
|
||||||
label: ":"
|
|
||||||
"\"":
|
|
||||||
keysym: "quotedbl"
|
|
||||||
@ -6,5 +6,4 @@ Exec=squeekboard
|
|||||||
Icon=squeekboard
|
Icon=squeekboard
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
NoDisplay=true
|
|
||||||
Categories=GTK;Utility;
|
Categories=GTK;Utility;
|
||||||
|
|||||||
@ -2,6 +2,10 @@
|
|||||||
<gresources>
|
<gresources>
|
||||||
<gresource prefix="/sm/puri/squeekboard">
|
<gresource prefix="/sm/puri/squeekboard">
|
||||||
<file compressed="true">style.css</file>
|
<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/ar.xml</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/as-inscript.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>
|
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/be.xml</file>
|
||||||
@ -19,6 +23,7 @@
|
|||||||
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ml-inscript.xml</file>
|
<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/mr-inscript.xml</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/my.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/or-inscript.xml</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/pa-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>
|
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ru.xml</file>
|
||||||
@ -28,7 +33,9 @@
|
|||||||
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/th.xml</file>
|
<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/ua.xml</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks">keyboards/symbols/ug.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/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-enter.svg</file>
|
||||||
<file>icons/key-shift.svg</file>
|
<file>icons/key-shift.svg</file>
|
||||||
<file>icons/keyboard-mode-symbolic.svg</file>
|
<file>icons/keyboard-mode-symbolic.svg</file>
|
||||||
|
|||||||
@ -1,41 +1,19 @@
|
|||||||
sq_view {
|
.keyboard {
|
||||||
background-color: rgba(0, 0, 0, 255);
|
background-color: rgba(0, 0, 0, 255);
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
font-family: cantarell, sans-serif;
|
font-family: cantarell, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
sq_button {
|
.key {
|
||||||
color: #deddda;
|
color: #deddda;
|
||||||
background: #464448;
|
background: #464448;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-color: #5e5c64;
|
border-color: #5e5c64;
|
||||||
border-radius: 3px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
sq_button:active {
|
.key:active {
|
||||||
background: #545256;
|
|
||||||
border-color: #716e78;
|
|
||||||
}
|
|
||||||
|
|
||||||
sq_button.altline,
|
|
||||||
sq_button.special,
|
|
||||||
sq_button.wide {
|
|
||||||
background: #2b292f;
|
|
||||||
border-color: #3e3a44
|
|
||||||
}
|
|
||||||
|
|
||||||
sq_button.locked {
|
|
||||||
background: #ffffff;
|
|
||||||
color: #2b292f;
|
|
||||||
}
|
|
||||||
|
|
||||||
#Return {
|
|
||||||
background: #1c71d8;
|
|
||||||
border-color: #1a5fb4
|
|
||||||
}
|
|
||||||
|
|
||||||
#Return:active {
|
|
||||||
background: #1c71d8;
|
background: #1c71d8;
|
||||||
border-color: #3584e4;
|
border-color: #3584e4;
|
||||||
}
|
}
|
||||||
|
|||||||
12
debian/cargo/config
vendored
12
debian/cargo/config
vendored
@ -1,12 +0,0 @@
|
|||||||
# 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'
|
|
||||||
|
|
||||||
19
debian/changelog
vendored
19
debian/changelog
vendored
@ -1,22 +1,3 @@
|
|||||||
squeekboard (1.2.1) amber-phone; urgency=medium
|
|
||||||
|
|
||||||
* Use different distribution
|
|
||||||
|
|
||||||
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Tue, 08 Oct 2019 10:56:10 +0000
|
|
||||||
|
|
||||||
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
|
squeekboard (1.0.10) unstable; urgency=medium
|
||||||
|
|
||||||
* Use a shared DBus definition
|
* Use a shared DBus definition
|
||||||
|
|||||||
9
debian/control
vendored
9
debian/control
vendored
@ -3,19 +3,12 @@ Section: x11
|
|||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>
|
Maintainer: Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>
|
||||||
Build-Depends:
|
Build-Depends:
|
||||||
cargo,
|
|
||||||
debhelper (>= 10),
|
debhelper (>= 10),
|
||||||
meson (>=0.51.0),
|
meson (>=0.43.0),
|
||||||
ninja-build,
|
|
||||||
pkg-config,
|
pkg-config,
|
||||||
libglib2.0-dev,
|
libglib2.0-dev,
|
||||||
libgtk-3-dev,
|
libgtk-3-dev,
|
||||||
libcroco3-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),
|
libwayland-dev (>= 1.16),
|
||||||
rustc,
|
rustc,
|
||||||
wayland-protocols (>= 1.14),
|
wayland-protocols (>= 1.14),
|
||||||
|
|||||||
7
debian/rules
vendored
7
debian/rules
vendored
@ -1,15 +1,8 @@
|
|||||||
#!/usr/bin/make -f
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
export CARGO_HOME = $(CURDIR)/debian/cargo
|
|
||||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||||
|
|
||||||
%:
|
%:
|
||||||
dh $@ --builddirectory=_build --buildsystem=meson
|
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-arch:
|
|
||||||
rm Cargo.lock
|
|
||||||
dh $@ --builddirectory=_build --buildsystem=meson
|
|
||||||
|
|
||||||
override_dh_autoreconf:
|
override_dh_autoreconf:
|
||||||
|
|||||||
2
debian/squeekboard.lintian-overrides
vendored
2
debian/squeekboard.lintian-overrides
vendored
@ -1,2 +0,0 @@
|
|||||||
# 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,6 +34,7 @@
|
|||||||
|
|
||||||
#include "eek-renderer.h"
|
#include "eek-renderer.h"
|
||||||
#include "eek-keyboard.h"
|
#include "eek-keyboard.h"
|
||||||
|
#include "src/symbol.h"
|
||||||
|
|
||||||
#include "eek-gtk-keyboard.h"
|
#include "eek-gtk-keyboard.h"
|
||||||
|
|
||||||
@ -52,6 +53,8 @@ typedef struct _EekGtkKeyboardPrivate
|
|||||||
{
|
{
|
||||||
EekRenderer *renderer;
|
EekRenderer *renderer;
|
||||||
LevelKeyboard *keyboard;
|
LevelKeyboard *keyboard;
|
||||||
|
GtkCssProvider *css_provider;
|
||||||
|
GtkStyleContext *scontext;
|
||||||
|
|
||||||
GdkEventSequence *sequence; // unowned reference
|
GdkEventSequence *sequence; // unowned reference
|
||||||
} EekGtkKeyboardPrivate;
|
} EekGtkKeyboardPrivate;
|
||||||
@ -59,15 +62,15 @@ typedef struct _EekGtkKeyboardPrivate
|
|||||||
G_DEFINE_TYPE_WITH_PRIVATE (EekGtkKeyboard, eek_gtk_keyboard, GTK_TYPE_DRAWING_AREA)
|
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,
|
static void on_button_pressed (struct squeek_button *button, struct squeek_view *view,
|
||||||
EekGtkKeyboard *self);
|
EekGtkKeyboard *self);
|
||||||
static void on_button_released (const struct squeek_button *button,
|
static void on_button_released (struct squeek_button *button,
|
||||||
struct squeek_view *view,
|
struct squeek_view *view,
|
||||||
EekGtkKeyboard *self);
|
EekGtkKeyboard *self);
|
||||||
static void render_pressed_button (GtkWidget *widget, struct button_place *place);
|
static void render_pressed_button (GtkWidget *widget, struct button_place *place);
|
||||||
static void render_locked_button (GtkWidget *widget,
|
static void render_locked_button (GtkWidget *widget,
|
||||||
struct button_place *place);
|
struct button_place *place);
|
||||||
static void render_released_button (GtkWidget *widget,
|
static void render_released_button (GtkWidget *widget,
|
||||||
const struct squeek_button *button);
|
struct squeek_button *button);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
eek_gtk_keyboard_real_realize (GtkWidget *self)
|
eek_gtk_keyboard_real_realize (GtkWidget *self)
|
||||||
@ -78,8 +81,7 @@ eek_gtk_keyboard_real_realize (GtkWidget *self)
|
|||||||
GDK_KEY_RELEASE_MASK |
|
GDK_KEY_RELEASE_MASK |
|
||||||
GDK_BUTTON_PRESS_MASK |
|
GDK_BUTTON_PRESS_MASK |
|
||||||
GDK_BUTTON_RELEASE_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);
|
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->realize (self);
|
||||||
}
|
}
|
||||||
@ -96,7 +98,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
|
|||||||
if (!priv->renderer) {
|
if (!priv->renderer) {
|
||||||
PangoContext *pcontext = gtk_widget_get_pango_context (self);
|
PangoContext *pcontext = gtk_widget_get_pango_context (self);
|
||||||
|
|
||||||
priv->renderer = eek_renderer_new (priv->keyboard, pcontext);
|
priv->renderer = eek_renderer_new (priv->keyboard, pcontext, priv->scontext);
|
||||||
|
|
||||||
eek_renderer_set_allocation_size (priv->renderer,
|
eek_renderer_set_allocation_size (priv->renderer,
|
||||||
allocation.width,
|
allocation.width,
|
||||||
@ -107,23 +109,25 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
|
|||||||
|
|
||||||
eek_renderer_render_keyboard (priv->renderer, cr);
|
eek_renderer_render_keyboard (priv->renderer, cr);
|
||||||
|
|
||||||
struct squeek_view *view = squeek_layout_get_current_view(priv->keyboard->layout);
|
struct squeek_view *view = priv->keyboard->views[priv->keyboard->level];
|
||||||
|
|
||||||
/* redraw pressed key */
|
/* redraw pressed key */
|
||||||
const GList *list = priv->keyboard->pressed_keys;
|
const GList *list = priv->keyboard->pressed_buttons;
|
||||||
for (const GList *head = list; head; head = g_list_next (head)) {
|
for (const GList *head = list; head; head = g_list_next (head)) {
|
||||||
struct button_place place = squeek_view_find_key(
|
struct button_place place = squeek_view_find_key(
|
||||||
view, head->data
|
view, squeek_button_get_key(head->data)
|
||||||
);
|
);
|
||||||
if (place.button)
|
if (place.button)
|
||||||
render_pressed_button (self, &place);
|
render_pressed_button (self, &place);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* redraw locked key */
|
/* redraw locked key */
|
||||||
list = priv->keyboard->locked_keys;
|
list = priv->keyboard->locked_buttons;
|
||||||
for (const GList *head = list; head; head = g_list_next (head)) {
|
for (const GList *head = list; head; head = g_list_next (head)) {
|
||||||
struct button_place place = squeek_view_find_key(
|
struct button_place place = squeek_view_find_key(
|
||||||
view, ((EekModifierKey *)head->data)->key
|
view, squeek_button_get_key(
|
||||||
|
((EekModifierKey *)head->data)->button
|
||||||
|
)
|
||||||
);
|
);
|
||||||
if (place.button)
|
if (place.button)
|
||||||
render_locked_button (self, &place);
|
render_locked_button (self, &place);
|
||||||
@ -156,78 +160,56 @@ static void depress(EekGtkKeyboard *self,
|
|||||||
struct squeek_button *button = eek_renderer_find_button_by_position (priv->renderer, view, x, y);
|
struct squeek_button *button = eek_renderer_find_button_by_position (priv->renderer, view, x, y);
|
||||||
|
|
||||||
if (button) {
|
if (button) {
|
||||||
eek_keyboard_press_key(
|
eek_keyboard_press_button(priv->keyboard, button, time);
|
||||||
priv->keyboard,
|
|
||||||
squeek_button_get_key(button),
|
|
||||||
time
|
|
||||||
);
|
|
||||||
on_button_pressed(button, view, self);
|
on_button_pressed(button, view, self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drag(EekGtkKeyboard *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);
|
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
|
||||||
struct squeek_view *view = level_keyboard_current(priv->keyboard);
|
struct squeek_view *view = level_keyboard_current(priv->keyboard);
|
||||||
struct squeek_button *button = eek_renderer_find_button_by_position (priv->renderer, view, x, y);
|
struct squeek_button *button = eek_renderer_find_button_by_position (priv->renderer, view, x, y);
|
||||||
GList *list, *head;
|
GList *list, *head;
|
||||||
|
|
||||||
list = g_list_copy(priv->keyboard->pressed_keys);
|
list = g_list_copy(priv->keyboard->pressed_buttons);
|
||||||
|
|
||||||
if (button) {
|
if (button) {
|
||||||
gboolean found = FALSE;
|
gboolean found = FALSE;
|
||||||
|
|
||||||
for (head = list; head; head = g_list_next (head)) {
|
for (head = list; head; head = g_list_next (head)) {
|
||||||
struct squeek_key *key = head->data;
|
if (head->data == button) {
|
||||||
if (squeek_button_has_key(button, key)) {
|
|
||||||
found = TRUE;
|
found = TRUE;
|
||||||
} else {
|
} else {
|
||||||
eek_keyboard_release_key(priv->keyboard, key, time);
|
eek_keyboard_release_button(priv->keyboard, head->data, time);
|
||||||
// The released handler proceeds to ignore this info...
|
on_button_released(button, view, self);
|
||||||
// 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);
|
g_list_free (list);
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
eek_keyboard_press_key(
|
eek_keyboard_press_button(priv->keyboard, button, time);
|
||||||
priv->keyboard,
|
|
||||||
squeek_button_get_key(button),
|
|
||||||
time
|
|
||||||
);
|
|
||||||
|
|
||||||
on_button_pressed(button, view, self);
|
on_button_pressed(button, view, self);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (head = list; head; head = g_list_next (head)) {
|
for (head = list; head; head = g_list_next (head)) {
|
||||||
struct squeek_key *key = head->data;
|
eek_keyboard_release_button(priv->keyboard, head->data, time);
|
||||||
eek_keyboard_release_key(priv->keyboard, key, time);
|
on_button_released(head->data, view, self);
|
||||||
// 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);
|
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);
|
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
|
||||||
|
|
||||||
struct squeek_view *view = level_keyboard_current(priv->keyboard);
|
struct squeek_view *view = level_keyboard_current(priv->keyboard);
|
||||||
|
|
||||||
GList *list = g_list_copy(priv->keyboard->pressed_keys);
|
GList *list = g_list_copy(priv->keyboard->pressed_buttons);
|
||||||
for (GList *head = list; head; head = g_list_next (head)) {
|
for (GList *head = list; head; head = g_list_next (head)) {
|
||||||
struct squeek_key *key = head->data;
|
struct squeek_button *button = head->data;
|
||||||
eek_keyboard_release_key(priv->keyboard, key, time);
|
eek_keyboard_release_button(priv->keyboard, button, time);
|
||||||
// The released handler proceeds to ignore this info...
|
on_button_released(button, view, self);
|
||||||
// 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);
|
g_list_free (list);
|
||||||
}
|
}
|
||||||
@ -272,27 +254,27 @@ handle_touch_event (GtkWidget *widget,
|
|||||||
EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget);
|
EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget);
|
||||||
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
|
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 (event->type == GDK_TOUCH_BEGIN) {
|
||||||
release(self, event->time);
|
if (priv->sequence) {
|
||||||
|
// Ignore second and following touch points
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
priv->sequence = event->sequence;
|
priv->sequence = event->sequence;
|
||||||
depress(self, event->x, event->y, event->time);
|
depress(self, event->x, event->y, event->time);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only allow the latest touch point to be dragged. */
|
if (priv->sequence != event->sequence) {
|
||||||
if (event->type == GDK_TOUCH_UPDATE && event->sequence == priv->sequence) {
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->type == GDK_TOUCH_UPDATE) {
|
||||||
drag(self, event->x, event->y, event->time);
|
drag(self, event->x, event->y, event->time);
|
||||||
}
|
}
|
||||||
else if (event->type == GDK_TOUCH_END || event->type == GDK_TOUCH_CANCEL) {
|
if (event->type == GDK_TOUCH_END || event->type == GDK_TOUCH_CANCEL) {
|
||||||
// TODO: can the event have different coords than the previous update event?
|
// TODO: can the event have different coords than the previous update event?
|
||||||
/* Only respond to the release of the latest touch point. Previous
|
release(self, event->time);
|
||||||
touches have already been released. */
|
priv->sequence = NULL;
|
||||||
if (event->sequence == priv->sequence) {
|
|
||||||
release(self, event->time);
|
|
||||||
priv->sequence = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -304,20 +286,49 @@ eek_gtk_keyboard_real_unmap (GtkWidget *self)
|
|||||||
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
|
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
|
||||||
|
|
||||||
if (priv->keyboard) {
|
if (priv->keyboard) {
|
||||||
GList *head;
|
GList *list, *head;
|
||||||
|
|
||||||
for (head = priv->keyboard->pressed_keys; head; head = g_list_next (head)) {
|
/* Make a copy of HEAD before sending "released" signal on
|
||||||
/* Unlike other places where we call this, we don't call
|
elements, so that the default handler of
|
||||||
on_button_released afterwards since we don't want to queue a
|
EekKeyboard::key-released signal can remove elements from its
|
||||||
redraw. */
|
internal copy */
|
||||||
eek_keyboard_release_key(priv->keyboard, head->data,
|
list = g_list_copy(priv->keyboard->pressed_buttons);
|
||||||
gdk_event_get_time(NULL));
|
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");
|
||||||
}
|
}
|
||||||
|
g_list_free (list);
|
||||||
}
|
}
|
||||||
|
|
||||||
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->unmap (self);
|
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
|
static void
|
||||||
eek_gtk_keyboard_set_property (GObject *object,
|
eek_gtk_keyboard_set_property (GObject *object,
|
||||||
guint prop_id,
|
guint prop_id,
|
||||||
@ -340,16 +351,17 @@ eek_gtk_keyboard_dispose (GObject *object)
|
|||||||
if (priv->renderer) {
|
if (priv->renderer) {
|
||||||
g_object_unref (priv->renderer);
|
g_object_unref (priv->renderer);
|
||||||
priv->renderer = NULL;
|
priv->renderer = NULL;
|
||||||
priv->renderer = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->keyboard) {
|
if (priv->keyboard) {
|
||||||
GList *head;
|
GList *list, *head;
|
||||||
|
|
||||||
for (head = priv->keyboard->pressed_keys; head; head = g_list_next (head)) {
|
list = g_list_copy(priv->keyboard->pressed_buttons);
|
||||||
eek_keyboard_release_key(priv->keyboard, head->data,
|
for (head = list; head; head = g_list_next (head)) {
|
||||||
gdk_event_get_time(NULL));
|
g_log("squeek", G_LOG_LEVEL_DEBUG, "emit EekKey pressed");
|
||||||
|
g_signal_emit_by_name (head->data, "released", level_keyboard_current(priv->keyboard));
|
||||||
}
|
}
|
||||||
|
g_list_free (list);
|
||||||
|
|
||||||
priv->keyboard = NULL;
|
priv->keyboard = NULL;
|
||||||
}
|
}
|
||||||
@ -373,6 +385,8 @@ eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass)
|
|||||||
eek_gtk_keyboard_real_button_release_event;
|
eek_gtk_keyboard_real_button_release_event;
|
||||||
widget_class->motion_notify_event =
|
widget_class->motion_notify_event =
|
||||||
eek_gtk_keyboard_real_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;
|
widget_class->touch_event = handle_touch_event;
|
||||||
|
|
||||||
gobject_class->set_property = eek_gtk_keyboard_set_property;
|
gobject_class->set_property = eek_gtk_keyboard_set_property;
|
||||||
@ -381,7 +395,22 @@ eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
eek_gtk_keyboard_init (EekGtkKeyboard *self)
|
eek_gtk_keyboard_init (EekGtkKeyboard *self)
|
||||||
{}
|
{
|
||||||
|
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
|
||||||
|
|
||||||
|
/* Create a default CSS provider and load a style sheet */
|
||||||
|
priv->css_provider = gtk_css_provider_new ();
|
||||||
|
gtk_css_provider_load_from_resource (priv->css_provider,
|
||||||
|
"/sm/puri/squeekboard/style.css");
|
||||||
|
|
||||||
|
/* Apply the style to the widget */
|
||||||
|
priv->scontext = gtk_widget_get_style_context (GTK_WIDGET(self));
|
||||||
|
gtk_style_context_add_class (priv->scontext, "keyboard");
|
||||||
|
gtk_style_context_add_provider (priv->scontext,
|
||||||
|
GTK_STYLE_PROVIDER(priv->css_provider),
|
||||||
|
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||||
|
gtk_style_context_set_state (priv->scontext, GTK_STATE_FLAG_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* eek_gtk_keyboard_new:
|
* eek_gtk_keyboard_new:
|
||||||
@ -438,10 +467,9 @@ render_locked_button (GtkWidget *widget, struct button_place *place)
|
|||||||
cairo_region_destroy (region);
|
cairo_region_destroy (region);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: does it really redraw the entire keyboard?
|
|
||||||
static void
|
static void
|
||||||
render_released_button (GtkWidget *widget,
|
render_released_button (GtkWidget *widget,
|
||||||
const struct squeek_button *button)
|
struct squeek_button *button)
|
||||||
{
|
{
|
||||||
(void)button;
|
(void)button;
|
||||||
EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget);
|
EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget);
|
||||||
@ -461,8 +489,8 @@ render_released_button (GtkWidget *widget,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
on_button_pressed (struct squeek_button *button,
|
on_button_pressed (struct squeek_button *button,
|
||||||
struct squeek_view *view,
|
struct squeek_view *view,
|
||||||
EekGtkKeyboard *self)
|
EekGtkKeyboard *self)
|
||||||
{
|
{
|
||||||
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
|
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
|
||||||
|
|
||||||
@ -490,9 +518,9 @@ on_button_pressed (struct squeek_button *button,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_button_released (const struct squeek_button *button,
|
on_button_released (struct squeek_button *button,
|
||||||
struct squeek_view *view,
|
struct squeek_view *view,
|
||||||
EekGtkKeyboard *self)
|
EekGtkKeyboard *self)
|
||||||
{
|
{
|
||||||
(void)view;
|
(void)view;
|
||||||
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
|
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
|
||||||
|
|||||||
217
eek/eek-keyboard-drawing.c
Normal file
217
eek/eek-keyboard-drawing.c
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006 Sergey V. Udaltsov <svu@gnome.org>
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <pango/pangocairo.h>
|
||||||
|
|
||||||
|
#include "eek-types.h"
|
||||||
|
|
||||||
|
static gdouble
|
||||||
|
length (gdouble x, gdouble y)
|
||||||
|
{
|
||||||
|
return sqrt (x * x + y * y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gdouble
|
||||||
|
point_line_distance (gdouble ax, gdouble ay, gdouble nx, gdouble ny)
|
||||||
|
{
|
||||||
|
return ax * nx + ay * ny;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
normal_form (gdouble ax, gdouble ay,
|
||||||
|
gdouble bx, gdouble by,
|
||||||
|
gdouble * nx, gdouble * ny, gdouble * d)
|
||||||
|
{
|
||||||
|
gdouble l;
|
||||||
|
|
||||||
|
*nx = by - ay;
|
||||||
|
*ny = ax - bx;
|
||||||
|
|
||||||
|
l = length (*nx, *ny);
|
||||||
|
|
||||||
|
*nx /= l;
|
||||||
|
*ny /= l;
|
||||||
|
|
||||||
|
*d = point_line_distance (ax, ay, *nx, *ny);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
inverse (gdouble a, gdouble b, gdouble c, gdouble d,
|
||||||
|
gdouble * e, gdouble * f, gdouble * g, gdouble * h)
|
||||||
|
{
|
||||||
|
gdouble det;
|
||||||
|
|
||||||
|
det = a * d - b * c;
|
||||||
|
|
||||||
|
*e = d / det;
|
||||||
|
*f = -b / det;
|
||||||
|
*g = -c / det;
|
||||||
|
*h = a / det;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
multiply (gdouble a, gdouble b, gdouble c, gdouble d,
|
||||||
|
gdouble e, gdouble f, gdouble * x, gdouble * y)
|
||||||
|
{
|
||||||
|
*x = a * e + b * f;
|
||||||
|
*y = c * e + d * f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
intersect (gdouble n1x, gdouble n1y, gdouble d1,
|
||||||
|
gdouble n2x, gdouble n2y, gdouble d2, gdouble * x, gdouble * y)
|
||||||
|
{
|
||||||
|
gdouble e, f, g, h;
|
||||||
|
|
||||||
|
inverse (n1x, n1y, n2x, n2y, &e, &f, &g, &h);
|
||||||
|
multiply (e, f, g, h, d1, d2, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* draw an angle from the current point to b and then to c,
|
||||||
|
* with a rounded corner of the given radius.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
rounded_corner (cairo_t * cr,
|
||||||
|
gdouble bx, gdouble by,
|
||||||
|
gdouble cx, gdouble cy, gdouble radius)
|
||||||
|
{
|
||||||
|
gdouble ax, ay;
|
||||||
|
gdouble n1x, n1y, d1;
|
||||||
|
gdouble n2x, n2y, d2;
|
||||||
|
gdouble pd1, pd2;
|
||||||
|
gdouble ix, iy;
|
||||||
|
gdouble dist1, dist2;
|
||||||
|
gdouble nx, ny, d;
|
||||||
|
gdouble a1x, a1y, c1x, c1y;
|
||||||
|
gdouble phi1, phi2;
|
||||||
|
|
||||||
|
cairo_get_current_point (cr, &ax, &ay);
|
||||||
|
#ifdef KBDRAW_DEBUG
|
||||||
|
printf (" current point: (%f, %f), radius %f:\n", ax, ay,
|
||||||
|
radius);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* make sure radius is not too large */
|
||||||
|
dist1 = length (bx - ax, by - ay);
|
||||||
|
dist2 = length (cx - bx, cy - by);
|
||||||
|
|
||||||
|
radius = MIN (radius, MIN (dist1, dist2));
|
||||||
|
|
||||||
|
/* construct normal forms of the lines */
|
||||||
|
normal_form (ax, ay, bx, by, &n1x, &n1y, &d1);
|
||||||
|
normal_form (bx, by, cx, cy, &n2x, &n2y, &d2);
|
||||||
|
|
||||||
|
/* find which side of the line a,b the point c is on */
|
||||||
|
if (point_line_distance (cx, cy, n1x, n1y) < d1)
|
||||||
|
pd1 = d1 - radius;
|
||||||
|
else
|
||||||
|
pd1 = d1 + radius;
|
||||||
|
|
||||||
|
/* find which side of the line b,c the point a is on */
|
||||||
|
if (point_line_distance (ax, ay, n2x, n2y) < d2)
|
||||||
|
pd2 = d2 - radius;
|
||||||
|
else
|
||||||
|
pd2 = d2 + radius;
|
||||||
|
|
||||||
|
/* intersect the parallels to find the center of the arc */
|
||||||
|
intersect (n1x, n1y, pd1, n2x, n2y, pd2, &ix, &iy);
|
||||||
|
|
||||||
|
nx = (bx - ax) / dist1;
|
||||||
|
ny = (by - ay) / dist1;
|
||||||
|
d = point_line_distance (ix, iy, nx, ny);
|
||||||
|
|
||||||
|
/* a1 is the point on the line a-b where the arc starts */
|
||||||
|
intersect (n1x, n1y, d1, nx, ny, d, &a1x, &a1y);
|
||||||
|
|
||||||
|
nx = (cx - bx) / dist2;
|
||||||
|
ny = (cy - by) / dist2;
|
||||||
|
d = point_line_distance (ix, iy, nx, ny);
|
||||||
|
|
||||||
|
/* c1 is the point on the line b-c where the arc ends */
|
||||||
|
intersect (n2x, n2y, d2, nx, ny, d, &c1x, &c1y);
|
||||||
|
|
||||||
|
/* determine the first angle */
|
||||||
|
if (a1x - ix == 0)
|
||||||
|
phi1 = (a1y - iy > 0) ? M_PI_2 : 3 * M_PI_2;
|
||||||
|
else if (a1x - ix > 0)
|
||||||
|
phi1 = atan ((a1y - iy) / (a1x - ix));
|
||||||
|
else
|
||||||
|
phi1 = M_PI + atan ((a1y - iy) / (a1x - ix));
|
||||||
|
|
||||||
|
/* determine the second angle */
|
||||||
|
if (c1x - ix == 0)
|
||||||
|
phi2 = (c1y - iy > 0) ? M_PI_2 : 3 * M_PI_2;
|
||||||
|
else if (c1x - ix > 0)
|
||||||
|
phi2 = atan ((c1y - iy) / (c1x - ix));
|
||||||
|
else
|
||||||
|
phi2 = M_PI + atan ((c1y - iy) / (c1x - ix));
|
||||||
|
|
||||||
|
/* compute the difference between phi2 and phi1 mod 2pi */
|
||||||
|
d = phi2 - phi1;
|
||||||
|
while (d < 0)
|
||||||
|
d += 2 * M_PI;
|
||||||
|
while (d > 2 * M_PI)
|
||||||
|
d -= 2 * M_PI;
|
||||||
|
|
||||||
|
#ifdef KBDRAW_DEBUG
|
||||||
|
printf (" line 1 to: (%f, %f):\n", a1x, a1y);
|
||||||
|
#endif
|
||||||
|
if (!(isnan (a1x) || isnan (a1y)))
|
||||||
|
cairo_line_to (cr, a1x, a1y);
|
||||||
|
|
||||||
|
/* pick the short arc from phi1 to phi2 */
|
||||||
|
if (d < M_PI)
|
||||||
|
cairo_arc (cr, ix, iy, radius, phi1, phi2);
|
||||||
|
else
|
||||||
|
cairo_arc_negative (cr, ix, iy, radius, phi1, phi2);
|
||||||
|
|
||||||
|
#ifdef KBDRAW_DEBUG
|
||||||
|
printf (" line 2 to: (%f, %f):\n", cx, cy);
|
||||||
|
#endif
|
||||||
|
cairo_line_to (cr, cx, cy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* renamed from rounded_polygon, use EekPoint instead of GdkPoint not
|
||||||
|
to depend on GTK+, and exported */
|
||||||
|
void
|
||||||
|
_eek_rounded_polygon (cairo_t *cr,
|
||||||
|
gdouble radius,
|
||||||
|
EekPoint *points,
|
||||||
|
guint num_points)
|
||||||
|
{
|
||||||
|
cairo_move_to (cr,
|
||||||
|
(gdouble) (points[num_points - 1].x +
|
||||||
|
points[0].x) / 2,
|
||||||
|
(gdouble) (points[num_points - 1].y +
|
||||||
|
points[0].y) / 2);
|
||||||
|
|
||||||
|
for (guint i = 0; i < num_points; i++) {
|
||||||
|
guint j = (i + 1) % num_points;
|
||||||
|
rounded_corner (cr, (gdouble) points[i].x,
|
||||||
|
(gdouble) points[i].y,
|
||||||
|
(gdouble) (points[i].x + points[j].x) / 2,
|
||||||
|
(gdouble) (points[i].y + points[j].y) / 2,
|
||||||
|
radius);
|
||||||
|
}
|
||||||
|
cairo_close_path (cr);
|
||||||
|
}
|
||||||
@ -34,6 +34,7 @@
|
|||||||
#include "eekboard/key-emitter.h"
|
#include "eekboard/key-emitter.h"
|
||||||
#include "keymap.h"
|
#include "keymap.h"
|
||||||
#include "src/keyboard.h"
|
#include "src/keyboard.h"
|
||||||
|
#include "src/symbol.h"
|
||||||
|
|
||||||
#include "eek-keyboard.h"
|
#include "eek-keyboard.h"
|
||||||
|
|
||||||
@ -49,52 +50,76 @@ eek_modifier_key_free (EekModifierKey *modkey)
|
|||||||
g_slice_free (EekModifierKey, modkey);
|
g_slice_free (EekModifierKey, modkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
/// Updates the state of locked keys based on the key that was activated
|
||||||
eek_keyboard_set_key_locked (LevelKeyboard *keyboard,
|
/// FIXME: make independent of what the key are named,
|
||||||
struct squeek_key *key)
|
/// and instead refer to the contained symbols
|
||||||
|
static guint
|
||||||
|
set_key_states (LevelKeyboard *keyboard,
|
||||||
|
struct squeek_button *button,
|
||||||
|
guint new_level)
|
||||||
{
|
{
|
||||||
EekModifierKey *modifier_key = g_slice_new (EekModifierKey);
|
struct squeek_key *key = squeek_button_get_key(button);
|
||||||
modifier_key->modifiers = 0;
|
// Keys locking rules hardcoded for the time being...
|
||||||
modifier_key->key = key;
|
const gchar *name = squeek_symbol_get_name(squeek_key_get_symbol(key));
|
||||||
keyboard->locked_keys =
|
// Lock the shift whenever it's pressed on the baselevel
|
||||||
g_list_prepend (keyboard->locked_keys, modifier_key);
|
// 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);
|
||||||
/// Unlock all locked keys.
|
modifier_key->modifiers = 0;
|
||||||
/// All locked keys will unlock at the next keypress (should be called "stuck")
|
modifier_key->button = button;
|
||||||
/// Returns the number of handled keys
|
keyboard->locked_buttons =
|
||||||
/// TODO: may need to check key type in order to chain locks
|
g_list_prepend (keyboard->locked_buttons, modifier_key);
|
||||||
/// before pressing an "emitting" key
|
squeek_key_set_locked(key, true);
|
||||||
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;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: unhardcode, parse some user information as to which key triggers which view (level)
|
||||||
static void
|
static void
|
||||||
set_level_from_press (LevelKeyboard *keyboard, struct squeek_key *key)
|
set_level_from_press (LevelKeyboard *keyboard, struct squeek_button *button)
|
||||||
{
|
{
|
||||||
// If the currently locked key was already handled in the unlock phase,
|
/* The levels are: 0 Letters, 1 Upper case letters, 2 Numbers, 3 Symbols */
|
||||||
// then skip
|
guint level = keyboard->level;
|
||||||
if (unlock_keys(keyboard) == 0) {
|
/* Handle non-emitting keys */
|
||||||
squeek_layout_set_state_from_press(keyboard->layout, keyboard, key);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keyboard->level = set_key_states(keyboard, button, level);
|
||||||
|
|
||||||
|
eek_layout_update_layout(keyboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
void eek_keyboard_press_key(LevelKeyboard *keyboard, struct squeek_key *key, guint32 timestamp) {
|
void eek_keyboard_press_button(LevelKeyboard *keyboard, struct squeek_button *button, guint32 timestamp) {
|
||||||
|
struct squeek_key *key = squeek_button_get_key(button);
|
||||||
squeek_key_set_pressed(key, TRUE);
|
squeek_key_set_pressed(key, TRUE);
|
||||||
keyboard->pressed_keys = g_list_prepend (keyboard->pressed_keys, key);
|
keyboard->pressed_buttons = g_list_prepend (keyboard->pressed_buttons, button);
|
||||||
|
|
||||||
|
struct squeek_symbol *symbol = squeek_key_get_symbol(key);
|
||||||
|
if (!symbol)
|
||||||
|
return;
|
||||||
|
|
||||||
// Only take action about setting level *after* the key has taken effect, i.e. on release
|
// Only take action about setting level *after* the key has taken effect, i.e. on release
|
||||||
//set_level_from_press (keyboard, key);
|
//set_level_from_press (keyboard, key);
|
||||||
@ -106,28 +131,43 @@ void eek_keyboard_press_key(LevelKeyboard *keyboard, struct squeek_key *key, gui
|
|||||||
emit_key_activated(keyboard->manager, keyboard, keycode, TRUE, timestamp);
|
emit_key_activated(keyboard->manager, keyboard, keycode, TRUE, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void eek_keyboard_release_key(LevelKeyboard *keyboard,
|
void eek_keyboard_release_button(LevelKeyboard *keyboard,
|
||||||
struct squeek_key *key,
|
struct squeek_button *button,
|
||||||
guint32 timestamp) {
|
guint32 timestamp) {
|
||||||
for (GList *head = keyboard->pressed_keys; head; head = g_list_next (head)) {
|
for (GList *head = keyboard->pressed_buttons; head; head = g_list_next (head)) {
|
||||||
if (squeek_key_equal(head->data, key)) {
|
if (head->data == button) {
|
||||||
keyboard->pressed_keys = g_list_remove_link (keyboard->pressed_keys, head);
|
keyboard->pressed_buttons = g_list_remove_link (keyboard->pressed_buttons, head);
|
||||||
g_list_free1 (head);
|
g_list_free1 (head);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set_level_from_press (keyboard, key);
|
struct squeek_symbol *symbol = squeek_button_get_symbol(button);
|
||||||
|
if (!symbol)
|
||||||
|
return;
|
||||||
|
|
||||||
|
set_level_from_press (keyboard, button);
|
||||||
|
|
||||||
// "Borrowed" from eek-context-service; doesn't influence the state but forwards the event
|
// "Borrowed" from eek-context-service; doesn't influence the state but forwards the event
|
||||||
|
|
||||||
guint keycode = squeek_key_get_keycode (key);
|
guint keycode = squeek_key_get_keycode (squeek_button_get_key(button));
|
||||||
|
|
||||||
emit_key_activated(keyboard->manager, keyboard, keycode, FALSE, timestamp);
|
emit_key_activated(keyboard->manager, keyboard, keycode, FALSE, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void level_keyboard_deinit(LevelKeyboard *self) {
|
void level_keyboard_deinit(LevelKeyboard *self) {
|
||||||
squeek_layout_free(self->layout);
|
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];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void level_keyboard_free(LevelKeyboard *self) {
|
void level_keyboard_free(LevelKeyboard *self) {
|
||||||
@ -135,18 +175,115 @@ void level_keyboard_free(LevelKeyboard *self) {
|
|||||||
g_free(self);
|
g_free(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void level_keyboard_init(LevelKeyboard *self, struct squeek_layout *layout) {
|
void level_keyboard_init(LevelKeyboard *self) {
|
||||||
self->layout = layout;
|
self->outline_array = g_array_new (FALSE, TRUE, sizeof (EekOutline));
|
||||||
}
|
}
|
||||||
|
|
||||||
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_layout *layout) {
|
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_view *views[4], GHashTable *name_button_hash) {
|
||||||
LevelKeyboard *keyboard = g_new0(LevelKeyboard, 1);
|
LevelKeyboard *keyboard = g_new0(LevelKeyboard, 1);
|
||||||
level_keyboard_init(keyboard, layout);
|
level_keyboard_init(keyboard);
|
||||||
|
for (uint i = 0; i < 4; i++) {
|
||||||
|
keyboard->views[i] = views[i];
|
||||||
|
}
|
||||||
keyboard->manager = manager;
|
keyboard->manager = manager;
|
||||||
|
keyboard->names = name_button_hash;
|
||||||
return keyboard;
|
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)
|
struct squeek_view *level_keyboard_current(LevelKeyboard *keyboard)
|
||||||
{
|
{
|
||||||
return squeek_layout_get_current_view(keyboard->layout);
|
return keyboard->views[keyboard->level];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,19 +36,24 @@ G_BEGIN_DECLS
|
|||||||
struct _EekModifierKey {
|
struct _EekModifierKey {
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
EekModifierType modifiers;
|
EekModifierType modifiers;
|
||||||
struct squeek_key *key;
|
struct squeek_button *button;
|
||||||
};
|
};
|
||||||
typedef struct _EekModifierKey EekModifierKey;
|
typedef struct _EekModifierKey EekModifierKey;
|
||||||
|
|
||||||
/// Keyboard state holder
|
/// Keyboard state holder
|
||||||
struct _LevelKeyboard {
|
struct _LevelKeyboard {
|
||||||
struct squeek_layout *layout;
|
struct squeek_view *views[4];
|
||||||
|
guint level;
|
||||||
struct xkb_keymap *keymap;
|
struct xkb_keymap *keymap;
|
||||||
int keymap_fd; // keymap formatted as XKB string
|
int keymap_fd; // keymap formatted as XKB string
|
||||||
size_t keymap_len; // length of the data inside keymap_fd
|
size_t keymap_len; // length of the data inside keymap_fd
|
||||||
|
GArray *outline_array;
|
||||||
|
|
||||||
GList *pressed_keys; // struct squeek_key*
|
GList *pressed_buttons; // struct squeek_button*
|
||||||
GList *locked_keys; // struct EekModifierKey*
|
GList *locked_buttons; // struct squeek_button*
|
||||||
|
|
||||||
|
/* Map button names to button objects: */
|
||||||
|
GHashTable *names;
|
||||||
|
|
||||||
guint id; // as a key to layout choices
|
guint id; // as a key to layout choices
|
||||||
|
|
||||||
@ -56,25 +61,31 @@ struct _LevelKeyboard {
|
|||||||
};
|
};
|
||||||
typedef struct _LevelKeyboard 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
|
/// Represents the path to the button within a view
|
||||||
struct button_place {
|
struct button_place {
|
||||||
const struct squeek_row *row;
|
const struct squeek_row *row;
|
||||||
const struct squeek_button *button;
|
const struct squeek_button *button;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
EekOutline *level_keyboard_get_outline
|
||||||
|
(LevelKeyboard *keyboard,
|
||||||
|
guint oref);
|
||||||
EekModifierKey *eek_modifier_key_copy
|
EekModifierKey *eek_modifier_key_copy
|
||||||
(EekModifierKey *modkey);
|
(EekModifierKey *modkey);
|
||||||
void eek_modifier_key_free
|
void eek_modifier_key_free
|
||||||
(EekModifierKey *modkey);
|
(EekModifierKey *modkey);
|
||||||
|
|
||||||
void eek_keyboard_press_key(LevelKeyboard *keyboard, struct squeek_key *key, guint32 timestamp);
|
void eek_keyboard_press_button(LevelKeyboard *keyboard, struct squeek_button *button, guint32 timestamp);
|
||||||
void eek_keyboard_release_key(LevelKeyboard *keyboard, struct squeek_key *key, guint32 timestamp);
|
void eek_keyboard_release_button(LevelKeyboard *keyboard, struct squeek_button *button, guint32 timestamp);
|
||||||
|
|
||||||
gchar * eek_keyboard_get_keymap
|
gchar * eek_keyboard_get_keymap
|
||||||
(LevelKeyboard *keyboard);
|
(LevelKeyboard *keyboard);
|
||||||
|
|
||||||
struct squeek_view *level_keyboard_current(LevelKeyboard *keyboard);
|
struct squeek_view *level_keyboard_current(LevelKeyboard *keyboard);
|
||||||
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_layout *layout);
|
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_view *views[], GHashTable *name_button_hash);
|
||||||
void level_keyboard_deinit(LevelKeyboard *self);
|
void level_keyboard_deinit(LevelKeyboard *self);
|
||||||
void level_keyboard_free(LevelKeyboard *self);
|
void level_keyboard_free(LevelKeyboard *self);
|
||||||
|
|
||||||
|
|||||||
65
eek/eek-keysym.c
Normal file
65
eek/eek-keysym.c
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
32
eek/eek-keysym.h
Normal file
32
eek/eek-keysym.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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,3 +45,9 @@ void
|
|||||||
eek_layout_init (EekLayout *self)
|
eek_layout_init (EekLayout *self)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eek_layout_update_layout(LevelKeyboard *keyboard)
|
||||||
|
{
|
||||||
|
squeek_view_place_contents(level_keyboard_current(keyboard), keyboard);
|
||||||
|
}
|
||||||
|
|||||||
@ -56,5 +56,14 @@ struct _EekLayoutClass
|
|||||||
|
|
||||||
GType eek_layout_get_type (void) G_GNUC_CONST;
|
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
|
G_END_DECLS
|
||||||
#endif /* EEK_LAYOUT_H */
|
#endif /* EEK_LAYOUT_H */
|
||||||
|
|||||||
@ -24,11 +24,14 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
|
|
||||||
|
#include "src/symbol.h"
|
||||||
|
|
||||||
#include "eek-renderer.h"
|
#include "eek-renderer.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_PCONTEXT,
|
PROP_PCONTEXT,
|
||||||
|
PROP_STYLE_CONTEXT,
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -37,9 +40,11 @@ typedef struct _EekRendererPrivate
|
|||||||
LevelKeyboard *keyboard;
|
LevelKeyboard *keyboard;
|
||||||
PangoContext *pcontext;
|
PangoContext *pcontext;
|
||||||
GtkCssProvider *css_provider;
|
GtkCssProvider *css_provider;
|
||||||
GtkStyleContext *layout_context;
|
GtkStyleContext *scontext;
|
||||||
GtkStyleContext *button_context; // TODO: maybe move a copy to each button
|
GtkStyleContext *key_context;
|
||||||
|
|
||||||
|
EekColor default_foreground_color;
|
||||||
|
EekColor default_background_color;
|
||||||
gdouble border_width;
|
gdouble border_width;
|
||||||
|
|
||||||
gdouble allocation_width;
|
gdouble allocation_width;
|
||||||
@ -51,7 +56,6 @@ typedef struct _EekRendererPrivate
|
|||||||
|
|
||||||
PangoFontDescription *ascii_font;
|
PangoFontDescription *ascii_font;
|
||||||
PangoFontDescription *font;
|
PangoFontDescription *font;
|
||||||
// TODO: Drop those or transform into general button surface caches
|
|
||||||
GHashTable *outline_surface_cache;
|
GHashTable *outline_surface_cache;
|
||||||
GHashTable *active_outline_surface_cache;
|
GHashTable *active_outline_surface_cache;
|
||||||
GHashTable *icons;
|
GHashTable *icons;
|
||||||
@ -61,7 +65,15 @@ typedef struct _EekRendererPrivate
|
|||||||
|
|
||||||
G_DEFINE_TYPE_WITH_PRIVATE (EekRenderer, eek_renderer, G_TYPE_OBJECT)
|
G_DEFINE_TYPE_WITH_PRIVATE (EekRenderer, eek_renderer, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
static const EekColor DEFAULT_FOREGROUND_COLOR = {0.3, 0.3, 0.3, 1.0};
|
||||||
|
static const EekColor DEFAULT_BACKGROUND_COLOR = {1.0, 1.0, 1.0, 1.0};
|
||||||
|
|
||||||
/* eek-keyboard-drawing.c */
|
/* eek-keyboard-drawing.c */
|
||||||
|
extern void _eek_rounded_polygon (cairo_t *cr,
|
||||||
|
gdouble radius,
|
||||||
|
EekPoint *points,
|
||||||
|
guint num_points);
|
||||||
|
|
||||||
static void eek_renderer_real_render_button_label (EekRenderer *self,
|
static void eek_renderer_real_render_button_label (EekRenderer *self,
|
||||||
PangoLayout *layout,
|
PangoLayout *layout,
|
||||||
const struct squeek_button *button);
|
const struct squeek_button *button);
|
||||||
@ -69,7 +81,7 @@ static void eek_renderer_real_render_button_label (EekRenderer *self,
|
|||||||
static void invalidate (EekRenderer *renderer);
|
static void invalidate (EekRenderer *renderer);
|
||||||
static void render_button (EekRenderer *self,
|
static void render_button (EekRenderer *self,
|
||||||
cairo_t *cr, struct button_place *place,
|
cairo_t *cr, struct button_place *place,
|
||||||
gboolean pressed, gboolean locked);
|
gboolean active);
|
||||||
|
|
||||||
struct _CreateKeyboardSurfaceCallbackData {
|
struct _CreateKeyboardSurfaceCallbackData {
|
||||||
cairo_t *cr;
|
cairo_t *cr;
|
||||||
@ -99,7 +111,7 @@ create_keyboard_surface_button_callback (struct squeek_button *button,
|
|||||||
.row = data->row,
|
.row = data->row,
|
||||||
.button = button,
|
.button = button,
|
||||||
};
|
};
|
||||||
render_button (data->renderer, data->cr, &place, FALSE, FALSE);
|
render_button (data->renderer, data->cr, &place, FALSE);
|
||||||
|
|
||||||
cairo_restore (data->cr);
|
cairo_restore (data->cr);
|
||||||
}
|
}
|
||||||
@ -119,7 +131,8 @@ create_keyboard_surface_row_callback (struct squeek_row *row,
|
|||||||
cairo_rotate (data->cr, angle * G_PI / 180);
|
cairo_rotate (data->cr, angle * G_PI / 180);
|
||||||
|
|
||||||
data->row = row;
|
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);
|
cairo_restore (data->cr);
|
||||||
}
|
}
|
||||||
@ -130,7 +143,7 @@ render_keyboard_surface (EekRenderer *renderer, struct squeek_view *view)
|
|||||||
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
|
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
|
||||||
EekColor foreground;
|
EekColor foreground;
|
||||||
|
|
||||||
eek_renderer_get_foreground_color (renderer, priv->layout_context, &foreground);
|
eek_renderer_get_foreground_color (renderer, priv->scontext, &foreground);
|
||||||
|
|
||||||
EekBounds bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard));
|
EekBounds bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard));
|
||||||
|
|
||||||
@ -141,11 +154,11 @@ render_keyboard_surface (EekRenderer *renderer, struct squeek_view *view)
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Paint the background covering the entire widget area */
|
/* Paint the background covering the entire widget area */
|
||||||
gtk_render_background (priv->layout_context,
|
gtk_render_background (priv->scontext,
|
||||||
data.cr,
|
data.cr,
|
||||||
0, 0,
|
0, 0,
|
||||||
priv->allocation_width, priv->allocation_height);
|
priv->allocation_width, priv->allocation_height);
|
||||||
gtk_render_frame (priv->layout_context,
|
gtk_render_frame (priv->scontext,
|
||||||
data.cr,
|
data.cr,
|
||||||
0, 0,
|
0, 0,
|
||||||
priv->allocation_width, priv->allocation_height);
|
priv->allocation_width, priv->allocation_height);
|
||||||
@ -162,33 +175,57 @@ render_keyboard_surface (EekRenderer *renderer, struct squeek_view *view)
|
|||||||
|
|
||||||
/* draw rows */
|
/* draw rows */
|
||||||
squeek_view_foreach(level_keyboard_current(priv->keyboard),
|
squeek_view_foreach(level_keyboard_current(priv->keyboard),
|
||||||
create_keyboard_surface_row_callback,
|
create_keyboard_surface_row_callback,
|
||||||
&data);
|
&data);
|
||||||
cairo_restore (data.cr);
|
cairo_restore (data.cr);
|
||||||
|
|
||||||
cairo_destroy (data.cr);
|
cairo_destroy (data.cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
render_outline (cairo_t *cr,
|
render_button_outline (EekRenderer *renderer,
|
||||||
GtkStyleContext *ctx,
|
cairo_t *cr,
|
||||||
EekBounds bounds)
|
const struct squeek_button *button,
|
||||||
|
gboolean active)
|
||||||
{
|
{
|
||||||
gtk_render_background (ctx, cr, 0, 0, bounds.width, bounds.height);
|
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
|
||||||
gtk_render_frame (ctx, cr, 0, 0, bounds.width, bounds.height);
|
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);
|
||||||
|
gtk_style_context_set_state(priv->key_context,
|
||||||
|
active ? GTK_STATE_FLAG_ACTIVE : GTK_STATE_FLAG_NORMAL);
|
||||||
|
|
||||||
|
gtk_render_background (priv->key_context,
|
||||||
|
cr, 0, 0, bounds.width, bounds.height);
|
||||||
|
gtk_render_frame (priv->key_context,
|
||||||
|
cr, 0, 0, bounds.width, bounds.height);
|
||||||
|
|
||||||
|
gtk_style_context_set_state(priv->key_context, GTK_STATE_FLAG_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void render_button_in_context(EekRenderer *self,
|
static void
|
||||||
cairo_t *cr,
|
render_button (EekRenderer *self,
|
||||||
GtkStyleContext *ctx,
|
cairo_t *cr,
|
||||||
struct button_place *place,
|
struct button_place *place,
|
||||||
gboolean active) {
|
gboolean active)
|
||||||
|
{
|
||||||
|
EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
|
||||||
|
EekOutline *outline;
|
||||||
cairo_surface_t *outline_surface;
|
cairo_surface_t *outline_surface;
|
||||||
GHashTable *outline_surface_cache;
|
GHashTable *outline_surface_cache;
|
||||||
PangoLayout *layout;
|
PangoLayout *layout;
|
||||||
PangoRectangle extents = { 0, };
|
PangoRectangle extents = { 0, };
|
||||||
EekColor foreground;
|
EekColor foreground;
|
||||||
EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
|
|
||||||
|
guint oref = squeek_button_get_oref (place->button);
|
||||||
|
outline = level_keyboard_get_outline (priv->keyboard, oref);
|
||||||
|
if (outline == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
/* render outline */
|
/* render outline */
|
||||||
EekBounds bounds = squeek_button_get_bounds(place->button);
|
EekBounds bounds = squeek_button_get_bounds(place->button);
|
||||||
@ -198,8 +235,7 @@ static void render_button_in_context(EekRenderer *self,
|
|||||||
else
|
else
|
||||||
outline_surface_cache = priv->outline_surface_cache;
|
outline_surface_cache = priv->outline_surface_cache;
|
||||||
|
|
||||||
outline_surface = g_hash_table_lookup (outline_surface_cache, place->button);
|
outline_surface = g_hash_table_lookup (outline_surface_cache, outline);
|
||||||
|
|
||||||
if (!outline_surface) {
|
if (!outline_surface) {
|
||||||
cairo_t *cr;
|
cairo_t *cr;
|
||||||
|
|
||||||
@ -217,26 +253,31 @@ static void render_button_in_context(EekRenderer *self,
|
|||||||
|
|
||||||
cairo_save (cr);
|
cairo_save (cr);
|
||||||
eek_renderer_apply_transformation_for_button (self, cr, place, 1.0, FALSE);
|
eek_renderer_apply_transformation_for_button (self, cr, place, 1.0, FALSE);
|
||||||
render_outline (cr, ctx, bounds);
|
render_button_outline (self, cr, place->button, active);
|
||||||
cairo_restore (cr);
|
cairo_restore (cr);
|
||||||
|
|
||||||
cairo_destroy (cr);
|
cairo_destroy (cr);
|
||||||
|
|
||||||
g_hash_table_insert (outline_surface_cache,
|
g_hash_table_insert (outline_surface_cache,
|
||||||
(gpointer)place->button,
|
outline,
|
||||||
outline_surface);
|
outline_surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_set_source_surface (cr, outline_surface, 0.0, 0.0);
|
cairo_set_source_surface (cr, outline_surface, 0.0, 0.0);
|
||||||
cairo_paint (cr);
|
cairo_paint (cr);
|
||||||
|
|
||||||
eek_renderer_get_foreground_color (self, ctx, &foreground);
|
eek_renderer_get_foreground_color (self, priv->key_context, &foreground);
|
||||||
/* render icon (if any) */
|
/* render icon (if any) */
|
||||||
const char *icon_name = squeek_button_get_icon_name(place->button);
|
struct squeek_symbol *symbol = squeek_button_get_symbol(place->button);
|
||||||
|
if (!symbol)
|
||||||
|
return;
|
||||||
|
|
||||||
if (icon_name) {
|
if (squeek_symbol_get_icon_name (symbol)) {
|
||||||
gint scale = priv->scale_factor;
|
gint scale = priv->scale_factor;
|
||||||
cairo_surface_t *icon_surface =
|
cairo_surface_t *icon_surface =
|
||||||
eek_renderer_get_icon_surface (self, icon_name, 16 / priv->scale,
|
eek_renderer_get_icon_surface (self,
|
||||||
|
squeek_symbol_get_icon_name (symbol),
|
||||||
|
16 / priv->scale,
|
||||||
scale);
|
scale);
|
||||||
if (icon_surface) {
|
if (icon_surface) {
|
||||||
gint width = cairo_image_surface_get_width (icon_surface);
|
gint width = cairo_image_surface_get_width (icon_surface);
|
||||||
@ -260,6 +301,7 @@ static void render_button_in_context(EekRenderer *self,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* render label */
|
/* render label */
|
||||||
layout = pango_cairo_create_layout (cr);
|
layout = pango_cairo_create_layout (cr);
|
||||||
eek_renderer_real_render_button_label (self, layout, place->button);
|
eek_renderer_real_render_button_label (self, layout, place->button);
|
||||||
@ -276,49 +318,10 @@ static void render_button_in_context(EekRenderer *self,
|
|||||||
foreground.green,
|
foreground.green,
|
||||||
foreground.blue,
|
foreground.blue,
|
||||||
foreground.alpha);
|
foreground.alpha);
|
||||||
|
|
||||||
pango_cairo_show_layout (cr, layout);
|
pango_cairo_show_layout (cr, layout);
|
||||||
cairo_restore (cr);
|
cairo_restore (cr);
|
||||||
g_object_unref (layout);
|
g_object_unref (layout);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
render_button (EekRenderer *self,
|
|
||||||
cairo_t *cr,
|
|
||||||
struct button_place *place,
|
|
||||||
gboolean pressed,
|
|
||||||
gboolean locked)
|
|
||||||
{
|
|
||||||
EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
|
|
||||||
|
|
||||||
GtkStyleContext *ctx = priv->button_context;
|
|
||||||
/* Set the name of the button on the widget path, using the name obtained
|
|
||||||
from the button's symbol. */
|
|
||||||
g_autoptr (GtkWidgetPath) path = NULL;
|
|
||||||
path = gtk_widget_path_copy (gtk_style_context_get_path (ctx));
|
|
||||||
const char *name = squeek_button_get_name(place->button);
|
|
||||||
gtk_widget_path_iter_set_name (path, -1, name);
|
|
||||||
|
|
||||||
/* Update the style context with the updated widget path. */
|
|
||||||
gtk_style_context_set_path (ctx, path);
|
|
||||||
/* Set the state to take into account whether the button is active
|
|
||||||
(pressed) or normal. */
|
|
||||||
gtk_style_context_set_state(ctx,
|
|
||||||
pressed ? GTK_STATE_FLAG_ACTIVE : GTK_STATE_FLAG_NORMAL);
|
|
||||||
const char *outline_name = squeek_button_get_outline_name(place->button);
|
|
||||||
if (locked) {
|
|
||||||
gtk_style_context_add_class(ctx, "locked");
|
|
||||||
}
|
|
||||||
gtk_style_context_add_class(ctx, outline_name);
|
|
||||||
|
|
||||||
render_button_in_context(self, cr, ctx, place, pressed);
|
|
||||||
|
|
||||||
// Save and restore functions don't work if gtk_render_* was used in between
|
|
||||||
gtk_style_context_set_state(ctx, GTK_STATE_FLAG_NORMAL);
|
|
||||||
gtk_style_context_remove_class(ctx, outline_name);
|
|
||||||
if (locked) {
|
|
||||||
gtk_style_context_remove_class(ctx, "locked");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -369,16 +372,18 @@ eek_renderer_real_render_button_label (EekRenderer *self,
|
|||||||
{
|
{
|
||||||
EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
|
EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
|
||||||
|
|
||||||
const gchar *label = squeek_button_get_label(button);
|
const gchar *label;
|
||||||
|
|
||||||
if (!label) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PangoFontDescription *font;
|
PangoFontDescription *font;
|
||||||
PangoLayoutLine *line;
|
PangoLayoutLine *line;
|
||||||
gdouble scale;
|
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) {
|
if (!priv->font) {
|
||||||
const PangoFontDescription *base_font;
|
const PangoFontDescription *base_font;
|
||||||
@ -449,8 +454,7 @@ eek_renderer_real_render_button (EekRenderer *self,
|
|||||||
struct squeek_key *key = squeek_button_get_key(place->button);
|
struct squeek_key *key = squeek_button_get_key(place->button);
|
||||||
render_button (
|
render_button (
|
||||||
self, cr, place,
|
self, cr, place,
|
||||||
squeek_key_is_pressed(key),
|
squeek_key_is_pressed(key) || squeek_key_is_locked (key)
|
||||||
squeek_key_is_locked (key)
|
|
||||||
);
|
);
|
||||||
cairo_restore (cr);
|
cairo_restore (cr);
|
||||||
}
|
}
|
||||||
@ -477,7 +481,7 @@ eek_renderer_real_render_keyboard (EekRenderer *self,
|
|||||||
cairo_get_target (cr), 0, 0,
|
cairo_get_target (cr), 0, 0,
|
||||||
priv->allocation_width, priv->allocation_height);
|
priv->allocation_width, priv->allocation_height);
|
||||||
|
|
||||||
render_keyboard_surface (self, squeek_layout_get_current_view(priv->keyboard->layout));
|
render_keyboard_surface (self, priv->keyboard->views[priv->keyboard->level]);
|
||||||
|
|
||||||
cairo_set_source_surface (cr, priv->keyboard_surface, 0.0, 0.0);
|
cairo_set_source_surface (cr, priv->keyboard_surface, 0.0, 0.0);
|
||||||
source = cairo_get_source (cr);
|
source = cairo_get_source (cr);
|
||||||
@ -501,6 +505,10 @@ eek_renderer_set_property (GObject *object,
|
|||||||
priv->pcontext = g_value_get_object (value);
|
priv->pcontext = g_value_get_object (value);
|
||||||
g_object_ref (priv->pcontext);
|
g_object_ref (priv->pcontext);
|
||||||
break;
|
break;
|
||||||
|
case PROP_STYLE_CONTEXT:
|
||||||
|
priv->scontext = g_value_get_object (value);
|
||||||
|
g_object_ref (priv->scontext);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -577,33 +585,15 @@ eek_renderer_class_init (EekRendererClass *klass)
|
|||||||
g_object_class_install_property (gobject_class,
|
g_object_class_install_property (gobject_class,
|
||||||
PROP_PCONTEXT,
|
PROP_PCONTEXT,
|
||||||
pspec);
|
pspec);
|
||||||
}
|
|
||||||
|
|
||||||
|
pspec = g_param_spec_object ("style-context",
|
||||||
static GType new_type(char *name) {
|
"GTK Style Context",
|
||||||
GTypeInfo info = {0};
|
"GTK Style Context",
|
||||||
info.class_size = sizeof(GtkWidgetClass);
|
GTK_TYPE_STYLE_CONTEXT,
|
||||||
info.instance_size = sizeof(GtkWidget);
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE);
|
||||||
|
g_object_class_install_property (gobject_class,
|
||||||
return g_type_register_static(GTK_TYPE_WIDGET, name, &info,
|
PROP_STYLE_CONTEXT,
|
||||||
G_TYPE_FLAG_ABSTRACT
|
pspec);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GType layout_type() {
|
|
||||||
static GType type = 0;
|
|
||||||
if (!type) {
|
|
||||||
type = new_type("sq_view");
|
|
||||||
}
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GType button_type() {
|
|
||||||
static GType type = 0;
|
|
||||||
if (!type) {
|
|
||||||
type = new_type("sq_button");
|
|
||||||
}
|
|
||||||
return type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -613,6 +603,8 @@ eek_renderer_init (EekRenderer *self)
|
|||||||
|
|
||||||
priv->keyboard = NULL;
|
priv->keyboard = NULL;
|
||||||
priv->pcontext = NULL;
|
priv->pcontext = NULL;
|
||||||
|
priv->default_foreground_color = DEFAULT_FOREGROUND_COLOR;
|
||||||
|
priv->default_background_color = DEFAULT_BACKGROUND_COLOR;
|
||||||
priv->border_width = 1.0;
|
priv->border_width = 1.0;
|
||||||
priv->allocation_width = 0.0;
|
priv->allocation_width = 0.0;
|
||||||
priv->allocation_height = 0.0;
|
priv->allocation_height = 0.0;
|
||||||
@ -644,30 +636,18 @@ eek_renderer_init (EekRenderer *self)
|
|||||||
gtk_css_provider_load_from_resource (priv->css_provider,
|
gtk_css_provider_load_from_resource (priv->css_provider,
|
||||||
"/sm/puri/squeekboard/style.css");
|
"/sm/puri/squeekboard/style.css");
|
||||||
|
|
||||||
/* Create a style context for the layout */
|
/* Create a style context for keys */
|
||||||
GtkWidgetPath *path = gtk_widget_path_new();
|
priv->key_context = gtk_style_context_new ();
|
||||||
gtk_widget_path_append_type(path, layout_type());
|
gtk_style_context_add_class (priv->key_context, "key");
|
||||||
|
gtk_style_context_add_provider (priv->key_context,
|
||||||
priv->layout_context = gtk_style_context_new();
|
|
||||||
gtk_style_context_set_path(priv->layout_context, path);
|
|
||||||
gtk_widget_path_unref(path);
|
|
||||||
gtk_style_context_add_provider (priv->layout_context,
|
|
||||||
GTK_STYLE_PROVIDER(priv->css_provider),
|
GTK_STYLE_PROVIDER(priv->css_provider),
|
||||||
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||||
|
|
||||||
/* Create a style context for the buttons */
|
g_autoptr (GtkWidgetPath) path = NULL;
|
||||||
path = gtk_widget_path_new();
|
path = gtk_widget_path_new ();
|
||||||
gtk_widget_path_append_type(path, layout_type());
|
gtk_widget_path_append_type (path, GTK_TYPE_BUTTON);
|
||||||
gtk_widget_path_append_type(path, button_type());
|
gtk_style_context_set_path (priv->key_context, path);
|
||||||
priv->button_context = gtk_style_context_new ();
|
gtk_style_context_set_state (priv->key_context, GTK_STATE_FLAG_NORMAL);
|
||||||
gtk_style_context_set_path(priv->button_context, path);
|
|
||||||
gtk_widget_path_unref(path);
|
|
||||||
|
|
||||||
gtk_style_context_set_parent(priv->button_context, priv->layout_context);
|
|
||||||
gtk_style_context_set_state (priv->button_context, GTK_STATE_FLAG_NORMAL);
|
|
||||||
gtk_style_context_add_provider (priv->button_context,
|
|
||||||
GTK_STYLE_PROVIDER(priv->css_provider),
|
|
||||||
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -689,10 +669,12 @@ invalidate (EekRenderer *renderer)
|
|||||||
|
|
||||||
EekRenderer *
|
EekRenderer *
|
||||||
eek_renderer_new (LevelKeyboard *keyboard,
|
eek_renderer_new (LevelKeyboard *keyboard,
|
||||||
PangoContext *pcontext)
|
PangoContext *pcontext,
|
||||||
|
GtkStyleContext *scontext)
|
||||||
{
|
{
|
||||||
EekRenderer *renderer = g_object_new (EEK_TYPE_RENDERER,
|
EekRenderer *renderer = g_object_new (EEK_TYPE_RENDERER,
|
||||||
"pango-context", pcontext,
|
"pango-context", pcontext,
|
||||||
|
"style-context", scontext,
|
||||||
NULL);
|
NULL);
|
||||||
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
|
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
|
||||||
priv->keyboard = keyboard;
|
priv->keyboard = keyboard;
|
||||||
@ -786,7 +768,7 @@ eek_renderer_get_button_bounds (EekRenderer *renderer,
|
|||||||
|
|
||||||
min = points[2];
|
min = points[2];
|
||||||
max = points[0];
|
max = points[0];
|
||||||
for (unsigned i = 0; i < G_N_ELEMENTS(points); i++) {
|
for (uint i = 0; i < G_N_ELEMENTS(points); i++) {
|
||||||
eek_point_rotate (&points[i], angle);
|
eek_point_rotate (&points[i], angle);
|
||||||
if (points[i].x < min.x)
|
if (points[i].x < min.x)
|
||||||
min.x = points[i].x;
|
min.x = points[i].x;
|
||||||
@ -889,6 +871,30 @@ eek_renderer_render_keyboard (EekRenderer *renderer,
|
|||||||
EEK_RENDERER_GET_CLASS(renderer)->render_keyboard (renderer, cr);
|
EEK_RENDERER_GET_CLASS(renderer)->render_keyboard (renderer, cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eek_renderer_set_default_foreground_color (EekRenderer *renderer,
|
||||||
|
const EekColor *color)
|
||||||
|
{
|
||||||
|
g_return_if_fail (EEK_IS_RENDERER(renderer));
|
||||||
|
g_return_if_fail (color);
|
||||||
|
|
||||||
|
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
|
||||||
|
|
||||||
|
memcpy (&priv->default_foreground_color, color, sizeof(EekColor));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eek_renderer_set_default_background_color (EekRenderer *renderer,
|
||||||
|
const EekColor *color)
|
||||||
|
{
|
||||||
|
g_return_if_fail (EEK_IS_RENDERER(renderer));
|
||||||
|
g_return_if_fail (color);
|
||||||
|
|
||||||
|
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
|
||||||
|
|
||||||
|
memcpy (&priv->default_background_color, color, sizeof(EekColor));
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
eek_renderer_get_foreground_color (EekRenderer *renderer,
|
eek_renderer_get_foreground_color (EekRenderer *renderer,
|
||||||
GtkStyleContext *context,
|
GtkStyleContext *context,
|
||||||
@ -930,7 +936,7 @@ eek_are_bounds_inside (EekBounds bounds, EekPoint point, EekPoint origin, int32_
|
|||||||
points[3].x = points[0].x;
|
points[3].x = points[0].x;
|
||||||
points[3].y = points[2].y;
|
points[3].y = points[2].y;
|
||||||
|
|
||||||
for (unsigned i = 0; i < G_N_ELEMENTS(points); i++) {
|
for (uint i = 0; i < G_N_ELEMENTS(points); i++) {
|
||||||
eek_point_rotate (&points[i], angle);
|
eek_point_rotate (&points[i], angle);
|
||||||
points[i].x += origin.x;
|
points[i].x += origin.x;
|
||||||
points[i].y += origin.y;
|
points[i].y += origin.y;
|
||||||
@ -965,15 +971,14 @@ eek_are_bounds_inside (EekBounds bounds, EekPoint point, EekPoint origin, int32_
|
|||||||
**/
|
**/
|
||||||
struct squeek_button *
|
struct squeek_button *
|
||||||
eek_renderer_find_button_by_position (EekRenderer *renderer,
|
eek_renderer_find_button_by_position (EekRenderer *renderer,
|
||||||
struct squeek_view *view,
|
struct squeek_view *view,
|
||||||
gdouble x,
|
gdouble x,
|
||||||
gdouble y)
|
gdouble y)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (EEK_IS_RENDERER(renderer), NULL);
|
g_return_val_if_fail (EEK_IS_RENDERER(renderer), NULL);
|
||||||
|
|
||||||
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
|
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
|
||||||
|
|
||||||
/* Transform from widget coordinates to keyboard coordinates */
|
|
||||||
EekPoint point = {
|
EekPoint point = {
|
||||||
.x = (x - priv->origin_x)/priv->scale,
|
.x = (x - priv->origin_x)/priv->scale,
|
||||||
.y = (y - priv->origin_y)/priv->scale,
|
.y = (y - priv->origin_y)/priv->scale,
|
||||||
|
|||||||
@ -57,7 +57,8 @@ struct _EekRendererClass
|
|||||||
|
|
||||||
GType eek_renderer_get_type (void) G_GNUC_CONST;
|
GType eek_renderer_get_type (void) G_GNUC_CONST;
|
||||||
EekRenderer *eek_renderer_new (LevelKeyboard *keyboard,
|
EekRenderer *eek_renderer_new (LevelKeyboard *keyboard,
|
||||||
PangoContext *pcontext);
|
PangoContext *pcontext,
|
||||||
|
GtkStyleContext *scontext);
|
||||||
void eek_renderer_set_allocation_size
|
void eek_renderer_set_allocation_size
|
||||||
(EekRenderer *renderer,
|
(EekRenderer *renderer,
|
||||||
gdouble width,
|
gdouble width,
|
||||||
|
|||||||
56
eek/eek-section.c
Normal file
56
eek/eek-section.c
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
34
eek/eek-section.h
Normal file
34
eek/eek-section.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* 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,11 +23,47 @@
|
|||||||
#ifndef EEK_XML_LAYOUT_H
|
#ifndef EEK_XML_LAYOUT_H
|
||||||
#define EEK_XML_LAYOUT_H 1
|
#define EEK_XML_LAYOUT_H 1
|
||||||
|
|
||||||
#include "eek-types.h"
|
#include <gio/gio.h>
|
||||||
|
#include "eek-layout.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
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 *
|
LevelKeyboard *
|
||||||
eek_xml_layout_real_create_keyboard (const char *keyboard_type,
|
eek_xml_layout_real_create_keyboard (EekLayout *self,
|
||||||
EekboardContextService *manager);
|
EekboardContextService *manager);
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
#endif /* EEK_XML_LAYOUT_H */
|
#endif /* EEK_XML_LAYOUT_H */
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "eek-keyboard.h"
|
#include "eek-keyboard.h"
|
||||||
#include "eek-layout.h"
|
#include "eek-layout.h"
|
||||||
|
#include "eek-keysym.h"
|
||||||
|
|
||||||
void eek_init (void);
|
void eek_init (void);
|
||||||
|
|
||||||
|
|||||||
50
eek/gen-keysym-entries.py
Executable file
50
eek/gen-keysym-entries.py
Executable file
@ -0,0 +1,50 @@
|
|||||||
|
#!/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,3 +6,34 @@ squeek_keymap_get_entries_for_keyval (struct xkb_keymap *xkb_keymap,
|
|||||||
guint keyval,
|
guint keyval,
|
||||||
GdkKeymapKey **keys,
|
GdkKeymapKey **keys,
|
||||||
guint *n_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,3 +6,15 @@ enum_headers = [
|
|||||||
|
|
||||||
enums = gnome.mkenums_simple('eek-enumtypes', sources: 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'),
|
||||||
|
]
|
||||||
|
|||||||
1306
eek/xkeysym-keysym-entries.txt
Normal file
1306
eek/xkeysym-keysym-entries.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -29,7 +29,6 @@
|
|||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#define _XOPEN_SOURCE 500
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/random.h> // TODO: this is Linux-specific
|
#include <sys/random.h> // TODO: this is Linux-specific
|
||||||
@ -51,6 +50,7 @@ enum {
|
|||||||
PROP_0, // Magic: without this, keyboard is not useable in g_object_notify
|
PROP_0, // Magic: without this, keyboard is not useable in g_object_notify
|
||||||
PROP_KEYBOARD,
|
PROP_KEYBOARD,
|
||||||
PROP_VISIBLE,
|
PROP_VISIBLE,
|
||||||
|
PROP_FULLSCREEN,
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -69,6 +69,7 @@ static guint signals[LAST_SIGNAL] = { 0, };
|
|||||||
struct _EekboardContextServicePrivate {
|
struct _EekboardContextServicePrivate {
|
||||||
gboolean enabled;
|
gboolean enabled;
|
||||||
gboolean visible;
|
gboolean visible;
|
||||||
|
gboolean fullscreen;
|
||||||
|
|
||||||
LevelKeyboard *keyboard; // currently used keyboard
|
LevelKeyboard *keyboard; // currently used keyboard
|
||||||
GHashTable *keyboard_hash; // a table of available keyboards, per layout
|
GHashTable *keyboard_hash; // a table of available keyboards, per layout
|
||||||
@ -88,17 +89,66 @@ static LevelKeyboard *
|
|||||||
eekboard_context_service_real_create_keyboard (EekboardContextService *self,
|
eekboard_context_service_real_create_keyboard (EekboardContextService *self,
|
||||||
const gchar *keyboard_type)
|
const gchar *keyboard_type)
|
||||||
{
|
{
|
||||||
LevelKeyboard *keyboard = eek_xml_layout_real_create_keyboard(keyboard_type, self);
|
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);
|
||||||
if (!keyboard) {
|
if (!keyboard) {
|
||||||
g_error("Failed to create a keyboard");
|
g_error("Failed to create a keyboard");
|
||||||
}
|
}
|
||||||
|
g_object_unref (layout);
|
||||||
|
|
||||||
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||||
if (!context) {
|
if (!context) {
|
||||||
g_error("No context created");
|
g_error("No context created");
|
||||||
}
|
}
|
||||||
|
|
||||||
const gchar *keymap_str = squeek_layout_get_keymap(keyboard->layout);
|
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);
|
||||||
|
|
||||||
struct xkb_keymap *keymap = xkb_keymap_new_from_string(context, keymap_str,
|
struct xkb_keymap *keymap = xkb_keymap_new_from_string(context, keymap_str,
|
||||||
XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||||
@ -106,6 +156,8 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self,
|
|||||||
if (!keymap)
|
if (!keymap)
|
||||||
g_error("Bad keymap:\n%s", keymap_str);
|
g_error("Bad keymap:\n%s", keymap_str);
|
||||||
|
|
||||||
|
free(keymap_str);
|
||||||
|
|
||||||
xkb_context_unref(context);
|
xkb_context_unref(context);
|
||||||
keyboard->keymap = keymap;
|
keyboard->keymap = keymap;
|
||||||
|
|
||||||
@ -115,7 +167,7 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self,
|
|||||||
g_autofree char *path = strdup("/eek_keymap-XXXXXX");
|
g_autofree char *path = strdup("/eek_keymap-XXXXXX");
|
||||||
char *r = &path[strlen(path) - 6];
|
char *r = &path[strlen(path) - 6];
|
||||||
getrandom(r, 6, GRND_NONBLOCK);
|
getrandom(r, 6, GRND_NONBLOCK);
|
||||||
for (unsigned i = 0; i < 6; i++) {
|
for (uint i = 0; i < 6; i++) {
|
||||||
r[i] = (r[i] & 0b1111111) | 0b1000000; // A-z
|
r[i] = (r[i] & 0b1111111) | 0b1000000; // A-z
|
||||||
r[i] = r[i] > 'z' ? '?' : r[i]; // The randomizer doesn't need to be good...
|
r[i] = r[i] > 'z' ? '?' : r[i]; // The randomizer doesn't need to be good...
|
||||||
}
|
}
|
||||||
@ -133,8 +185,9 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self,
|
|||||||
if ((void*)ptr == (void*)-1) {
|
if ((void*)ptr == (void*)-1) {
|
||||||
g_error("Failed to set up mmap");
|
g_error("Failed to set up mmap");
|
||||||
}
|
}
|
||||||
strncpy(ptr, keymap_str, keyboard->keymap_len);
|
strcpy(ptr, keymap_str);
|
||||||
munmap(ptr, keyboard->keymap_len);
|
munmap(ptr, keyboard->keymap_len);
|
||||||
|
free(keymap_str);
|
||||||
|
|
||||||
return keyboard;
|
return keyboard;
|
||||||
}
|
}
|
||||||
@ -168,6 +221,9 @@ eekboard_context_service_set_property (GObject *object,
|
|||||||
case PROP_VISIBLE:
|
case PROP_VISIBLE:
|
||||||
context->priv->visible = g_value_get_boolean (value);
|
context->priv->visible = g_value_get_boolean (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_FULLSCREEN:
|
||||||
|
context->priv->fullscreen = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -189,6 +245,9 @@ eekboard_context_service_get_property (GObject *object,
|
|||||||
case PROP_VISIBLE:
|
case PROP_VISIBLE:
|
||||||
g_value_set_boolean (value, context->priv->visible);
|
g_value_set_boolean (value, context->priv->visible);
|
||||||
break;
|
break;
|
||||||
|
case PROP_FULLSCREEN:
|
||||||
|
g_value_set_boolean (value, context->priv->fullscreen);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -393,6 +452,20 @@ eekboard_context_service_class_init (EekboardContextServiceClass *klass)
|
|||||||
g_object_class_install_property (gobject_class,
|
g_object_class_install_property (gobject_class,
|
||||||
PROP_VISIBLE,
|
PROP_VISIBLE,
|
||||||
pspec);
|
pspec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EekboardContextService:fullscreen:
|
||||||
|
*
|
||||||
|
* Flag to indicate if keyboard is rendered in fullscreen mode.
|
||||||
|
*/
|
||||||
|
pspec = g_param_spec_boolean ("fullscreen",
|
||||||
|
"Fullscreen",
|
||||||
|
"Fullscreen",
|
||||||
|
FALSE,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
g_object_class_install_property (gobject_class,
|
||||||
|
PROP_FULLSCREEN,
|
||||||
|
pspec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -502,6 +575,19 @@ eekboard_context_service_get_keyboard (EekboardContextService *context)
|
|||||||
return context->priv->keyboard;
|
return context->priv->keyboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eekboard_context_service_get_fullscreen:
|
||||||
|
* @context: an #EekboardContextService
|
||||||
|
*
|
||||||
|
* Check if keyboard is rendered in fullscreen mode in @context.
|
||||||
|
* Returns: %TRUE or %FALSE
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
eekboard_context_service_get_fullscreen (EekboardContextService *context)
|
||||||
|
{
|
||||||
|
return context->priv->fullscreen;
|
||||||
|
}
|
||||||
|
|
||||||
void eekboard_context_service_set_keymap(EekboardContextService *context,
|
void eekboard_context_service_set_keymap(EekboardContextService *context,
|
||||||
const LevelKeyboard *keyboard)
|
const LevelKeyboard *keyboard)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -98,6 +98,8 @@ void eekboard_context_service_hide_keyboard
|
|||||||
(EekboardContextService *context);
|
(EekboardContextService *context);
|
||||||
void eekboard_context_service_destroy (EekboardContextService *context);
|
void eekboard_context_service_destroy (EekboardContextService *context);
|
||||||
LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *context);
|
LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *context);
|
||||||
|
gboolean eekboard_context_service_get_fullscreen
|
||||||
|
(EekboardContextService *context);
|
||||||
|
|
||||||
void eekboard_context_service_set_keymap(EekboardContextService *context,
|
void eekboard_context_service_set_keymap(EekboardContextService *context,
|
||||||
const LevelKeyboard *keyboard);
|
const LevelKeyboard *keyboard);
|
||||||
|
|||||||
654
eekboard/eekboard-context.c
Normal file
654
eekboard/eekboard-context.c
Normal file
@ -0,0 +1,654 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
|
||||||
|
* Copyright (C) 2010-2011 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION:eekboard-context
|
||||||
|
* @short_description: client interface of eekboard input context service
|
||||||
|
*
|
||||||
|
* The #EekboardContext class provides a client access to remote input
|
||||||
|
* context.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "eekboard/eekboard-context.h"
|
||||||
|
//#include "eekboard/eekboard-marshalers.h"
|
||||||
|
|
||||||
|
#define I_(string) g_intern_static_string (string)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ENABLED,
|
||||||
|
DISABLED,
|
||||||
|
DESTROYED,
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint signals[LAST_SIGNAL] = { 0, };
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP_0,
|
||||||
|
PROP_VISIBLE,
|
||||||
|
PROP_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _EekboardContextPrivate
|
||||||
|
{
|
||||||
|
gboolean visible;
|
||||||
|
gboolean enabled;
|
||||||
|
gboolean fullscreen;
|
||||||
|
gint group;
|
||||||
|
} EekboardContextPrivate;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE_WITH_PRIVATE (EekboardContext, eekboard_context, G_TYPE_DBUS_PROXY)
|
||||||
|
|
||||||
|
static void
|
||||||
|
eekboard_context_real_g_signal (GDBusProxy *self,
|
||||||
|
const gchar *sender_name,
|
||||||
|
const gchar *signal_name,
|
||||||
|
GVariant *parameters)
|
||||||
|
{
|
||||||
|
EekboardContext *context = EEKBOARD_CONTEXT (self);
|
||||||
|
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
|
||||||
|
|
||||||
|
if (g_strcmp0 (signal_name, "Enabled") == 0) {
|
||||||
|
g_signal_emit (context, signals[ENABLED], 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_strcmp0 (signal_name, "Disabled") == 0) {
|
||||||
|
g_signal_emit (context, signals[DISABLED], 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_strcmp0 (signal_name, "Destroyed") == 0) {
|
||||||
|
g_signal_emit (context, signals[DESTROYED], 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_strcmp0 (signal_name, "VisibilityChanged") == 0) {
|
||||||
|
gboolean visible = FALSE;
|
||||||
|
|
||||||
|
g_variant_get (parameters, "(b)", &visible);
|
||||||
|
if (visible != priv->visible) {
|
||||||
|
priv->visible = visible;
|
||||||
|
g_object_notify (G_OBJECT(context), "visible");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_strcmp0 (signal_name, "GroupChanged") == 0) {
|
||||||
|
gint group = 0;
|
||||||
|
|
||||||
|
g_variant_get (parameters, "(i)", &group);
|
||||||
|
if (group != priv->group) {
|
||||||
|
priv->group = group;
|
||||||
|
/* g_object_notify (G_OBJECT(context), "group"); */
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_return_if_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eekboard_context_real_enabled (EekboardContext *self)
|
||||||
|
{
|
||||||
|
EekboardContextPrivate *priv = eekboard_context_get_instance_private (self);
|
||||||
|
|
||||||
|
priv->enabled = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eekboard_context_real_disabled (EekboardContext *self)
|
||||||
|
{
|
||||||
|
EekboardContextPrivate *priv = eekboard_context_get_instance_private (self);
|
||||||
|
|
||||||
|
priv->enabled = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eekboard_context_real_destroyed (EekboardContext *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eekboard_context_get_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
EekboardContext *context = EEKBOARD_CONTEXT(object);
|
||||||
|
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
case PROP_VISIBLE:
|
||||||
|
g_value_set_boolean (value, priv->visible);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eekboard_context_class_init (EekboardContextClass *klass)
|
||||||
|
{
|
||||||
|
GDBusProxyClass *proxy_class = G_DBUS_PROXY_CLASS (klass);
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
GParamSpec *pspec;
|
||||||
|
|
||||||
|
klass->enabled = eekboard_context_real_enabled;
|
||||||
|
klass->disabled = eekboard_context_real_disabled;
|
||||||
|
klass->destroyed = eekboard_context_real_destroyed;
|
||||||
|
|
||||||
|
proxy_class->g_signal = eekboard_context_real_g_signal;
|
||||||
|
|
||||||
|
gobject_class->get_property = eekboard_context_get_property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EekboardContext:visible:
|
||||||
|
*
|
||||||
|
* Flag to indicate if keyboard is visible or not.
|
||||||
|
*/
|
||||||
|
pspec = g_param_spec_boolean ("visible",
|
||||||
|
"visible",
|
||||||
|
"Flag that indicates if keyboard is visible",
|
||||||
|
FALSE,
|
||||||
|
G_PARAM_READABLE);
|
||||||
|
g_object_class_install_property (gobject_class,
|
||||||
|
PROP_VISIBLE,
|
||||||
|
pspec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EekboardContext::enabled:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
*
|
||||||
|
* Emitted when @context is enabled.
|
||||||
|
*/
|
||||||
|
signals[ENABLED] =
|
||||||
|
g_signal_new (I_("enabled"),
|
||||||
|
G_TYPE_FROM_CLASS(gobject_class),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET(EekboardContextClass, enabled),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
g_cclosure_marshal_VOID__VOID,
|
||||||
|
G_TYPE_NONE,
|
||||||
|
0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EekboardContext::disabled:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
*
|
||||||
|
* The ::disabled signal is emitted each time @context is disabled.
|
||||||
|
*/
|
||||||
|
signals[DISABLED] =
|
||||||
|
g_signal_new (I_("disabled"),
|
||||||
|
G_TYPE_FROM_CLASS(gobject_class),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET(EekboardContextClass, disabled),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
g_cclosure_marshal_VOID__VOID,
|
||||||
|
G_TYPE_NONE,
|
||||||
|
0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EekboardContext::destroyed:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
*
|
||||||
|
* The ::destroyed signal is emitted each time the name of remote
|
||||||
|
* end is vanished.
|
||||||
|
*/
|
||||||
|
signals[DESTROYED] =
|
||||||
|
g_signal_new (I_("destroyed"),
|
||||||
|
G_TYPE_FROM_CLASS(gobject_class),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET(EekboardContextClass, destroyed),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
g_cclosure_marshal_VOID__VOID,
|
||||||
|
G_TYPE_NONE,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eekboard_context_init (EekboardContext *self)
|
||||||
|
{
|
||||||
|
/* void */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
context_name_vanished_callback (GDBusConnection *connection,
|
||||||
|
const gchar *name,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
EekboardContext *context = user_data;
|
||||||
|
g_signal_emit (context, signals[DESTROYED], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eekboard_context_new:
|
||||||
|
* @connection: a #GDBusConnection
|
||||||
|
* @object_path: object path
|
||||||
|
* @cancellable: a #GCancellable
|
||||||
|
*
|
||||||
|
* Create a D-Bus proxy of an input context maintained by
|
||||||
|
* eekboard-server. This function is seldom called from applications
|
||||||
|
* since eekboard_server_create_context() calls it implicitly.
|
||||||
|
*/
|
||||||
|
EekboardContext *
|
||||||
|
eekboard_context_new (GDBusConnection *connection,
|
||||||
|
const gchar *object_path,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
GInitable *initable;
|
||||||
|
GError *error;
|
||||||
|
|
||||||
|
g_return_val_if_fail (object_path != NULL, NULL);
|
||||||
|
g_return_val_if_fail (G_IS_DBUS_CONNECTION(connection), NULL);
|
||||||
|
|
||||||
|
error = NULL;
|
||||||
|
initable =
|
||||||
|
g_initable_new (EEKBOARD_TYPE_CONTEXT,
|
||||||
|
cancellable,
|
||||||
|
&error,
|
||||||
|
"g-name", "org.fedorahosted.Eekboard",
|
||||||
|
"g-connection", connection,
|
||||||
|
"g-interface-name", "org.fedorahosted.Eekboard.Context",
|
||||||
|
"g-object-path", object_path,
|
||||||
|
NULL);
|
||||||
|
if (initable != NULL) {
|
||||||
|
EekboardContext *context = EEKBOARD_CONTEXT (initable);
|
||||||
|
gchar *name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY(context));
|
||||||
|
|
||||||
|
if (name_owner == NULL) {
|
||||||
|
g_object_unref (context);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the vanished callback is called when the server is disconnected */
|
||||||
|
g_bus_watch_name_on_connection (connection,
|
||||||
|
name_owner,
|
||||||
|
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||||
|
NULL,
|
||||||
|
context_name_vanished_callback,
|
||||||
|
context,
|
||||||
|
NULL);
|
||||||
|
g_free (name_owner);
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_warning ("can't create context client: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
context_async_ready_callback (GObject *source_object,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
GVariant *result;
|
||||||
|
|
||||||
|
result = g_dbus_proxy_call_finish (G_DBUS_PROXY(source_object),
|
||||||
|
res,
|
||||||
|
&error);
|
||||||
|
if (result)
|
||||||
|
g_variant_unref (result);
|
||||||
|
else {
|
||||||
|
g_warning ("error in D-Bus proxy call: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eekboard_context_add_keyboard:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
* @keyboard: a string representing keyboard
|
||||||
|
* @cancellable: a #GCancellable
|
||||||
|
*
|
||||||
|
* Register @keyboard in @context.
|
||||||
|
*/
|
||||||
|
guint
|
||||||
|
eekboard_context_add_keyboard (EekboardContext *context,
|
||||||
|
const gchar *keyboard,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
GVariant *result;
|
||||||
|
GError *error;
|
||||||
|
|
||||||
|
g_return_val_if_fail (EEKBOARD_IS_CONTEXT(context), 0);
|
||||||
|
|
||||||
|
error = NULL;
|
||||||
|
result = g_dbus_proxy_call_sync (G_DBUS_PROXY(context),
|
||||||
|
"AddKeyboard",
|
||||||
|
g_variant_new ("(s)", keyboard),
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
&error);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
guint keyboard_id;
|
||||||
|
|
||||||
|
g_variant_get (result, "(u)", &keyboard_id);
|
||||||
|
g_variant_unref (result);
|
||||||
|
|
||||||
|
return keyboard_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_warning ("error in AddKeyboard call: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eekboard_context_remove_keyboard:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
* @keyboard_id: keyboard ID
|
||||||
|
* @cancellable: a #GCancellable
|
||||||
|
*
|
||||||
|
* Unregister the keyboard with @keyboard_id in @context.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
eekboard_context_remove_keyboard (EekboardContext *context,
|
||||||
|
guint keyboard_id,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
|
||||||
|
|
||||||
|
g_dbus_proxy_call (G_DBUS_PROXY(context),
|
||||||
|
"RemoveKeyboard",
|
||||||
|
g_variant_new ("(u)", keyboard_id),
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
context_async_ready_callback,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eekboard_context_set_keyboard:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
* @keyboard_id: keyboard ID
|
||||||
|
* @cancellable: a #GCancellable
|
||||||
|
*
|
||||||
|
* Select a keyboard with ID @keyboard_id in @context.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
eekboard_context_set_keyboard (EekboardContext *context,
|
||||||
|
guint keyboard_id,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
|
||||||
|
|
||||||
|
g_dbus_proxy_call (G_DBUS_PROXY(context),
|
||||||
|
"SetKeyboard",
|
||||||
|
g_variant_new ("(u)", keyboard_id),
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
context_async_ready_callback,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eekboard_context_set_group:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
* @group: group number
|
||||||
|
* @cancellable: a #GCancellable
|
||||||
|
*
|
||||||
|
* Set the keyboard group of @context.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
eekboard_context_set_group (EekboardContext *context,
|
||||||
|
gint group,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
|
||||||
|
|
||||||
|
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
|
||||||
|
|
||||||
|
if (priv->group != group) {
|
||||||
|
g_dbus_proxy_call (G_DBUS_PROXY(context),
|
||||||
|
"SetGroup",
|
||||||
|
g_variant_new ("(i)", group),
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
context_async_ready_callback,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eekboard_context_get_group:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
* @cancellable: a #GCancellable
|
||||||
|
*
|
||||||
|
* Get the keyboard group of @context.
|
||||||
|
*/
|
||||||
|
gint
|
||||||
|
eekboard_context_get_group (EekboardContext *context,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (EEKBOARD_IS_CONTEXT(context), 0);
|
||||||
|
|
||||||
|
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
|
||||||
|
|
||||||
|
return priv->group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eekboard_context_show_keyboard:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
* @cancellable: a #GCancellable
|
||||||
|
*
|
||||||
|
* Request eekboard-server to show a keyboard set by
|
||||||
|
* eekboard_context_set_keyboard().
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
eekboard_context_show_keyboard (EekboardContext *context,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
|
||||||
|
|
||||||
|
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
|
||||||
|
|
||||||
|
if (priv->enabled) {
|
||||||
|
g_dbus_proxy_call (G_DBUS_PROXY(context),
|
||||||
|
"ShowKeyboard",
|
||||||
|
NULL,
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
context_async_ready_callback,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eekboard_context_hide_keyboard:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
* @cancellable: a #GCancellable
|
||||||
|
*
|
||||||
|
* Request eekboard-server to hide a keyboard.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
eekboard_context_hide_keyboard (EekboardContext *context,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
|
||||||
|
|
||||||
|
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
|
||||||
|
|
||||||
|
if (priv->enabled) {
|
||||||
|
g_dbus_proxy_call (G_DBUS_PROXY(context),
|
||||||
|
"HideKeyboard",
|
||||||
|
NULL,
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
context_async_ready_callback,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eekboard_context_press_keycode:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
* @keycode: keycode number
|
||||||
|
* @cancellable: a #GCancellable
|
||||||
|
*
|
||||||
|
* Tell eekboard-server that a key identified by @keycode is pressed.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
eekboard_context_press_keycode (EekboardContext *context,
|
||||||
|
guint keycode,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
|
||||||
|
|
||||||
|
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
|
||||||
|
|
||||||
|
if (priv->enabled) {
|
||||||
|
g_dbus_proxy_call (G_DBUS_PROXY(context),
|
||||||
|
"PressKeycode",
|
||||||
|
g_variant_new ("(u)", keycode),
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
context_async_ready_callback,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eekboard_context_release_keycode:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
* @keycode: keycode number
|
||||||
|
* @cancellable: a #GCancellable
|
||||||
|
*
|
||||||
|
* Tell eekboard-server that a key identified by @keycode is released.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
eekboard_context_release_keycode (EekboardContext *context,
|
||||||
|
guint keycode,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
|
||||||
|
|
||||||
|
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
|
||||||
|
|
||||||
|
if (priv->enabled) {
|
||||||
|
g_dbus_proxy_call (G_DBUS_PROXY(context),
|
||||||
|
"ReleaseKeycode",
|
||||||
|
g_variant_new ("(u)", keycode),
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
context_async_ready_callback,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eekboard_context_is_visible:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
*
|
||||||
|
* Check if keyboard is visible.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
eekboard_context_is_visible (EekboardContext *context)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (EEKBOARD_IS_CONTEXT(context), FALSE);
|
||||||
|
|
||||||
|
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
|
||||||
|
|
||||||
|
return priv->enabled && priv->visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eekboard_context_set_enabled:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
* @enabled: flag to indicate if @context is enabled
|
||||||
|
*
|
||||||
|
* Set @context enabled or disabled. This function is seldom called
|
||||||
|
* since the flag is set via D-Bus signal #EekboardContext::enabled
|
||||||
|
* and #EekboardContext::disabled.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
eekboard_context_set_enabled (EekboardContext *context,
|
||||||
|
gboolean enabled)
|
||||||
|
{
|
||||||
|
g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
|
||||||
|
|
||||||
|
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
|
||||||
|
|
||||||
|
priv->enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eekboard_context_is_enabled:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
*
|
||||||
|
* Check if @context is enabled.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
eekboard_context_is_enabled (EekboardContext *context)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (EEKBOARD_IS_CONTEXT(context), FALSE);
|
||||||
|
|
||||||
|
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
|
||||||
|
|
||||||
|
return priv->enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eekboard_context_set_fullscreen:
|
||||||
|
* @context: an #EekboardContext
|
||||||
|
* @fullscreen: a flag to indicate fullscreen mode
|
||||||
|
* @cancellable: a #GCancellable
|
||||||
|
*
|
||||||
|
* Set the fullscreen mode of @context.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
eekboard_context_set_fullscreen (EekboardContext *context,
|
||||||
|
gboolean fullscreen,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
|
||||||
|
|
||||||
|
EekboardContextPrivate *priv = eekboard_context_get_instance_private (context);
|
||||||
|
|
||||||
|
if (priv->fullscreen != fullscreen) {
|
||||||
|
g_dbus_proxy_call (G_DBUS_PROXY(context),
|
||||||
|
"SetFullscreen",
|
||||||
|
g_variant_new ("(b)", fullscreen),
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
context_async_ready_callback,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
94
eekboard/eekboard-context.h
Normal file
94
eekboard/eekboard-context.h
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
|
||||||
|
* Copyright (C) 2010-2011 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#if !defined(__EEKBOARD_CLIENT_H_INSIDE__) && !defined(EEKBOARD_COMPILATION)
|
||||||
|
#error "Only <eekboard/eekboard-client.h> can be included directly."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef EEKBOARD_CONTEXT_H
|
||||||
|
#define EEKBOARD_CONTEXT_H 1
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include "eek/eek.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define EEKBOARD_TYPE_CONTEXT (eekboard_context_get_type())
|
||||||
|
G_DECLARE_DERIVABLE_TYPE (EekboardContext, eekboard_context, EEKBOARD, CONTEXT, GDBusProxy)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EekboardContextClass:
|
||||||
|
* @enabled: class handler for #EekboardContext::enabled signal
|
||||||
|
* @disabled: class handler for #EekboardContext::disabled signal
|
||||||
|
* @key_pressed: class handler for #EekboardContext::key-pressed signal
|
||||||
|
* @destroyed: class handler for #EekboardContext::destroyed signal
|
||||||
|
*/
|
||||||
|
struct _EekboardContextClass {
|
||||||
|
/*< private >*/
|
||||||
|
GDBusProxyClass parent_class;
|
||||||
|
|
||||||
|
/*< public >*/
|
||||||
|
/* signals */
|
||||||
|
void (*enabled) (EekboardContext *self);
|
||||||
|
void (*disabled) (EekboardContext *self);
|
||||||
|
void (*destroyed) (EekboardContext *self);
|
||||||
|
|
||||||
|
/*< private >*/
|
||||||
|
/* padding */
|
||||||
|
gpointer pdummy[24];
|
||||||
|
};
|
||||||
|
|
||||||
|
GType eekboard_context_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
EekboardContext *eekboard_context_new (GDBusConnection *connection,
|
||||||
|
const gchar *object_path,
|
||||||
|
GCancellable *cancellable);
|
||||||
|
guint eekboard_context_add_keyboard (EekboardContext *context,
|
||||||
|
const gchar *keyboard,
|
||||||
|
GCancellable *cancellable);
|
||||||
|
void eekboard_context_remove_keyboard (EekboardContext *context,
|
||||||
|
guint keyboard_id,
|
||||||
|
GCancellable *cancellable);
|
||||||
|
void eekboard_context_set_keyboard (EekboardContext *context,
|
||||||
|
guint keyboard_id,
|
||||||
|
GCancellable *cancellable);
|
||||||
|
void eekboard_context_show_keyboard (EekboardContext *context,
|
||||||
|
GCancellable *cancellable);
|
||||||
|
void eekboard_context_hide_keyboard (EekboardContext *context,
|
||||||
|
GCancellable *cancellable);
|
||||||
|
void eekboard_context_set_group (EekboardContext *context,
|
||||||
|
gint group,
|
||||||
|
GCancellable *cancellable);
|
||||||
|
gint eekboard_context_get_group (EekboardContext *context,
|
||||||
|
GCancellable *cancellable);
|
||||||
|
void eekboard_context_press_keycode (EekboardContext *context,
|
||||||
|
guint keycode,
|
||||||
|
GCancellable *cancellable);
|
||||||
|
void eekboard_context_release_keycode (EekboardContext *context,
|
||||||
|
guint keycode,
|
||||||
|
GCancellable *cancellable);
|
||||||
|
gboolean eekboard_context_is_visible
|
||||||
|
(EekboardContext *context);
|
||||||
|
void eekboard_context_set_enabled (EekboardContext *context,
|
||||||
|
gboolean enabled);
|
||||||
|
gboolean eekboard_context_is_enabled (EekboardContext *context);
|
||||||
|
void eekboard_context_set_fullscreen (EekboardContext *context,
|
||||||
|
gboolean fullscreen,
|
||||||
|
GCancellable *cancellable);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
#endif /* EEKBOARD_CONTEXT_H */
|
||||||
@ -90,9 +90,12 @@ send_fake_key (SeatEmitter *emitter,
|
|||||||
gboolean pressed,
|
gboolean pressed,
|
||||||
uint32_t timestamp)
|
uint32_t timestamp)
|
||||||
{
|
{
|
||||||
zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, 0);
|
guint level = keyboard->level;
|
||||||
|
uint32_t group = (level / 2);
|
||||||
|
|
||||||
|
zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, group);
|
||||||
send_virtual_keyboard_key (emitter->virtual_keyboard, keycode - 8, (unsigned)pressed, timestamp);
|
send_virtual_keyboard_key (emitter->virtual_keyboard, keycode - 8, (unsigned)pressed, timestamp);
|
||||||
zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, 0);
|
zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@ -1,29 +0,0 @@
|
|||||||
extern crate rs;
|
|
||||||
extern crate xkbcommon;
|
|
||||||
|
|
||||||
use std::env;
|
|
||||||
|
|
||||||
use rs::data::{ Layout, LoadError };
|
|
||||||
|
|
||||||
use xkbcommon::xkb;
|
|
||||||
|
|
||||||
|
|
||||||
fn check_layout(name: &str) {
|
|
||||||
let layout = Layout::from_resource(name)
|
|
||||||
.and_then(|layout| layout.build().map_err(LoadError::BadKeyMap))
|
|
||||||
.expect("layout broken");
|
|
||||||
|
|
||||||
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
|
|
||||||
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(
|
project(
|
||||||
'squeekboard',
|
'squeekboard',
|
||||||
'c', 'rust',
|
'c', 'rust',
|
||||||
version: '1.2.1',
|
version: '1.0.10',
|
||||||
license: 'GPLv3',
|
license: 'GPLv3',
|
||||||
meson_version: '>=0.51.0',
|
meson_version: '>=0.49.0',
|
||||||
default_options: [
|
default_options: [
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'buildtype=debugoptimized',
|
'buildtype=debugoptimized',
|
||||||
@ -53,9 +53,6 @@ summary = [
|
|||||||
]
|
]
|
||||||
message('\n'.join(summary))
|
message('\n'.join(summary))
|
||||||
|
|
||||||
cargo = find_program('cargo')
|
|
||||||
cargo_script = find_program('cargo.sh')
|
|
||||||
|
|
||||||
subdir('data')
|
subdir('data')
|
||||||
subdir('protocols')
|
subdir('protocols')
|
||||||
subdir('eek')
|
subdir('eek')
|
||||||
|
|||||||
1350
src/bitflags.rs
Normal file
1350
src/bitflags.rs
Normal file
File diff suppressed because it is too large
Load Diff
698
src/data.rs
698
src/data.rs
@ -1,698 +0,0 @@
|
|||||||
/**! 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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
enum DataSource {
|
|
||||||
File(PathBuf),
|
|
||||||
Resource(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for DataSource {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
DataSource::File(path) => write!(f, "Path: {:?}", path.display()),
|
|
||||||
DataSource::Resource(name) => write!(f, "Resource: {}", name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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,
|
|
||||||
keyboards_path: Option<PathBuf>,
|
|
||||||
) -> (
|
|
||||||
Result<::layout::Layout, LoadError>, // last attempted
|
|
||||||
DataSource, // last attempt source
|
|
||||||
Option<(LoadError, DataSource)>, // first attempt source
|
|
||||||
) {
|
|
||||||
let path = keyboards_path.map(|path|
|
|
||||||
path.join(name).with_extension("yaml")
|
|
||||||
);
|
|
||||||
|
|
||||||
let layout = match path {
|
|
||||||
Some(path) => Some((
|
|
||||||
Layout::from_file(path.clone())
|
|
||||||
.map_err(LoadError::BadData)
|
|
||||||
.and_then(|layout|
|
|
||||||
layout.build().map_err(LoadError::BadKeyMap)
|
|
||||||
),
|
|
||||||
DataSource::File(path),
|
|
||||||
)),
|
|
||||||
None => None, // No env var, not an error
|
|
||||||
};
|
|
||||||
|
|
||||||
let (failed_attempt, layout) = match layout {
|
|
||||||
Some((Ok(layout), path)) => (None, Some((layout, path))),
|
|
||||||
Some((Err(e), path)) => (Some((e, path)), None),
|
|
||||||
None => (None, None),
|
|
||||||
};
|
|
||||||
|
|
||||||
let (layout, source) = match layout {
|
|
||||||
Some((layout, path)) => (Ok(layout), path),
|
|
||||||
None => (
|
|
||||||
Layout::from_resource(name)
|
|
||||||
.and_then(|layout|
|
|
||||||
layout.build().map_err(LoadError::BadKeyMap)
|
|
||||||
),
|
|
||||||
DataSource::Resource(name.into()),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
(layout, source, failed_attempt)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn log_attempt_info(attempt: Option<(LoadError, DataSource)>) {
|
|
||||||
match attempt {
|
|
||||||
Some((
|
|
||||||
LoadError::BadData(Error::Missing(_e)),
|
|
||||||
DataSource::File(_file)
|
|
||||||
)) => {
|
|
||||||
// Missing file, not to worry. TODO: print in debug logging level
|
|
||||||
}
|
|
||||||
Some((e, source)) => {
|
|
||||||
eprintln!(
|
|
||||||
"Failed to load layout from {}: {}, trying builtin",
|
|
||||||
source, e
|
|
||||||
);
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_layout_with_fallback(
|
|
||||||
name: &str
|
|
||||||
) -> ::layout::Layout {
|
|
||||||
let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR")
|
|
||||||
.map(PathBuf::from)
|
|
||||||
.or_else(|| xdg::data_path("squeekboard/keyboards"));
|
|
||||||
|
|
||||||
let (layout, source, attempt) = load_layout(name, path.clone());
|
|
||||||
|
|
||||||
log_attempt_info(attempt);
|
|
||||||
|
|
||||||
let (layout, source, attempt) = match (layout, source) {
|
|
||||||
(Err(e), source) => {
|
|
||||||
eprintln!(
|
|
||||||
"Failed to load layout from {}: {}, using fallback",
|
|
||||||
source, e
|
|
||||||
);
|
|
||||||
load_layout(FALLBACK_LAYOUT_NAME, path)
|
|
||||||
},
|
|
||||||
(res, source) => (res, source, None),
|
|
||||||
};
|
|
||||||
|
|
||||||
log_attempt_info(attempt);
|
|
||||||
|
|
||||||
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 {
|
|
||||||
row_spacing: f64,
|
|
||||||
button_spacing: f64,
|
|
||||||
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 {
|
|
||||||
bounds: Bounds,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Errors encountered loading the layout into yaml
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
Yaml(serde_yaml::Error),
|
|
||||||
Io(io::Error),
|
|
||||||
/// The file was missing.
|
|
||||||
/// It's distinct from Io in order to make it matchable
|
|
||||||
/// without calling io::Error::kind()
|
|
||||||
Missing(io::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Error::Yaml(e) => write!(f, "YAML: {}", e),
|
|
||||||
Error::Io(e) => write!(f, "IO: {}", e),
|
|
||||||
Error::Missing(e) => write!(f, "Missing: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
|
||||||
fn from(e: io::Error) -> Self {
|
|
||||||
let kind = e.kind();
|
|
||||||
match kind {
|
|
||||||
io::ErrorKind::NotFound => Error::Missing(e),
|
|
||||||
_ => Error::Io(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Layout {
|
|
||||||
pub fn from_resource(name: &str) -> Result<Layout, LoadError> {
|
|
||||||
let data = resources::get_keyboard(name)
|
|
||||||
.ok_or(LoadError::MissingResource)?;
|
|
||||||
serde_yaml::from_str(data)
|
|
||||||
.map_err(LoadError::BadResource)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_file(path: PathBuf) -> Result<Layout, Error> {
|
|
||||||
let infile = BufReader::new(
|
|
||||||
fs::OpenOptions::new()
|
|
||||||
.read(true)
|
|
||||||
.open(&path)?
|
|
||||||
);
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
spacing: ::layout::Spacing {
|
|
||||||
row: self.row_spacing,
|
|
||||||
button: self.button_spacing,
|
|
||||||
},
|
|
||||||
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 {
|
|
||||||
bounds: Bounds { x: 0f64, y: 0f64, width: 1f64, height: 1f64 },
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
::layout::Button {
|
|
||||||
name: cname,
|
|
||||||
outline_name: CString::new(outline_name).expect("Bad outline"),
|
|
||||||
// TODO: do layout before creating buttons
|
|
||||||
bounds: ::layout::c::Bounds {
|
|
||||||
x: outline.bounds.x,
|
|
||||||
y: outline.bounds.y,
|
|
||||||
width: outline.bounds.width,
|
|
||||||
height: outline.bounds.height,
|
|
||||||
},
|
|
||||||
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_file(PathBuf::from("tests/layout.yaml")).unwrap(),
|
|
||||||
Layout {
|
|
||||||
row_spacing: 0f64,
|
|
||||||
button_spacing: 0f64,
|
|
||||||
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 {
|
|
||||||
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_file(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_file(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_file(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_file(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!(Layout::from_resource(FALLBACK_LAYOUT_NAME)
|
|
||||||
.and_then(|layout| layout.build().map_err(LoadError::BadKeyMap))
|
|
||||||
.is_ok()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// First fallback should be to builtin, not to FALLBACK_LAYOUT_NAME
|
|
||||||
#[test]
|
|
||||||
fn fallbacks_order() {
|
|
||||||
let (layout, source, _failure) = load_layout(
|
|
||||||
"nb",
|
|
||||||
Some(PathBuf::from("tests"))
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
source,
|
|
||||||
load_layout("nb", None).1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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,10 +5,6 @@
|
|||||||
/* Adapted from https://github.com/notriddle/rust-float-ord revision e995165f
|
/* Adapted from https://github.com/notriddle/rust-float-ord revision e995165f
|
||||||
* maintained by Michael Howell <michael@notriddle.com>
|
* maintained by Michael Howell <michael@notriddle.com>
|
||||||
* licensed under MIT / Apache-2.0 licenses
|
* 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;
|
extern crate core;
|
||||||
@ -71,7 +67,6 @@ float_ord_impl!(f64, u64, 64);
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use rs::float_ord;
|
|
||||||
/// let mut v = [-5.0, 4.0, 1.0, -3.0, 2.0];
|
/// let mut v = [-5.0, 4.0, 1.0, -3.0, 2.0];
|
||||||
///
|
///
|
||||||
/// float_ord::sort(&mut v);
|
/// float_ord::sort(&mut v);
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use std::ffi::CString;
|
|||||||
use std::num::Wrapping;
|
use std::num::Wrapping;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
|
|
||||||
use ::util::c::into_cstring;
|
use super::bitflags;
|
||||||
|
|
||||||
// Traits
|
// Traits
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
@ -13,8 +13,15 @@ use std::convert::TryFrom;
|
|||||||
pub mod c {
|
pub mod c {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use std::ffi::CStr;
|
||||||
use std::os::raw::{c_char, c_void};
|
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
|
// The following defined in C
|
||||||
|
|
||||||
/// struct zwp_input_method_v2*
|
/// struct zwp_input_method_v2*
|
||||||
@ -84,9 +91,7 @@ pub mod c {
|
|||||||
{
|
{
|
||||||
let imservice = check_imservice(imservice, im).unwrap();
|
let imservice = check_imservice(imservice, im).unwrap();
|
||||||
imservice.pending = IMProtocolState {
|
imservice.pending = IMProtocolState {
|
||||||
surrounding_text: into_cstring(text)
|
surrounding_text: into_cstring(text).expect("Received invalid string"),
|
||||||
.expect("Received invalid string")
|
|
||||||
.expect("Received null string"),
|
|
||||||
surrounding_cursor: cursor,
|
surrounding_cursor: cursor,
|
||||||
..imservice.pending.clone()
|
..imservice.pending.clone()
|
||||||
};
|
};
|
||||||
@ -225,8 +230,7 @@ bitflags!{
|
|||||||
/// Map to `text_input_unstable_v3.content_purpose` values
|
/// Map to `text_input_unstable_v3.content_purpose` values
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use rs::imservice::ContentPurpose;
|
/// assert_eq!(ContentPurpose::Alpha as u32, 0);
|
||||||
/// assert_eq!(ContentPurpose::Alpha as u32, 1);
|
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ContentPurpose {
|
pub enum ContentPurpose {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#ifndef __KEYBOARD_H
|
#ifndef __KEYBOARD_H
|
||||||
#define __KEYBOARD_H
|
#define __KYBOARD_H
|
||||||
|
|
||||||
#include "stdbool.h"
|
#include "stdbool.h"
|
||||||
#include "inttypes.h"
|
#include "inttypes.h"
|
||||||
@ -19,7 +19,6 @@ uint32_t squeek_key_is_locked(struct squeek_key *key);
|
|||||||
void squeek_key_set_locked(struct squeek_key *key, uint32_t pressed);
|
void squeek_key_set_locked(struct squeek_key *key, uint32_t pressed);
|
||||||
uint32_t squeek_key_get_keycode(struct squeek_key *key);
|
uint32_t squeek_key_get_keycode(struct squeek_key *key);
|
||||||
void squeek_key_set_keycode(struct squeek_key *key, uint32_t keycode);
|
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);
|
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);
|
const char* squeek_key_to_keymap_entry(const char *key_name, struct squeek_key *key);
|
||||||
|
|||||||
363
src/keyboard.rs
363
src/keyboard.rs
@ -1,41 +1,90 @@
|
|||||||
/*! State of the emulated keyboard and keys */
|
use std::vec::Vec;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use super::symbol;
|
||||||
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
|
/// Gathers stuff defined in C or called by C
|
||||||
pub mod c {
|
pub mod c {
|
||||||
use super::*;
|
use super::*;
|
||||||
use ::util::c;
|
use ::util::c::{ as_cstr, into_cstring };
|
||||||
use ::util::c::as_cstr;
|
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
|
use std::ptr;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub type CKeyState = c::Wrapped<KeyState>;
|
// 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
|
||||||
|
|
||||||
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
|
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
|
||||||
|
|
||||||
|
// 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]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_key_free(key: CKeyState) {
|
fn squeek_key_free(key: CKeyState) {
|
||||||
unsafe { key.unwrap() }; // reference dropped
|
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]
|
#[no_mangle]
|
||||||
@ -48,9 +97,7 @@ pub mod c {
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_key_set_pressed(key: CKeyState, pressed: u32) {
|
fn squeek_key_set_pressed(key: CKeyState, pressed: u32) {
|
||||||
let key = key.clone_ref();
|
key.borrow_mut(|key| key.pressed = pressed != 0);
|
||||||
let mut key = key.borrow_mut();
|
|
||||||
key.pressed = pressed != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -62,15 +109,109 @@ pub mod c {
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_key_set_locked(key: CKeyState, locked: u32) {
|
fn squeek_key_set_locked(key: CKeyState, locked: u32) {
|
||||||
let key = key.clone_ref();
|
key.borrow_mut(|key| key.locked = locked != 0);
|
||||||
let mut key = key.borrow_mut();
|
|
||||||
key.locked = locked != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_key_get_keycode(key: CKeyState) -> u32 {
|
fn squeek_key_get_keycode(key: CKeyState) -> u32 {
|
||||||
return key.to_owned().keycode.unwrap_or(0u32);
|
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(),
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -84,14 +225,20 @@ pub mod c {
|
|||||||
.to_str()
|
.to_str()
|
||||||
.expect("Bad key name");
|
.expect("Bad key name");
|
||||||
|
|
||||||
let symbol_name = match key.to_owned().symbol.action {
|
let symbol_name = match key.to_owned().symbol {
|
||||||
Action::Submit { text: Some(text), .. } => {
|
Some(ref symbol) => match &symbol.action {
|
||||||
Some(
|
symbol::Action::Submit { text: Some(text), .. } => {
|
||||||
text.clone()
|
Some(
|
||||||
.into_string().expect("Bad symbol")
|
text.clone()
|
||||||
)
|
.into_string().expect("Bad symbol")
|
||||||
|
)
|
||||||
|
},
|
||||||
|
_ => None
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
eprintln!("Key {} has no symbol", key_name);
|
||||||
|
None
|
||||||
},
|
},
|
||||||
_ => None,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let inner = match symbol_name {
|
let inner = match symbol_name {
|
||||||
@ -104,7 +251,7 @@ pub mod c {
|
|||||||
.into_raw()
|
.into_raw()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_key_get_action_name(
|
fn squeek_key_get_action_name(
|
||||||
key_name: *const c_char,
|
key_name: *const c_char,
|
||||||
@ -115,14 +262,20 @@ pub mod c {
|
|||||||
.to_str()
|
.to_str()
|
||||||
.expect("Bad key name");
|
.expect("Bad key name");
|
||||||
|
|
||||||
let symbol_name = match key.to_owned().symbol.action {
|
let symbol_name = match key.to_owned().symbol {
|
||||||
Action::Submit { text: Some(text), .. } => {
|
Some(ref symbol) => match &symbol.action {
|
||||||
Some(
|
symbol::Action::Submit { text: Some(text), .. } => {
|
||||||
text.clone()
|
Some(
|
||||||
.into_string().expect("Bad symbol text")
|
text.clone()
|
||||||
)
|
.into_string().expect("Bad symbol")
|
||||||
|
)
|
||||||
|
},
|
||||||
|
_ => None
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
eprintln!("Key {} has no symbol", key_name);
|
||||||
|
None
|
||||||
},
|
},
|
||||||
_ => None
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let inner = match symbol_name {
|
let inner = match symbol_name {
|
||||||
@ -134,126 +287,14 @@ pub mod c {
|
|||||||
.expect("Couldn't convert string")
|
.expect("Couldn't convert string")
|
||||||
.into_raw()
|
.into_raw()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct KeyState {
|
pub struct KeyState {
|
||||||
pub pressed: bool,
|
pub pressed: bool,
|
||||||
pub locked: bool,
|
pub locked: bool,
|
||||||
pub keycode: Option<u32>,
|
pub keycode: u32,
|
||||||
pub symbol: Symbol,
|
// TODO: remove the optionality of a symbol
|
||||||
}
|
pub symbol: Option<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)
|
|
||||||
}
|
}
|
||||||
|
|||||||
41
src/layout.h
41
src/layout.h
@ -9,11 +9,17 @@
|
|||||||
struct squeek_button;
|
struct squeek_button;
|
||||||
struct squeek_row;
|
struct squeek_row;
|
||||||
struct squeek_view;
|
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*);
|
int32_t squeek_row_get_angle(const struct squeek_row*);
|
||||||
|
|
||||||
EekBounds squeek_row_get_bounds(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);
|
uint32_t squeek_row_contains(struct squeek_row*, struct squeek_button *button);
|
||||||
|
|
||||||
@ -27,20 +33,34 @@ void squeek_row_foreach(struct squeek_row*,
|
|||||||
|
|
||||||
void squeek_row_free(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*);
|
uint32_t squeek_button_get_oref(const struct squeek_button*);
|
||||||
EekBounds squeek_button_get_bounds(const struct squeek_button*);
|
EekBounds squeek_button_get_bounds(const struct squeek_button*);
|
||||||
const char *squeek_button_get_label(const struct squeek_button*);
|
void squeek_button_set_bounds(struct squeek_button* button, EekBounds bounds);
|
||||||
const char *squeek_button_get_icon_name(const struct squeek_button*);
|
|
||||||
const char *squeek_button_get_name(const struct squeek_button*);
|
|
||||||
const char *squeek_button_get_outline_name(const struct squeek_button*);
|
|
||||||
|
|
||||||
|
struct squeek_symbol *squeek_button_get_symbol (
|
||||||
|
const struct squeek_button *button);
|
||||||
struct squeek_key *squeek_button_get_key(const struct squeek_button*);
|
struct squeek_key *squeek_button_get_key(const struct squeek_button*);
|
||||||
uint32_t *squeek_button_has_key(const struct squeek_button* button,
|
uint32_t *squeek_button_has_key(const struct squeek_button* button,
|
||||||
const struct squeek_key *key);
|
const struct squeek_key *key);
|
||||||
void squeek_button_print(const struct squeek_button* button);
|
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*);
|
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);
|
typedef void (*RowCallback) (struct squeek_row *row, gpointer user_data);
|
||||||
void squeek_view_foreach(struct squeek_view*,
|
void squeek_view_foreach(struct squeek_view*,
|
||||||
@ -50,16 +70,9 @@ void squeek_view_foreach(struct squeek_view*,
|
|||||||
struct squeek_row *squeek_view_get_row(struct squeek_view *view,
|
struct squeek_row *squeek_view_get_row(struct squeek_view *view,
|
||||||
struct squeek_button *button);
|
struct squeek_button *button);
|
||||||
|
|
||||||
struct squeek_button *squeek_view_find_button_by_position(struct squeek_view *view, EekPoint point);
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
squeek_layout_place_contents(struct squeek_layout*);
|
squeek_view_place_contents(struct squeek_view *view, LevelKeyboard *keyboard);
|
||||||
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
|
#endif
|
||||||
|
|||||||
517
src/layout.rs
517
src/layout.rs
@ -1,4 +1,4 @@
|
|||||||
/*!
|
/**
|
||||||
* Layout-related data.
|
* Layout-related data.
|
||||||
*
|
*
|
||||||
* The `View` contains `Row`s and each `Row` contains `Button`s.
|
* The `View` contains `Row`s and each `Row` contains `Button`s.
|
||||||
@ -18,8 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ffi::CString;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
@ -31,8 +29,7 @@ use ::symbol::*;
|
|||||||
pub mod c {
|
pub mod c {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use std::ffi::CStr;
|
use std::os::raw::c_void;
|
||||||
use std::os::raw::{ c_char, c_void };
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
// The following defined in C
|
// The following defined in C
|
||||||
@ -40,6 +37,11 @@ pub mod c {
|
|||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct UserData(*const c_void);
|
pub struct UserData(*const c_void);
|
||||||
|
|
||||||
|
/// The index in the relevant outline table
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct OutlineRef(u32);
|
||||||
|
|
||||||
/// Defined in eek-types.h
|
/// Defined in eek-types.h
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -58,11 +60,26 @@ pub mod c {
|
|||||||
pub height: f64
|
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 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);
|
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
|
// 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]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_view_get_bounds(view: *const ::layout::View) -> Bounds {
|
fn squeek_view_get_bounds(view: *const ::layout::View) -> Bounds {
|
||||||
@ -71,6 +88,30 @@ pub mod c {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C"
|
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(
|
fn squeek_view_foreach(
|
||||||
view: *mut ::layout::View,
|
view: *mut ::layout::View,
|
||||||
callback: RowCallback,
|
callback: RowCallback,
|
||||||
@ -83,6 +124,68 @@ 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]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_row_get_angle(row: *const ::layout::Row) -> i32 {
|
fn squeek_row_get_angle(row: *const ::layout::Row) -> i32 {
|
||||||
@ -128,11 +231,57 @@ pub mod c {
|
|||||||
unsafe { Box::from_raw(row) }; // gets dropped
|
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]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_button_get_bounds(button: *const ::layout::Button) -> Bounds {
|
fn squeek_button_get_bounds(button: *const ::layout::Button) -> Bounds {
|
||||||
let button = unsafe { &*button };
|
let button = unsafe { &*button };
|
||||||
button.bounds.clone()
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrow a new reference to key state. Doesn't need freeing
|
/// Borrow a new reference to key state. Doesn't need freeing
|
||||||
@ -153,50 +302,12 @@ pub mod c {
|
|||||||
) -> *const Symbol {
|
) -> *const Symbol {
|
||||||
let button = unsafe { &*button };
|
let button = unsafe { &*button };
|
||||||
let state = button.state.borrow();
|
let state = button.state.borrow();
|
||||||
&state.symbol as *const Symbol
|
match state.symbol {
|
||||||
}
|
Some(ref symbol) => symbol as *const Symbol,
|
||||||
|
None => ptr::null(),
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_button_get_label(
|
|
||||||
button: *const ::layout::Button
|
|
||||||
) -> *const c_char {
|
|
||||||
let button = unsafe { &*button };
|
|
||||||
match &button.label {
|
|
||||||
Label::Text(text) => text.as_ptr(),
|
|
||||||
// returning static strings to C is a bit cumbersome
|
|
||||||
Label::IconName(_) => unsafe {
|
|
||||||
// CStr doesn't allocate anything, so it only points to
|
|
||||||
// the 'static str, avoiding a memory leak
|
|
||||||
CStr::from_bytes_with_nul_unchecked(b"icon\0")
|
|
||||||
}.as_ptr(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_button_get_icon_name(button: *const Button) -> *const c_char {
|
|
||||||
let button = unsafe { &*button };
|
|
||||||
match &button.label {
|
|
||||||
Label::Text(_) => ptr::null(),
|
|
||||||
Label::IconName(name) => name.as_ptr(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_button_get_name(button: *const Button) -> *const c_char {
|
|
||||||
let button = unsafe { &*button };
|
|
||||||
button.name.as_ptr()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_button_get_outline_name(button: *const Button) -> *const c_char {
|
|
||||||
let button = unsafe { &*button };
|
|
||||||
button.outline_name.as_ptr()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_button_has_key(
|
fn squeek_button_has_key(
|
||||||
@ -204,8 +315,9 @@ pub mod c {
|
|||||||
state: ::keyboard::c::CKeyState,
|
state: ::keyboard::c::CKeyState,
|
||||||
) -> u32 {
|
) -> u32 {
|
||||||
let button = unsafe { &*button };
|
let button = unsafe { &*button };
|
||||||
let state = state.clone_ref();
|
let state = state.unwrap();
|
||||||
let equal = Rc::ptr_eq(&button.state, &state);
|
let equal = Rc::ptr_eq(&button.state, &state);
|
||||||
|
Rc::into_raw(state); // Prevent dropping
|
||||||
equal as u32
|
equal as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,34 +328,13 @@ pub mod c {
|
|||||||
println!("{:?}", button);
|
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
|
/// Entry points for more complex procedures and algoithms which span multiple modules
|
||||||
pub mod procedures {
|
pub mod procedures {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct LevelKeyboard(*const c_void);
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct ButtonPlace {
|
pub struct ButtonPlace {
|
||||||
@ -251,11 +342,13 @@ pub mod c {
|
|||||||
button: *const Button,
|
button: *const Button,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(transparent)]
|
|
||||||
pub struct LevelKeyboard(*const c_void);
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
fn eek_get_outline_size(
|
||||||
|
keyboard: *const LevelKeyboard,
|
||||||
|
outline: u32
|
||||||
|
) -> Bounds;
|
||||||
|
|
||||||
/// Checks if point falls within bounds,
|
/// Checks if point falls within bounds,
|
||||||
/// which are relative to origin and rotated by angle (I think)
|
/// which are relative to origin and rotated by angle (I think)
|
||||||
pub fn eek_are_bounds_inside (bounds: Bounds,
|
pub fn eek_are_bounds_inside (bounds: Bounds,
|
||||||
@ -263,53 +356,15 @@ pub mod c {
|
|||||||
origin: Point,
|
origin: Point,
|
||||||
angle: i32
|
angle: i32
|
||||||
) -> u32;
|
) -> u32;
|
||||||
|
|
||||||
pub fn eek_keyboard_set_key_locked(
|
|
||||||
keyboard: *mut LevelKeyboard,
|
|
||||||
key: ::keyboard::c::CKeyState,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
fn squeek_buttons_get_outlines(
|
||||||
pub extern "C"
|
buttons: &Vec<Box<Button>>,
|
||||||
fn squeek_layout_set_state_from_press(
|
keyboard: *const LevelKeyboard,
|
||||||
layout: *mut Layout,
|
) -> Vec<Bounds> {
|
||||||
keyboard: *mut LevelKeyboard,
|
buttons.iter().map(|button| {
|
||||||
key: ::keyboard::c::CKeyState,
|
unsafe { eek_get_outline_size(keyboard, button.oref.0) }
|
||||||
) {
|
}).collect()
|
||||||
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,
|
/// Places each button in order, starting from 0 on the left,
|
||||||
@ -320,19 +375,17 @@ pub mod c {
|
|||||||
/// Sets button and row sizes according to their contents.
|
/// Sets button and row sizes according to their contents.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_layout_place_contents(
|
fn squeek_view_place_contents(
|
||||||
layout: *mut Layout,
|
view: *mut ::layout::View,
|
||||||
|
keyboard: *const LevelKeyboard, // source of outlines
|
||||||
) {
|
) {
|
||||||
let layout = unsafe { &mut *layout };
|
let view = unsafe { &mut *view };
|
||||||
for view in layout.views.values_mut() {
|
|
||||||
let sizes: Vec<Vec<Bounds>> = view.rows.iter().map(|row| {
|
let sizes: Vec<Vec<Bounds>> = view.rows.iter().map(|row|
|
||||||
row.buttons.iter()
|
squeek_buttons_get_outlines(&row.buttons, keyboard)
|
||||||
.map(|button| button.bounds.clone())
|
).collect();
|
||||||
.collect()
|
|
||||||
}).collect();
|
view.place_buttons_with_sizes(sizes);
|
||||||
let spacing = view.spacing.clone();
|
|
||||||
view.place_buttons_with_sizes(sizes, spacing);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn squeek_row_contains(row: &Row, needle: *const Button) -> bool {
|
fn squeek_row_contains(row: &Row, needle: *const Button) -> bool {
|
||||||
@ -365,10 +418,13 @@ pub mod c {
|
|||||||
needle: ::keyboard::c::CKeyState,
|
needle: ::keyboard::c::CKeyState,
|
||||||
) -> ButtonPlace {
|
) -> ButtonPlace {
|
||||||
let view = unsafe { &*view };
|
let view = unsafe { &*view };
|
||||||
let state = needle.clone_ref();
|
let state = needle.unwrap();
|
||||||
|
|
||||||
let paths = ::layout::procedures::find_key_paths(view, &state);
|
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
|
// Can only return 1 entry back to C
|
||||||
let (row, button) = match paths.get(0) {
|
let (row, button) = match paths.get(0) {
|
||||||
Some((row, button)) => (
|
Some((row, button)) => (
|
||||||
@ -398,36 +454,35 @@ pub mod c {
|
|||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use super::super::test::*;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn row_has_button() {
|
fn row_has_button() {
|
||||||
let state = make_state();
|
|
||||||
let button = make_button_with_state(
|
|
||||||
"test".into(),
|
|
||||||
state.clone()
|
|
||||||
);
|
|
||||||
let button_ptr = button_as_raw(&button);
|
|
||||||
let mut row = Row::new(0);
|
let mut row = Row::new(0);
|
||||||
row.buttons.push(button);
|
let button = squeek_row_create_button(&mut row as *mut Row, 0, 0);
|
||||||
assert_eq!(squeek_row_contains(&row, button_ptr), true);
|
assert_eq!(squeek_row_contains(&row, button), true);
|
||||||
let shared_button = make_button_with_state(
|
let shared_button = squeek_row_create_button_with_state(
|
||||||
"test2".into(),
|
&mut row as *mut Row,
|
||||||
state
|
button
|
||||||
);
|
);
|
||||||
let shared_button_ptr = button_as_raw(&shared_button);
|
assert_eq!(squeek_row_contains(&row, shared_button), true);
|
||||||
row.buttons.push(shared_button);
|
|
||||||
assert_eq!(squeek_row_contains(&row, shared_button_ptr), true);
|
|
||||||
let row = Row::new(0);
|
let row = Row::new(0);
|
||||||
assert_eq!(squeek_row_contains(&row, button_ptr), false);
|
assert_eq!(squeek_row_contains(&row, button), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn view_has_button() {
|
fn view_has_button() {
|
||||||
let state = make_state();
|
let state = Rc::new(RefCell::new(::keyboard::KeyState {
|
||||||
|
pressed: false,
|
||||||
|
locked: false,
|
||||||
|
keycode: 0,
|
||||||
|
symbol: None,
|
||||||
|
}));
|
||||||
let state_clone = ::keyboard::c::CKeyState::wrap(state.clone());
|
let state_clone = ::keyboard::c::CKeyState::wrap(state.clone());
|
||||||
|
|
||||||
let button = make_button_with_state("1".into(), state);
|
let button = Box::new(Button {
|
||||||
|
oref: OutlineRef(0),
|
||||||
|
bounds: None,
|
||||||
|
state: state,
|
||||||
|
});
|
||||||
let button_ptr = button.as_ref() as *const Button;
|
let button_ptr = button.as_ref() as *const Button;
|
||||||
|
|
||||||
let row = Box::new(Row {
|
let row = Box::new(Row {
|
||||||
@ -442,10 +497,6 @@ pub mod c {
|
|||||||
x: 0f64, y: 0f64,
|
x: 0f64, y: 0f64,
|
||||||
width: 0f64, height: 0f64
|
width: 0f64, height: 0f64
|
||||||
},
|
},
|
||||||
spacing: Spacing {
|
|
||||||
button: 0f64,
|
|
||||||
row: 0f64,
|
|
||||||
},
|
|
||||||
rows: vec!(row),
|
rows: vec!(row),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -465,10 +516,6 @@ pub mod c {
|
|||||||
x: 0f64, y: 0f64,
|
x: 0f64, y: 0f64,
|
||||||
width: 0f64, height: 0f64
|
width: 0f64, height: 0f64
|
||||||
},
|
},
|
||||||
spacing: Spacing {
|
|
||||||
button: 0f64,
|
|
||||||
row: 0f64,
|
|
||||||
},
|
|
||||||
rows: Vec::new(),
|
rows: Vec::new(),
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -489,63 +536,17 @@ pub mod c {
|
|||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
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(),
|
|
||||||
bounds: c::Bounds {
|
|
||||||
x: 0f64, y: 0f64, width: 0f64, height: 0f64
|
|
||||||
},
|
|
||||||
outline_name: CString::new("test").unwrap(),
|
|
||||||
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]
|
#[test]
|
||||||
fn button_has_key() {
|
fn button_has_key() {
|
||||||
let state = make_state();
|
let button = squeek_button_new(0, 0);
|
||||||
let button = make_button_with_state("1".into(), state.clone());
|
let state = squeek_button_get_key(button);
|
||||||
assert_eq!(
|
assert_eq!(squeek_button_has_key(button, state.clone()), 1);
|
||||||
squeek_button_has_key(
|
let other_button = squeek_button_new(0, 0);
|
||||||
button_as_raw(&button),
|
assert_eq!(squeek_button_has_key(other_button, state.clone()), 0);
|
||||||
CKeyState::wrap(state.clone())
|
let other_state = ::keyboard::c::squeek_key_new(0);
|
||||||
),
|
assert_eq!(squeek_button_has_key(button, other_state), 0);
|
||||||
1
|
let shared_button = squeek_button_new_with_state(button);
|
||||||
);
|
assert_eq!(squeek_button_has_key(shared_button, state), 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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -556,37 +557,28 @@ pub struct Size {
|
|||||||
pub height: f64,
|
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
|
/// The graphical representation of a button
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Button {
|
pub struct Button {
|
||||||
/// ID string, e.g. for CSS
|
oref: c::OutlineRef,
|
||||||
pub name: CString,
|
/// TODO: abolish Option, buttons should be created with bounds fully formed
|
||||||
/// Label to display to the user
|
|
||||||
pub label: Label,
|
|
||||||
/// TODO: position the buttons before they get initial bounds
|
|
||||||
/// Position relative to some origin (i.e. parent/row)
|
/// Position relative to some origin (i.e. parent/row)
|
||||||
pub bounds: c::Bounds,
|
bounds: Option<c::Bounds>,
|
||||||
/// The name of the visual class applied
|
|
||||||
pub outline_name: CString,
|
|
||||||
/// current state, shared with other buttons
|
/// current state, shared with other buttons
|
||||||
pub state: Rc<RefCell<KeyState>>,
|
pub state: Rc<RefCell<KeyState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: derive from the style/margin/padding
|
||||||
|
const BUTTON_SPACING: f64 = 4.0;
|
||||||
|
const ROW_SPACING: f64 = 7.0;
|
||||||
|
|
||||||
/// The graphical representation of a row of buttons
|
/// The graphical representation of a row of buttons
|
||||||
pub struct Row {
|
pub struct Row {
|
||||||
pub buttons: Vec<Box<Button>>,
|
buttons: Vec<Box<Button>>,
|
||||||
/// Angle is not really used anywhere...
|
/// Angle is not really used anywhere...
|
||||||
pub angle: i32,
|
angle: i32,
|
||||||
/// Position relative to some origin (i.e. parent/view origin)
|
/// Position relative to some origin (i.e. parent/view origin)
|
||||||
pub bounds: Option<c::Bounds>,
|
bounds: Option<c::Bounds>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Row {
|
impl Row {
|
||||||
@ -606,7 +598,7 @@ impl Row {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_button_positions(outlines: Vec<c::Bounds>, button_spacing: f64)
|
fn calculate_button_positions(outlines: Vec<c::Bounds>)
|
||||||
-> Vec<c::Bounds>
|
-> Vec<c::Bounds>
|
||||||
{
|
{
|
||||||
let mut x_offset = 0f64;
|
let mut x_offset = 0f64;
|
||||||
@ -616,7 +608,7 @@ impl Row {
|
|||||||
x: x_offset,
|
x: x_offset,
|
||||||
..outline.clone()
|
..outline.clone()
|
||||||
};
|
};
|
||||||
x_offset += outline.width + button_spacing;
|
x_offset += outline.width + BUTTON_SPACING;
|
||||||
position
|
position
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
@ -647,7 +639,9 @@ impl Row {
|
|||||||
};
|
};
|
||||||
let angle = self.angle;
|
let angle = self.angle;
|
||||||
self.buttons.iter_mut().find(|button| {
|
self.buttons.iter_mut().find(|button| {
|
||||||
let bounds = button.bounds.clone();
|
let bounds = button.bounds
|
||||||
|
.as_ref().expect("Missing bounds on button")
|
||||||
|
.clone();
|
||||||
let point = point.clone();
|
let point = point.clone();
|
||||||
let origin = origin.clone();
|
let origin = origin.clone();
|
||||||
procedures::is_point_inside(bounds, point, origin, angle)
|
procedures::is_point_inside(bounds, point, origin, angle)
|
||||||
@ -655,17 +649,10 @@ impl Row {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Spacing {
|
|
||||||
pub row: f64,
|
|
||||||
pub button: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct View {
|
pub struct View {
|
||||||
/// Position relative to keyboard origin
|
/// Position relative to keyboard origin
|
||||||
pub bounds: c::Bounds,
|
bounds: c::Bounds,
|
||||||
pub spacing: Spacing,
|
rows: Vec<Box<Row>>,
|
||||||
pub rows: Vec<Box<Row>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View {
|
impl View {
|
||||||
@ -676,9 +663,7 @@ impl View {
|
|||||||
/// and derive a scaling factor that lets contents fit into view)
|
/// and derive a scaling factor that lets contents fit into view)
|
||||||
/// (or TODO: blow up view bounds to match contents
|
/// (or TODO: blow up view bounds to match contents
|
||||||
/// and then scale the entire thing)
|
/// and then scale the entire thing)
|
||||||
fn calculate_row_positions(&self, sizes: Vec<Size>, row_spacing: f64)
|
fn calculate_row_positions(&self, sizes: Vec<Size>) -> Vec<c::Bounds> {
|
||||||
-> Vec<c::Bounds>
|
|
||||||
{
|
|
||||||
let mut y_offset = self.bounds.y;
|
let mut y_offset = self.bounds.y;
|
||||||
sizes.into_iter().map(|size| {
|
sizes.into_iter().map(|size| {
|
||||||
let position = c::Bounds {
|
let position = c::Bounds {
|
||||||
@ -687,7 +672,7 @@ impl View {
|
|||||||
width: size.width,
|
width: size.width,
|
||||||
height: size.height,
|
height: size.height,
|
||||||
};
|
};
|
||||||
y_offset += size.height + row_spacing;
|
y_offset += size.height + ROW_SPACING;
|
||||||
position
|
position
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
@ -696,23 +681,19 @@ impl View {
|
|||||||
/// The view itself will not be affected by the sizes
|
/// The view itself will not be affected by the sizes
|
||||||
fn place_buttons_with_sizes(
|
fn place_buttons_with_sizes(
|
||||||
&mut self,
|
&mut self,
|
||||||
button_outlines: Vec<Vec<c::Bounds>>,
|
button_outlines: Vec<Vec<c::Bounds>>
|
||||||
spacing: Spacing,
|
|
||||||
) {
|
) {
|
||||||
// Determine all positions
|
// Determine all positions
|
||||||
let button_positions: Vec<_>
|
let button_positions: Vec<_>
|
||||||
= button_outlines.into_iter()
|
= button_outlines.into_iter()
|
||||||
.map(|outlines| {
|
.map(Row::calculate_button_positions)
|
||||||
Row::calculate_button_positions(outlines, spacing.button)
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let row_sizes = button_positions.iter()
|
let row_sizes = button_positions.iter()
|
||||||
.map(Row::calculate_row_size)
|
.map(Row::calculate_row_size)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let row_positions
|
let row_positions = self.calculate_row_positions(row_sizes);
|
||||||
= self.calculate_row_positions(row_sizes, spacing.row);
|
|
||||||
|
|
||||||
// Apply all positions
|
// Apply all positions
|
||||||
for ((mut row, row_position), button_positions)
|
for ((mut row, row_position), button_positions)
|
||||||
@ -723,7 +704,7 @@ impl View {
|
|||||||
for (mut button, button_position)
|
for (mut button, button_position)
|
||||||
in row.buttons.iter_mut()
|
in row.buttons.iter_mut()
|
||||||
.zip(button_positions) {
|
.zip(button_positions) {
|
||||||
button.bounds = button_position;
|
button.bounds = Some(button_position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -746,26 +727,6 @@ 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 {
|
mod procedures {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|||||||
13
src/lib.rs
13
src/lib.rs
@ -1,16 +1,9 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
mod bitflags;
|
||||||
#[macro_use]
|
|
||||||
extern crate maplit;
|
|
||||||
extern crate serde;
|
|
||||||
extern crate xkbcommon;
|
|
||||||
|
|
||||||
pub mod data;
|
mod float_ord;
|
||||||
pub mod float_ord;
|
mod imservice;
|
||||||
pub mod imservice;
|
|
||||||
mod keyboard;
|
mod keyboard;
|
||||||
mod layout;
|
mod layout;
|
||||||
mod resources;
|
|
||||||
mod symbol;
|
mod symbol;
|
||||||
mod util;
|
mod util;
|
||||||
mod xdg;
|
|
||||||
|
|||||||
@ -19,15 +19,20 @@ sources = [
|
|||||||
'../eek/eek-element.c',
|
'../eek/eek-element.c',
|
||||||
'../eek/eek-gtk-keyboard.c',
|
'../eek/eek-gtk-keyboard.c',
|
||||||
'../eek/eek-keyboard.c',
|
'../eek/eek-keyboard.c',
|
||||||
|
'../eek/eek-keyboard-drawing.c',
|
||||||
|
'../eek/eek-keysym.c',
|
||||||
'../eek/eek-layout.c',
|
'../eek/eek-layout.c',
|
||||||
'../eek/eek-renderer.c',
|
'../eek/eek-renderer.c',
|
||||||
|
'../eek/eek-section.c',
|
||||||
'../eek/eek-types.c',
|
'../eek/eek-types.c',
|
||||||
'../eek/eek-xml-layout.c',
|
'../eek/eek-xml-layout.c',
|
||||||
'../eek/layersurface.c',
|
'../eek/layersurface.c',
|
||||||
dbus_src,
|
dbus_src,
|
||||||
enums,
|
enums,
|
||||||
|
keysym_entries,
|
||||||
'../eekboard/key-emitter.c',
|
'../eekboard/key-emitter.c',
|
||||||
'../eekboard/eekboard-context-service.c',
|
'../eekboard/eekboard-context-service.c',
|
||||||
|
'../eekboard/eekboard-context.c',
|
||||||
'../eekboard/eekboard-service.c',
|
'../eekboard/eekboard-service.c',
|
||||||
# '../eekboard/eekboard-xklutil.c',
|
# '../eekboard/eekboard-xklutil.c',
|
||||||
squeekboard_resources,
|
squeekboard_resources,
|
||||||
@ -51,41 +56,25 @@ deps = [
|
|||||||
# dependency('libxklavier'), # FIXME remove
|
# dependency('libxklavier'), # FIXME remove
|
||||||
]
|
]
|
||||||
|
|
||||||
rslibs = custom_target(
|
# Replacement for eekboard-server
|
||||||
'rslibs',
|
rslib = static_library(
|
||||||
build_by_default: true,
|
'rslib',
|
||||||
build_always_stale: true,
|
sources: ['lib.rs'],
|
||||||
output: ['librs.a'],
|
rust_crate_type: 'staticlib'
|
||||||
install: false,
|
|
||||||
console: true,
|
|
||||||
command: [cargo_script, '@OUTPUT@', 'build']
|
|
||||||
)
|
)
|
||||||
|
|
||||||
build_rstests = custom_target(
|
rstests = executable(
|
||||||
'build_rstests',
|
'rstests',
|
||||||
build_by_default: false,
|
sources: ['lib.rs'],
|
||||||
# HACK: this target needs to build before all the tests,
|
rust_args: ['--test'],
|
||||||
# but it doesn't produce anything stable.
|
install: false
|
||||||
# Declaring build_by_default with some random but irrelevant output
|
|
||||||
# ensures that it's always built as it should
|
|
||||||
build_always_stale: true,
|
|
||||||
output: ['src'],
|
|
||||||
install: false,
|
|
||||||
console: true,
|
|
||||||
command: [cargo_script, '', 'build', '--tests'],
|
|
||||||
depends: rslibs, # no point building tests if the code itself fails
|
|
||||||
)
|
)
|
||||||
|
|
||||||
test(
|
test('rstests', rstests)
|
||||||
'rstest',
|
|
||||||
cargo_script,
|
|
||||||
args: ['', 'test'],
|
|
||||||
depends: build_rstests,
|
|
||||||
)
|
|
||||||
|
|
||||||
libsqueekboard = static_library('libsqueekboard',
|
libsqueekboard = static_library('libsqueekboard',
|
||||||
sources,
|
sources,
|
||||||
link_with: [rslibs],
|
link_with: rslib,
|
||||||
include_directories: [include_directories('..'), include_directories('../eek')],
|
include_directories: [include_directories('..'), include_directories('../eek')],
|
||||||
dependencies: deps,
|
dependencies: deps,
|
||||||
c_args: [
|
c_args: [
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
/*! 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")),
|
|
||||||
("el", include_str!("../data/keyboards/el.yaml")),
|
|
||||||
("es", include_str!("../data/keyboards/es.yaml")),
|
|
||||||
("it", include_str!("../data/keyboards/it.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 }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@ -40,7 +40,6 @@ struct _ServerContextService {
|
|||||||
|
|
||||||
GtkWidget *window;
|
GtkWidget *window;
|
||||||
GtkWidget *widget;
|
GtkWidget *widget;
|
||||||
guint hiding;
|
|
||||||
|
|
||||||
gdouble size_constraint_landscape[2];
|
gdouble size_constraint_landscape[2];
|
||||||
gdouble size_constraint_portrait[2];
|
gdouble size_constraint_portrait[2];
|
||||||
@ -52,6 +51,17 @@ struct _ServerContextServiceClass {
|
|||||||
|
|
||||||
G_DEFINE_TYPE (ServerContextService, server_context_service, EEKBOARD_TYPE_CONTEXT_SERVICE);
|
G_DEFINE_TYPE (ServerContextService, server_context_service, EEKBOARD_TYPE_CONTEXT_SERVICE);
|
||||||
|
|
||||||
|
static void set_geometry (ServerContextService *context);
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_monitors_changed (GdkScreen *screen,
|
||||||
|
ServerContextService *context)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (context->window)
|
||||||
|
set_geometry (context);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_destroy (GtkWidget *widget, gpointer user_data)
|
on_destroy (GtkWidget *widget, gpointer user_data)
|
||||||
{
|
{
|
||||||
@ -97,6 +107,15 @@ on_notify_keyboard (GObject *object,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_notify_fullscreen (GObject *object,
|
||||||
|
GParamSpec *spec,
|
||||||
|
ServerContextService *context)
|
||||||
|
{
|
||||||
|
if (context->window)
|
||||||
|
set_geometry (context);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_notify_map (GObject *object,
|
on_notify_map (GObject *object,
|
||||||
ServerContextService *context)
|
ServerContextService *context)
|
||||||
@ -112,6 +131,49 @@ on_notify_unmap (GObject *object,
|
|||||||
g_object_set (context, "visible", FALSE, NULL);
|
g_object_set (context, "visible", FALSE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_geometry (ServerContextService *context)
|
||||||
|
{
|
||||||
|
GdkScreen *screen = gdk_screen_get_default ();
|
||||||
|
GdkWindow *root = gdk_screen_get_root_window (screen);
|
||||||
|
GdkDisplay *display = gdk_display_get_default ();
|
||||||
|
GdkMonitor *monitor = gdk_display_get_monitor_at_window (display, root);
|
||||||
|
LevelKeyboard *keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context));
|
||||||
|
|
||||||
|
GdkRectangle rect;
|
||||||
|
|
||||||
|
gdk_monitor_get_geometry (monitor, &rect);
|
||||||
|
EekBounds bounds = squeek_view_get_bounds (level_keyboard_current(keyboard));
|
||||||
|
|
||||||
|
if (eekboard_context_service_get_fullscreen (EEKBOARD_CONTEXT_SERVICE(context))) {
|
||||||
|
gint width = rect.width;
|
||||||
|
gint height = rect.height;
|
||||||
|
|
||||||
|
if (width > height) {
|
||||||
|
width *= context->size_constraint_landscape[0];
|
||||||
|
height *= context->size_constraint_landscape[1];
|
||||||
|
} else {
|
||||||
|
width *= context->size_constraint_portrait[0];
|
||||||
|
height *= context->size_constraint_portrait[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width * bounds.height > height * bounds.width)
|
||||||
|
width = (height / bounds.height) * bounds.width;
|
||||||
|
else
|
||||||
|
height = (width / bounds.width) * bounds.height;
|
||||||
|
|
||||||
|
gtk_window_resize (GTK_WINDOW(context->widget), width, height);
|
||||||
|
|
||||||
|
gtk_window_move (GTK_WINDOW(context->window),
|
||||||
|
(rect.width - width) / 2,
|
||||||
|
rect.height - height);
|
||||||
|
|
||||||
|
gtk_window_set_decorated (GTK_WINDOW(context->window), FALSE);
|
||||||
|
gtk_window_set_resizable (GTK_WINDOW(context->window), FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define KEYBOARD_HEIGHT 210
|
#define KEYBOARD_HEIGHT 210
|
||||||
static void
|
static void
|
||||||
make_window (ServerContextService *context)
|
make_window (ServerContextService *context)
|
||||||
@ -175,6 +237,7 @@ make_widget (ServerContextService *context)
|
|||||||
gtk_widget_set_has_tooltip (context->widget, TRUE);
|
gtk_widget_set_has_tooltip (context->widget, TRUE);
|
||||||
gtk_container_add (GTK_CONTAINER(context->window), context->widget);
|
gtk_container_add (GTK_CONTAINER(context->window), context->widget);
|
||||||
gtk_widget_show (context->widget);
|
gtk_widget_show (context->widget);
|
||||||
|
set_geometry (context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -182,11 +245,6 @@ server_context_service_real_show_keyboard (EekboardContextService *_context)
|
|||||||
{
|
{
|
||||||
ServerContextService *context = SERVER_CONTEXT_SERVICE(_context);
|
ServerContextService *context = SERVER_CONTEXT_SERVICE(_context);
|
||||||
|
|
||||||
if (context->hiding) {
|
|
||||||
g_source_remove (context->hiding);
|
|
||||||
context->hiding = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!context->window)
|
if (!context->window)
|
||||||
make_window (context);
|
make_window (context);
|
||||||
if (!context->widget)
|
if (!context->widget)
|
||||||
@ -197,22 +255,12 @@ server_context_service_real_show_keyboard (EekboardContextService *_context)
|
|||||||
gtk_widget_show (context->window);
|
gtk_widget_show (context->window);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
on_hide (ServerContextService *context)
|
|
||||||
{
|
|
||||||
gtk_widget_hide (context->window);
|
|
||||||
context->hiding = 0;
|
|
||||||
|
|
||||||
return G_SOURCE_REMOVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
server_context_service_real_hide_keyboard (EekboardContextService *_context)
|
server_context_service_real_hide_keyboard (EekboardContextService *_context)
|
||||||
{
|
{
|
||||||
ServerContextService *context = SERVER_CONTEXT_SERVICE(_context);
|
ServerContextService *context = SERVER_CONTEXT_SERVICE(_context);
|
||||||
|
|
||||||
if (!context->hiding)
|
gtk_widget_hide (context->window);
|
||||||
context->hiding = g_timeout_add (200, (GSourceFunc) on_hide, context);
|
|
||||||
|
|
||||||
EEKBOARD_CONTEXT_SERVICE_CLASS (server_context_service_parent_class)->
|
EEKBOARD_CONTEXT_SERVICE_CLASS (server_context_service_parent_class)->
|
||||||
hide_keyboard (_context);
|
hide_keyboard (_context);
|
||||||
@ -301,10 +349,21 @@ server_context_service_class_init (ServerContextServiceClass *klass)
|
|||||||
static void
|
static void
|
||||||
server_context_service_init (ServerContextService *context)
|
server_context_service_init (ServerContextService *context)
|
||||||
{
|
{
|
||||||
|
GdkScreen *screen = gdk_screen_get_default ();
|
||||||
|
|
||||||
|
g_signal_connect (screen,
|
||||||
|
"monitors-changed",
|
||||||
|
G_CALLBACK(on_monitors_changed),
|
||||||
|
context);
|
||||||
g_signal_connect (context,
|
g_signal_connect (context,
|
||||||
"notify::keyboard",
|
"notify::keyboard",
|
||||||
G_CALLBACK(on_notify_keyboard),
|
G_CALLBACK(on_notify_keyboard),
|
||||||
context);
|
context);
|
||||||
|
|
||||||
|
g_signal_connect (context,
|
||||||
|
"notify::fullscreen",
|
||||||
|
G_CALLBACK(on_notify_fullscreen),
|
||||||
|
context);
|
||||||
}
|
}
|
||||||
|
|
||||||
EekboardContextService *
|
EekboardContextService *
|
||||||
|
|||||||
51
src/server-context.h
Normal file
51
src/server-context.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
|
||||||
|
* Copyright (C) 2010-2011 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef SERVER_CONTEXT_H
|
||||||
|
#define SERVER_CONTEXT_H 1
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define SERVER_CONTEXT_PATH "/org/fedorahosted/Eekboard/Context_%d"
|
||||||
|
#define SERVER_CONTEXT_INTERFACE "org.fedorahosted.Eekboard.Context"
|
||||||
|
|
||||||
|
#define SERVER_TYPE_CONTEXT (server_context_get_type())
|
||||||
|
#define SERVER_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SERVER_TYPE_CONTEXT, ServerContext))
|
||||||
|
#define SERVER_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SERVER_TYPE_CONTEXT, ServerContextClass))
|
||||||
|
#define SERVER_IS_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SERVER_TYPE_CONTEXT))
|
||||||
|
#define SERVER_IS_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SERVER_TYPE_CONTEXT))
|
||||||
|
#define SERVER_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SERVER_TYPE_CONTEXT, ServerContextClass))
|
||||||
|
|
||||||
|
typedef struct _ServerContext ServerContext;
|
||||||
|
|
||||||
|
ServerContext *server_context_new (const gchar *object_path,
|
||||||
|
GDBusConnection *connection);
|
||||||
|
void server_context_set_enabled (ServerContext *context,
|
||||||
|
gboolean enabled);
|
||||||
|
void server_context_set_client_connection
|
||||||
|
(ServerContext *context,
|
||||||
|
const gchar *client_connection);
|
||||||
|
const gchar *server_context_get_client_connection
|
||||||
|
(ServerContext *context);
|
||||||
|
void server_context_set_client_name
|
||||||
|
(ServerContext *context,
|
||||||
|
const gchar *client_name);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
#endif /* SERVER_CONTEXT_H */
|
||||||
24
src/symbol.h
Normal file
24
src/symbol.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#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,46 +1,138 @@
|
|||||||
/*! The symbol object, defining actions that the key can do when activated */
|
|
||||||
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
|
||||||
/// Name of the keysym
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
/// Gathers stuff defined in C or called by C
|
||||||
pub struct KeySym(pub String);
|
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),
|
||||||
|
}
|
||||||
|
|
||||||
/// Use to switch layouts
|
/// Use to switch layouts
|
||||||
type Level = String;
|
type Level = u8;
|
||||||
|
|
||||||
/// Use to send modified keypresses
|
/// Use to send modified keypresses
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Modifier {
|
pub enum Modifier {
|
||||||
Control,
|
Control,
|
||||||
Alt,
|
Alt,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Action to perform on the keypress and, in reverse, on keyrelease
|
/// Action to perform on the keypress and, in reverse, on keyrelease
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
/// Switch to this view
|
/// Switch to this level TODO: reverse?
|
||||||
SetLevel(Level),
|
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?
|
/// Set this modifier TODO: release?
|
||||||
SetModifier(Modifier),
|
SetModifier(Modifier),
|
||||||
/// Submit some text
|
/// Submit some text
|
||||||
Submit {
|
Submit {
|
||||||
/// Text to submit with input-method
|
/// orig: Canonical name of the symbol
|
||||||
text: Option<CString>,
|
text: Option<CString>,
|
||||||
/// The key events this symbol submits when submitting text is not possible
|
/// The key events this symbol submits when submitting text is not possible
|
||||||
keys: Vec<KeySym>,
|
keys: Vec<XKeySym>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains a static description of a particular key's actions
|
/// Contains a static description of a particular key's actions
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Symbol {
|
pub struct Symbol {
|
||||||
/// The action that this key performs
|
/// The action that this key performs
|
||||||
pub action: Action,
|
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,14 +1,9 @@
|
|||||||
pub mod c {
|
pub mod c {
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::ffi::{ CStr, CString };
|
use std::ffi::{ CStr, CString };
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::str::Utf8Error;
|
use std::str::Utf8Error;
|
||||||
|
|
||||||
// traits
|
#[allow(dead_code)]
|
||||||
|
|
||||||
use std::borrow::ToOwned;
|
|
||||||
|
|
||||||
pub fn as_str(s: &*const c_char) -> Result<Option<&str>, Utf8Error> {
|
pub fn as_str(s: &*const c_char) -> Result<Option<&str>, Utf8Error> {
|
||||||
if s.is_null() {
|
if s.is_null() {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@ -52,52 +47,4 @@ pub mod c {
|
|||||||
assert_eq!(as_str(&ptr::null()), Ok(None))
|
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
63
src/xdg.rs
@ -1,63 +0,0 @@
|
|||||||
/*! 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())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
45
tests/eek-simple-test.c
Normal file
45
tests/eek-simple-test.c
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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 ();
|
||||||
|
}
|
||||||
55
tests/eek-xml-test.c
Normal file
55
tests/eek-xml-test.c
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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 ();
|
||||||
|
}
|
||||||
@ -1,41 +0,0 @@
|
|||||||
#!/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)
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
---
|
|
||||||
row_spacing: 0
|
|
||||||
button_spacing: 0
|
|
||||||
|
|
||||||
bounds:
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
width: 0
|
|
||||||
height: 0
|
|
||||||
views:
|
|
||||||
base:
|
|
||||||
- "test"
|
|
||||||
outlines:
|
|
||||||
default:
|
|
||||||
bounds: { x: 0, y: 0, width: 0, height: 0 }
|
|
||||||
|
|
||||||
buttons:
|
|
||||||
test:
|
|
||||||
label: "test"
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
---
|
|
||||||
# missing views
|
|
||||||
row_spacing: 0
|
|
||||||
button_spacing: 0
|
|
||||||
|
|
||||||
bounds:
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
width: 0
|
|
||||||
height: 0
|
|
||||||
outlines:
|
|
||||||
default:
|
|
||||||
bounds: { x: 0, y: 0, width: 0, height: 0 }
|
|
||||||
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
---
|
|
||||||
# extra field
|
|
||||||
row_spacing: 0
|
|
||||||
button_spacing: 0
|
|
||||||
|
|
||||||
bounds:
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
width: 0
|
|
||||||
height: 0
|
|
||||||
views:
|
|
||||||
base:
|
|
||||||
- "test"
|
|
||||||
outlines:
|
|
||||||
default:
|
|
||||||
bounds: { x: 0, y: 0, width: 0, height: 0 }
|
|
||||||
|
|
||||||
bad_field: false
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
# punctuation
|
|
||||||
row_spacing: 0
|
|
||||||
button_spacing: 0
|
|
||||||
|
|
||||||
bounds:
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
width: 0
|
|
||||||
height: 0
|
|
||||||
views:
|
|
||||||
base:
|
|
||||||
- "."
|
|
||||||
outlines:
|
|
||||||
default:
|
|
||||||
bounds: { x: 0, y: 0, width: 0, height: 0 }
|
|
||||||
|
|
||||||
buttons:
|
|
||||||
".":
|
|
||||||
label: "test"
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
# punctuation
|
|
||||||
row_spacing: 0
|
|
||||||
button_spacing: 0
|
|
||||||
|
|
||||||
bounds:
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
width: 0
|
|
||||||
height: 0
|
|
||||||
views:
|
|
||||||
base:
|
|
||||||
- "å"
|
|
||||||
outlines:
|
|
||||||
default:
|
|
||||||
bounds: { x: 0, y: 0, width: 0, height: 0 }
|
|
||||||
|
|
||||||
buttons:
|
|
||||||
å:
|
|
||||||
label: "test"
|
|
||||||
@ -19,10 +19,13 @@ test_link_args = [
|
|||||||
'-fPIC',
|
'-fPIC',
|
||||||
]
|
]
|
||||||
|
|
||||||
c_tests = [
|
tests = [
|
||||||
|
'eek-simple-test',
|
||||||
|
'eek-xml-test',
|
||||||
|
'test-keymap-generation'
|
||||||
]
|
]
|
||||||
|
|
||||||
foreach name : c_tests
|
foreach name : tests
|
||||||
|
|
||||||
test_sources = [name + '.c']
|
test_sources = [name + '.c']
|
||||||
|
|
||||||
@ -44,15 +47,4 @@ foreach name : c_tests
|
|||||||
|
|
||||||
endforeach
|
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', 'el', 'es', 'it', 'nb', 'number']
|
|
||||||
test(
|
|
||||||
'test_layout_' + layout,
|
|
||||||
cargo_script,
|
|
||||||
args: ['', 'run', '--example', 'test_layout', layout]
|
|
||||||
)
|
|
||||||
endforeach
|
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|||||||
72
tests/test-keymap-generation.c
Normal file
72
tests/test-keymap-generation.c
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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