Compare commits

..

4 Commits

Author SHA1 Message Date
0e2def7069 Merge branch 'dorota.czaplejewicz/squeekboard-layouts' into 'layouts'
Check for null buttons

See merge request dorota.czaplejewicz/squeekboard!7
2019-08-28 14:14:41 +00:00
aa5e1d87dd Check for null buttons 2019-08-28 14:01:25 +00:00
0a0f7a09a4 Check for button position more in Rust
The check against fitting inside the Layout was removed: as an optimization it is unneeded, as the actual search must be optimized to be quick. In addition, the view bounds don't correspond to anything physical as long as negative offsets are allowed.
2019-08-28 10:45:04 +00:00
9ef38ecf30 Drop callback iteration for button finding 2019-08-28 10:45:00 +00:00
116 changed files with 9312 additions and 5071 deletions

View File

@ -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 .
@ -22,35 +18,14 @@ build_meson:
artifacts: artifacts:
paths: paths:
- _build - _build
expire_in: 3h
script: script:
- 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
needs: dependencies:
- build_meson - build_meson
script: script:
- ninja -C _build test - ninja -C _build test

37
AUTHORS
View File

@ -1,5 +1,36 @@
squeekboard is written by Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> on behlf of Purism, SPC. eekboard is written by Daiki Ueno <ueno@unixuser.org>. The following
eekboard was written by Daiki Ueno <ueno@unixuser.org> files contain code derived from other free software packages:
For more details, see the debian/copyright file. eek/eek-keyboard-drawing.h
eek/eek-keyboard-drawing.c
These files contain code derived from the libgnomekbd library.
Copyright (C) 2006 Sergey V. Udaltsov <svu@gnome.org>
eek/eek-theme.h
eek/eek-theme.c
eek/eek-theme-context.h
eek/eek-theme-context.c
eek/eek-theme-node.h
eek/eek-theme-node.c
These files contain code derived from gnome-shell.
Copyright 2008-2010 Red Hat, Inc.
Copyright 2009 Steve Frécinaux
Copyright 2009, 2010 Florian Müllner
Copyright 2010 Adel Gadllah
Copyright 2010 Giovanni Campagna
Copyright 2003-2004 Dodji Seketeli
data/icons/8x8/Makefile.am
data/icons/16x16/Makefile.am
data/icons/22x22/Makefile.am
data/icons/24x24/Makefile.am
data/icons/32x32/Makefile.am
data/icons/48x48/Makefile.am
data/icons/scalable/Makefile.am
These files contain code derived from im-chooser.
Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved.

162
Cargo.lock generated
View File

@ -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"

View File

@ -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"]

View File

@ -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
```

View File

@ -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
```

View File

@ -0,0 +1 @@
Eek cheader_filename="eek/eek.h"

View File

@ -0,0 +1 @@
EekGtk cheader_filename="eek/eek-gtk.h"

View File

@ -0,0 +1 @@
EekXkl cheader_filename="eek/eek-xkl.h"

View File

@ -0,0 +1 @@
gio-2.0

View File

@ -0,0 +1 @@
eek-0.90

View File

@ -0,0 +1,2 @@
eek-0.90
x11

View File

@ -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

View File

@ -0,0 +1,6 @@
[Desktop Entry]
Name=Eekboard
Exec=eekboard -f
Type=Application
#AutostartCondition=GSettings org.gnome.desktop.a11y.applications screen-keyboard-enabled
X-GNOME-AutoRestart=true

View File

@ -0,0 +1,3 @@
[D-BUS Service]
Name=org.fedorahosted.Eekboard
Exec=@bindir@/eekboard-server

9
data/eekboard.desktop.in Normal file
View File

@ -0,0 +1,9 @@
[Desktop Entry]
Name=Eekboard
GenericName=Eekboard Virtual Keyboard
Comment=Virtual Keyboard
Exec=eekboard
Icon=eekboard
Terminal=false
Type=Application
Categories=GTK;Utility;

View File

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

View File

@ -1,196 +0,0 @@
# Greek layout created by Antonis Tsolomitis
# University of the Aegean, Department of Mathematics, atsol@aegean.gr
# Sep 2019
---
bounds: { x: 0, y: 0.33, width: 360, height: 210 }
outlines:
default:
bounds: { x: 0, y: 0, width: 32, height: 52 }
altline:
bounds: { x: 0, y: 0, width: 48.39024, height: 52 }
wide:
bounds: { x: 0, y: 0, width: 62, 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 period 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: "wide"
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: "]"

View File

@ -1,93 +0,0 @@
---
bounds: { x: 0, y: 1, width: 360, height: 210 }
outlines:
default:
bounds: { x: 0, y: 0, width: 35.33, height: 52 }
altline:
bounds: { x: 0, y: 0, width: 52.67, height: 52 }
wide:
bounds: { x: 0, y: 0, width: 62, height: 52 }
spaceline:
bounds: { x: 0, y: 0, width: 99.67, height: 52 }
special:
bounds: { x: 0, y: 0, width: 44, height: 52 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l ñ"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers show_eschars preferences space ? period Return"
upper:
- "Q W E R T Y U I O P"
- "A S D F G H J K L Ñ"
- "Shift_L Z X C V B N M BackSpace"
- "show_numbers show_eschars preferences space ¿ period Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon ; ! = BackSpace"
- "show_letters show_eschars preferences space ? period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers \\ / < > = [ ] BackSpace"
- "show_letters show_eschars preferences space ? period Return"
eschars:
- "á é í ó ú Á É Í Ó Ú"
- "à è ì ò ù À È Ì Ò Ù"
- "show_numbers ü ç ï Ü Ç Ï ¡ BackSpace"
- "show_letters show_eschars preferences space « » Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
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"

View 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>

View 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>

View 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>

View File

@ -1,97 +0,0 @@
# Italian layout created by Antonio Pandolfo
# 03 october 2019
---
bounds: { x: 0, y: 1, width: 360, height: 210 }
outlines:
default:
bounds: { x: 0, y: 0, width: 35.33, height: 52 }
altline:
bounds: { x: 0, y: 0, width: 52.67, height: 52 }
wide:
bounds: { x: 0, y: 0, width: 62, height: 52 }
spaceline:
bounds: { x: 0, y: 0, width: 99.67, height: 52 }
special:
bounds: { x: 0, y: 0, width: 44, height: 52 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers show_eschars preferences space , period Return"
upper:
- "Q W E R T Y U I O P"
- "A S D F G H J K L"
- "Shift_L Z X C V B N M BackSpace"
- "show_numbers show_eschars preferences space ? period Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters show_eschars preferences space ? period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers \\ / < > = [ ] BackSpace"
- "show_letters show_eschars preferences space ? period Return"
eschars:
- "á é í ó ú Á É Í Ó Ú"
- "à è ì ò « » ù ! { }"
- "show_numbers \\ / < > = [ ] BackSpace"
- "show_letters show_eschars preferences space « » Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
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_eschars:
action:
set_view: "eschars"
outline: "altline"
label: "àè"
period:
outline: "default"
label: "."
space:
outline: "spaceline"
label: " "
Return:
outline: "altline"
icon: "key-enter"
colon:
label: ":"
"\"":
keysym: "quotedbl"

View File

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

View File

@ -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>

View File

@ -1,177 +0,0 @@
---
bounds: { x: 0, y: 0.33, width: 360, height: 210 }
outlines:
default:
bounds: { x: 0, y: 0, width: 32, height: 52 }
altline:
bounds: { x: 0, y: 0, width: 48.39024, height: 52 }
wide:
bounds: { x: 0, y: 0, width: 62, 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: "wide"
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: "]"

View File

@ -1,43 +0,0 @@
---
bounds: { x: 0, y: 0.33, width: 360, height: 210 }
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: ")"

View 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="&#964;">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="&#183;">U00B7</symbol>
<symbol label="t">t</symbol>
<symbol label="T">T</symbol>
<symbol label="5">5</symbol>
<symbol label="&#8730;">squareroot</symbol>
<symbol label="y">y</symbol>
<symbol label="Y">Y</symbol>
<symbol label="6">6</symbol>
<symbol label="&#960;">Greek_pi</symbol>
<symbol label="u">u</symbol>
<symbol label="U">U</symbol>
<symbol label="7">7</symbol>
<symbol label="&#247;">division</symbol>
<symbol label="i">i</symbol>
<symbol label="I">I</symbol>
<symbol label="8">8</symbol>
<symbol label="&#215;">multiply</symbol>
<symbol label="o">o</symbol>
<symbol label="O">O</symbol>
<symbol label="9">9</symbol>
<symbol label="&#182;">paragraph</symbol>
<symbol label="p">p</symbol>
<symbol label="P">P</symbol>
<symbol label="0">0</symbol>
<symbol label="&#9651;">U25B3</symbol>
<symbol keyval="229" label="&#229;">aring</symbol>
<symbol keyval="197" label="&#197;">Aring</symbol>
<symbol label="a">a</symbol>
<symbol label="A">A</symbol>
<symbol label="@">at</symbol>
<symbol label="&#169;">copyright</symbol>
<symbol label="s">s</symbol>
<symbol label="S">S</symbol>
<symbol label="#">numbersign</symbol>
<symbol label="&#174;">U00AE</symbol>
<symbol label="d">d</symbol>
<symbol label="D">D</symbol>
<symbol label="$">dollar</symbol>
<symbol label="&#163;">U00A3</symbol>
<symbol label="f">f</symbol>
<symbol label="F">F</symbol>
<symbol label="%">percent</symbol>
<symbol label="&#8364;">EuroSign</symbol>
<symbol label="g">g</symbol>
<symbol label="G">G</symbol>
<symbol label="&amp;">ampersand</symbol>
<symbol label="&#165;">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="&#176;">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="&#248;">oslash</symbol>
<symbol keyval="216" label="&#216;">Oslash</symbol>
<symbol label=")">parenright</symbol>
<symbol label="}">braceright</symbol>
<symbol keyval="230" label="&#230;">ae</symbol>
<symbol keyval="198" label="&#198;">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="&quot;">quotedbl</symbol>
<symbol label="/">slash</symbol>
<symbol label="c">c</symbol>
<symbol label="C">C</symbol>
<symbol label="'">quoteright</symbol>
<symbol label="&lt;">less</symbol>
<symbol label="v">v</symbol>
<symbol label="V">V</symbol>
<symbol label=":">colon</symbol>
<symbol label="&gt;">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="&#9786;" icon="keyboard-mode-symbolic" tooltip="Setup">preferences</symbol>
<symbol label=" ">space</symbol>
<symbol keyval="65288" icon="edit-clear-symbolic">BackSpace</symbol>
</symbols>

View 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>

View 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="&#183;">U00B7</symbol>
<symbol label="t">t</symbol>
<symbol label="T">T</symbol>
<symbol label="5">5</symbol>
<symbol label="&#8730;">squareroot</symbol>
<symbol label="y">y</symbol>
<symbol label="Y">Y</symbol>
<symbol label="6">6</symbol>
<symbol label="&#960;">Greek_pi</symbol>
<symbol label="u">u</symbol>
<symbol label="U">U</symbol>
<symbol label="7">7</symbol>
<symbol label="&#247;">division</symbol>
<symbol label="i">i</symbol>
<symbol label="I">I</symbol>
<symbol label="8">8</symbol>
<symbol label="&#215;">multiply</symbol>
<symbol label="o">o</symbol>
<symbol label="O">O</symbol>
<symbol label="9">9</symbol>
<symbol label="&#182;">paragraph</symbol>
<symbol label="p">p</symbol>
<symbol label="P">P</symbol>
<symbol label="0">0</symbol>
<symbol label="&#964;">Greek_tau</symbol>
<symbol label="a">a</symbol>
<symbol label="A">A</symbol>
<symbol label="@">at</symbol>
<symbol label="&#169;">copyright</symbol>
<symbol label="s">s</symbol>
<symbol label="S">S</symbol>
<symbol label="#">numbersign</symbol>
<symbol label="&#174;">U00AE</symbol>
<symbol label="d">d</symbol>
<symbol label="D">D</symbol>
<symbol label="$">dollar</symbol>
<symbol label="&#163;">U00A3</symbol>
<symbol label="f">f</symbol>
<symbol label="F">F</symbol>
<symbol label="%">percent</symbol>
<symbol label="&#8364;">EuroSign</symbol>
<symbol label="g">g</symbol>
<symbol label="G">G</symbol>
<symbol label="&amp;">ampersand</symbol>
<symbol label="&#165;">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="&#176;">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="&quot;">quotedbl</symbol>
<symbol label="/">slash</symbol>
<symbol label="c">c</symbol>
<symbol label="C">C</symbol>
<symbol label="'">quoteright</symbol>
<symbol label="&lt;">less</symbol>
<symbol label="v">v</symbol>
<symbol label="V">V</symbol>
<symbol label=":">colon</symbol>
<symbol label="&gt;">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="&#9786;" icon="keyboard-mode-symbolic" tooltip="Setup">preferences</symbol>
<symbol label=" ">space</symbol>
<symbol keyval="65288" icon="edit-clear-symbolic">BackSpace</symbol>
</symbols>

View File

@ -1,85 +0,0 @@
---
bounds: { x: 0, y: 1, width: 360, height: 208 }
outlines:
default:
bounds: { x: 0, y: 0, width: 35.33, height: 52 }
altline:
bounds: { x: 0, y: 0, width: 52.67, height: 52 }
wide:
bounds: { x: 0, y: 0, width: 62, height: 52 }
spaceline:
bounds: { x: 0, y: 0, width: 142, height: 52 }
special:
bounds: { x: 0, y: 0, width: 44, height: 52 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers preferences space 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"

View File

@ -1,85 +0,0 @@
---
bounds: { x: 0, y: 1, width: 540, height: 168 }
outlines:
default:
bounds: { x: 0, y: 0, width: 54, height: 42 }
altline:
bounds: { x: 0, y: 0, width: 81, height: 42 }
wide:
bounds: { x: 0, y: 0, width: 108, height: 42 }
spaceline:
bounds: { x: 0, y: 0, width: 216, height: 42 }
special:
bounds: { x: 0, y: 0, width: 54, height: 42 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers preferences space 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"

View File

@ -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;

View File

@ -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>

View File

@ -1,46 +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_view 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;
margin: 4px 2px 4px 2px;
} }
sq_view.wide sq_button { .key:active {
margin: 1px 1px 1px 1px;
}
sq_button:active {
background: #747077;
border-color: #96949d;
}
sq_button.altline,
sq_button.special,
sq_button.wide {
background: #2b292f;
border-color: #3e3a44;
}
sq_button.locked {
background: #ffffff;
color: #2b292f;
}
#Return {
background: #1c71d8;
border-color: #1a5fb4;
}
#Return:active {
background: #1c71d8; background: #1c71d8;
border-color: #3584e4; border-color: #3584e4;
} }

12
debian/cargo/config vendored
View File

@ -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'

25
debian/changelog vendored
View File

@ -1,28 +1,3 @@
squeekboard (1.2.2) amber-phone; urgency=medium
* Landscape mode
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Wed, 30 Oct 2019 12:38:39 +0000
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
View File

@ -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
View File

@ -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:

View File

@ -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

View File

@ -0,0 +1,83 @@
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
[
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
]>
<book id="index">
<bookinfo>
<title>libeek Reference Manual</title>
<releaseinfo>
for libeek 0.90.0.
</releaseinfo>
<copyright>
<year>2010-2011</year>
<holder>Daiki Ueno</holder>
</copyright>
<copyright>
<year>2010-2011</year>
<holder>Red Hat, Inc.</holder>
</copyright>
<legalnotice>
<para>
Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License,
Version 1.3 or any later version published by the Free Software
Foundation; with no Invariant Sections, no Front-Cover Texts and
no Back-Cover Texts. A copy of the license is included in the
section entitled "GNU Free Documentation License".
</para>
</legalnotice>
</bookinfo>
<xi:include href="xml/eek-overview.xml"/>
<part id="apireference">
<title>API Manual</title>
<chapter>
<title>Base Classes, Interfaces, and Utilities</title>
<xi:include href="xml/eek.xml"/>
<xi:include href="xml/eek-serializable.xml"/>
<xi:include href="xml/eek-element.xml"/>
<xi:include href="xml/eek-container.xml"/>
<xi:include href="xml/eek-keyboard.xml"/>
<xi:include href="xml/eek-section.xml"/>
<xi:include href="xml/eek-key.xml"/>
<xi:include href="xml/eek-symbol.xml"/>
<xi:include href="xml/eek-keysym.xml"/>
<xi:include href="xml/eek-text.xml"/>
<xi:include href="xml/eek-layout.xml"/>
<xi:include href="xml/eek-types.xml"/>
</chapter>
<chapter>
<title>GTK Adapter</title>
<xi:include href="xml/eek-gtk-keyboard.xml"/>
</chapter>
<chapter>
<title>Clutter Adapter</title>
<xi:include href="xml/eek-clutter-keyboard.xml"/>
</chapter>
<chapter>
<title>Libxklavier Layout Engine</title>
<xi:include href="xml/eek-xkl-layout.xml"/>
</chapter>
<chapter>
<title>XKB Layout Engine</title>
<xi:include href="xml/eek-xkb-layout.xml"/>
</chapter>
<chapter>
<title>XML Layout Engine</title>
<xi:include href="xml/eek-xml-layout.xml"/>
<xi:include href="xml/eek-xml.xml"/>
</chapter>
<chapter id="object-tree">
<title>Object Hierarchy</title>
<xi:include href="xml/tree_index.sgml"/>
</chapter>
<index id="api-index-full">
<title>API Index</title>
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
</index>
</part>
</book>

View File

@ -0,0 +1,70 @@
<part id="eek-overview">
<title>Usage Overview</title>
<partintro>
<para>libeek is a library to create keyboard-like user interface.
Since it is designed as simple as possible, it provides only two
kind of objects. One is <emphasis>keyboard element</emphasis>
(objects derived from #EekElement) and another is
<emphasis>keyboard layout engine</emphasis> (objects which
implements the #EekLayout interface).</para>
<para>A keyboard element represents either a keyboard
(#EekKeyboard), a section (#EekSection), or a key (#EekKey). Each
element implements the Builder design pattern so that it can map
itself to different UI widgets (#ClutterActor, #GtkDrawingArea,
aso).</para>
<para>A layout engine arranges keyboard elements using information
from external configuration mechanisms (libxklavier, XKB,
matchbox-keyboard layouts in XML, aso)</para>
<para>Here is a sample code which demonstrates (1) keyboard
elements are arranged with the system keyboard layout using
libxklavier and (2) keyboard elements are mapped into
#ClutterActor:</para>
<informalexample>
<programlisting>
EekLayout *layout;
EekKeyboard *keyboard;
ClutterActor *actor;
/* Create a layout engine based on libxklavier configuration. */
layout = eek_xkl_layout_new ();
/* Create a keyboard from the given layout. */
keyboard = eek_keyboard_new (layout, initial_width, initial_height);
/* Create a ClutterActor. */
actor = eek_clutter_keyboard_new (eekboard->keyboard);
/* Add the actor to a stage. */
clutter_group_add (CLUTTER_GROUP(stage), actor);
</programlisting>
</informalexample>
<para>libeek currently supports GTK+ and Clutter as UI toolkits.
To create a keyboard-like #GtkWidget instead of #ClutterActor,
replace eek_clutter_keyboard_new() with eek_gtk_keyboard_new().
Similarly, if you want to use XKB configuration directly (without
libxklavier), you will only need to replace eek_xkl_layout_new ()
with eek_xkb_layout_new().</para>
<para>In the above example, a keyboard is represented as a tree of
#EekElement -- #EekKeyboard contains one or more #EekSection's and
#EekSection contains one or more #EekKey's. Each element may emit
events when user pushes the corresponding UI widget.</para>
<para>
Here is another sample code which demonstrates logical events on
#EekElement:
</para>
<informalexample>
<programlisting>
/* Find a key element in the logical keyboard. */
EekKey *key = eek_keyboard_find_key_by_keycode (keyboard, 0x38);
g_signal_connect (key, "pressed", on_a_pressed);
</programlisting>
</informalexample>
<para>When user pushed a widget which looks like "a" key (i.e. keycode 0x38), on_a_pressed will be called.</para>
</partintro>
</part>

View File

@ -0,0 +1,544 @@
<SECTION>
<FILE>eek</FILE>
eek_init
</SECTION>
<SECTION>
<FILE>eek-clutter</FILE>
</SECTION>
<SECTION>
<FILE>eek-clutter-key</FILE>
<TITLE>EekClutterKey</TITLE>
EekClutterKey
EekClutterKeyClass
eek_clutter_key_new
<SUBSECTION Standard>
EEK_CLUTTER_KEY
EEK_CLUTTER_KEY_CLASS
EEK_CLUTTER_KEY_GET_CLASS
EEK_IS_CLUTTER_KEY
EEK_IS_CLUTTER_KEY_CLASS
EEK_TYPE_CLUTTER_KEY
EekClutterKeyPrivate
eek_clutter_key_get_type
</SECTION>
<SECTION>
<FILE>eek-clutter-keyboard</FILE>
<TITLE>EekClutterKeyboard</TITLE>
EekClutterKeyboard
EekClutterKeyboardClass
eek_clutter_keyboard_new
eek_clutter_keyboard_set_theme
<SUBSECTION Standard>
EEK_CLUTTER_KEYBOARD
EEK_CLUTTER_KEYBOARD_CLASS
EEK_CLUTTER_KEYBOARD_GET_CLASS
EEK_IS_CLUTTER_KEYBOARD
EEK_IS_CLUTTER_KEYBOARD_CLASS
EEK_TYPE_CLUTTER_KEYBOARD
EekClutterKeyboardPrivate
eek_clutter_keyboard_get_type
</SECTION>
<SECTION>
<FILE>eek-clutter-renderer</FILE>
<TITLE>EekClutterRenderer</TITLE>
EekClutterRenderer
EekClutterRendererClass
eek_clutter_renderer_new
eek_clutter_renderer_render_key
<SUBSECTION Standard>
EEK_CLUTTER_RENDERER
EEK_CLUTTER_RENDERER_CLASS
EEK_CLUTTER_RENDERER_GET_CLASS
EEK_IS_CLUTTER_RENDERER
EEK_IS_CLUTTER_RENDERER_CLASS
EEK_TYPE_CLUTTER_RENDERER
EekClutterRendererPrivate
eek_clutter_renderer_get_type
</SECTION>
<SECTION>
<FILE>eek-clutter-section</FILE>
<TITLE>EekClutterSection</TITLE>
EekClutterSection
EekClutterSectionClass
eek_clutter_section_new
<SUBSECTION Standard>
EEK_CLUTTER_SECTION
EEK_CLUTTER_SECTION_CLASS
EEK_CLUTTER_SECTION_GET_CLASS
EEK_IS_CLUTTER_SECTION
EEK_IS_CLUTTER_SECTION_CLASS
EEK_TYPE_CLUTTER_SECTION
EekClutterSectionPrivate
eek_clutter_section_get_type
</SECTION>
<SECTION>
<FILE>eek-container</FILE>
<TITLE>EekContainer</TITLE>
EekCallback
EekCompareFunc
EekContainer
EekContainerClass
eek_container_add_child
eek_container_find
eek_container_foreach_child
<SUBSECTION Standard>
EEK_CONTAINER
EEK_CONTAINER_CLASS
EEK_CONTAINER_GET_CLASS
EEK_IS_CONTAINER
EEK_IS_CONTAINER_CLASS
EEK_TYPE_CONTAINER
EekContainerPrivate
eek_container_get_type
</SECTION>
<SECTION>
<FILE>eek-element</FILE>
<TITLE>EekElement</TITLE>
EekElement
EekElementClass
eek_element_get_absolute_position
eek_element_get_bounds
eek_element_get_group
eek_element_get_level
eek_element_get_name
eek_element_get_parent
eek_element_get_symbol_index
eek_element_set_bounds
eek_element_set_group
eek_element_set_level
eek_element_set_name
eek_element_set_parent
eek_element_set_position
eek_element_set_size
eek_element_set_symbol_index
<SUBSECTION Standard>
EEK_ELEMENT
EEK_ELEMENT_CLASS
EEK_ELEMENT_GET_CLASS
EEK_IS_ELEMENT
EEK_IS_ELEMENT_CLASS
EEK_TYPE_ELEMENT
EekElementPrivate
eek_element_get_type
</SECTION>
<SECTION>
<FILE>eek-gtk</FILE>
</SECTION>
<SECTION>
<FILE>eek-gtk-keyboard</FILE>
<TITLE>EekGtkKeyboard</TITLE>
EekGtkKeyboard
EekGtkKeyboardClass
eek_gtk_keyboard_new
eek_gtk_keyboard_set_theme
<SUBSECTION Standard>
EEK_GTK_KEYBOARD
EEK_GTK_KEYBOARD_CLASS
EEK_GTK_KEYBOARD_GET_CLASS
EEK_IS_GTK_KEYBOARD
EEK_IS_GTK_KEYBOARD_CLASS
EEK_TYPE_GTK_KEYBOARD
EekGtkKeyboardPrivate
eek_gtk_keyboard_get_type
</SECTION>
<SECTION>
<FILE>eek-key</FILE>
<TITLE>EekKey</TITLE>
EekKey
EekKeyClass
eek_key_get_index
eek_key_get_keycode
eek_key_get_oref
eek_key_get_symbol
eek_key_get_symbol_at_index
eek_key_get_symbol_matrix
eek_key_get_symbol_with_fallback
eek_key_is_locked
eek_key_is_pressed
eek_key_set_index
eek_key_set_keycode
eek_key_set_oref
eek_key_set_symbol_matrix
<SUBSECTION Standard>
EEK_IS_KEY
EEK_IS_KEY_CLASS
EEK_KEY
EEK_KEY_CLASS
EEK_KEY_GET_CLASS
EEK_TYPE_KEY
EekKeyPrivate
eek_key_get_type
</SECTION>
<SECTION>
<FILE>eek-keyboard</FILE>
<TITLE>EekKeyboard</TITLE>
EekKeyboard
EekKeyboardClass
EekModifierKey
eek_keyboard_add_outline
eek_keyboard_create_section
eek_keyboard_find_key_by_keycode
eek_keyboard_get_alt_gr_mask
eek_keyboard_get_group
eek_keyboard_get_layout
eek_keyboard_get_level
eek_keyboard_get_locked_keys
eek_keyboard_get_modifier_behavior
eek_keyboard_get_modifiers
eek_keyboard_get_num_lock_mask
eek_keyboard_get_outline
eek_keyboard_get_pressed_keys
eek_keyboard_get_size
eek_keyboard_get_symbol_index
eek_keyboard_new
eek_keyboard_set_alt_gr_mask
eek_keyboard_set_group
eek_keyboard_set_level
eek_keyboard_set_modifier_behavior
eek_keyboard_set_modifiers
eek_keyboard_set_num_lock_mask
eek_keyboard_set_size
eek_keyboard_set_symbol_index
<SUBSECTION Standard>
EEK_IS_KEYBOARD
EEK_IS_KEYBOARD_CLASS
EEK_KEYBOARD
EEK_KEYBOARD_CLASS
EEK_KEYBOARD_GET_CLASS
EEK_TYPE_KEYBOARD
EekKeyboardPrivate
eek_keyboard_get_type
</SECTION>
<SECTION>
<FILE>eek-keysym</FILE>
<TITLE>EekKeysym</TITLE>
EekKeysym
EekKeysymClass
eek_keysym_get_xkeysym
eek_keysym_new
eek_keysym_new_from_name
eek_keysym_new_with_modifier
<SUBSECTION Standard>
EEK_INVALID_KEYSYM
EEK_IS_KEYSYM
EEK_IS_KEYSYM_CLASS
EEK_KEYSYM
EEK_KEYSYM_CLASS
EEK_KEYSYM_GET_CLASS
EEK_TYPE_KEYSYM
EekKeysymPrivate
eek_keysym_get_type
</SECTION>
<SECTION>
<FILE>eek-layout</FILE>
<TITLE>EekLayout</TITLE>
EekLayout
EekLayoutClass
<SUBSECTION Standard>
EEK_IS_LAYOUT
EEK_IS_LAYOUT_CLASS
EEK_LAYOUT
EEK_LAYOUT_CLASS
EEK_LAYOUT_GET_CLASS
EEK_TYPE_LAYOUT
eek_layout_get_type
</SECTION>
<SECTION>
<FILE>eek-marshalers</FILE>
</SECTION>
<SECTION>
<FILE>eek-section</FILE>
<TITLE>EekSection</TITLE>
EekSection
EekSectionClass
eek_section_add_row
eek_section_create_key
eek_section_find_key_by_keycode
eek_section_get_angle
eek_section_get_n_rows
eek_section_get_row
eek_section_set_angle
<SUBSECTION Standard>
EEK_IS_SECTION
EEK_IS_SECTION_CLASS
EEK_SECTION
EEK_SECTION_CLASS
EEK_SECTION_GET_CLASS
EEK_TYPE_SECTION
EekSectionPrivate
eek_section_get_type
</SECTION>
<SECTION>
<FILE>eek-serializable</FILE>
<TITLE>EekSerializable</TITLE>
EekSerializableIface
eek_serializable_deserialize
eek_serializable_serialize
<SUBSECTION Standard>
EEK_IS_SERIALIZABLE
EEK_SERIALIZABLE
EEK_SERIALIZABLE_GET_IFACE
EEK_TYPE_SERIALIZABLE
eek_serializable_get_type
</SECTION>
<SECTION>
<FILE>eek-special-keysym-entries</FILE>
</SECTION>
<SECTION>
<FILE>eek-symbol</FILE>
<TITLE>EekSymbol</TITLE>
EekSymbol
EekSymbolCategory
EekSymbolClass
eek_symbol_category_from_name
eek_symbol_category_get_name
eek_symbol_get_category
eek_symbol_get_icon_name
eek_symbol_get_label
eek_symbol_get_modifier_mask
eek_symbol_get_name
eek_symbol_is_modifier
eek_symbol_new
eek_symbol_set_category
eek_symbol_set_icon_name
eek_symbol_set_label
eek_symbol_set_modifier_mask
eek_symbol_set_name
<SUBSECTION Standard>
EEK_IS_SYMBOL
EEK_IS_SYMBOL_CLASS
EEK_SYMBOL
EEK_SYMBOL_CLASS
EEK_SYMBOL_GET_CLASS
EEK_TYPE_SYMBOL
EekSymbolPrivate
eek_symbol_get_type
</SECTION>
<SECTION>
<FILE>eek-symbol-matrix</FILE>
EekSymbolMatrix
eek_symbol_matrix_copy
eek_symbol_matrix_free
eek_symbol_matrix_get_symbol
eek_symbol_matrix_new
eek_symbol_matrix_set_symbol
<SUBSECTION Standard>
EEK_TYPE_SYMBOL_MATRIX
eek_symbol_matrix_get_type
</SECTION>
<SECTION>
<FILE>eek-text</FILE>
<TITLE>EekText</TITLE>
EekText
EekTextClass
eek_text_get_text
eek_text_new
<SUBSECTION Standard>
EEK_IS_TEXT
EEK_IS_TEXT_CLASS
EEK_TEXT
EEK_TEXT_CLASS
EEK_TEXT_GET_CLASS
EEK_TYPE_TEXT
EekTextPrivate
eek_text_get_type
</SECTION>
<SECTION>
<FILE>eek-theme-context</FILE>
EekThemeContextClass
eek_theme_context_get_font
eek_theme_context_get_resolution
eek_theme_context_get_root_node
eek_theme_context_get_theme
eek_theme_context_new
eek_theme_context_set_default_resolution
eek_theme_context_set_font
eek_theme_context_set_resolution
eek_theme_context_set_theme
<SUBSECTION Standard>
EEK_IS_THEME_CONTEXT
EEK_IS_THEME_CONTEXT_CLASS
EEK_THEME_CONTEXT
EEK_THEME_CONTEXT_CLASS
EEK_THEME_CONTEXT_GET_CLASS
EEK_TYPE_THEME_CONTEXT
eek_theme_context_get_type
</SECTION>
<SECTION>
<FILE>eek-theme-private</FILE>
</SECTION>
<SECTION>
<FILE>eek-types</FILE>
EEK_INVALID_KEYCODE
EekBounds
EekColor
EekContainer
EekElement
EekGradientType
EekKey
EekKeyboard
EekKeysym
EekModifierBehavior
EekModifierType
EekOrientation
EekOutline
EekPoint
EekSection
EekSymbol
EekSymbolMatrix
EekText
EekTheme
EekThemeContext
EekThemeNode
I_
eek_bounds_copy
eek_bounds_free
eek_bounds_long_side
eek_color_copy
eek_color_free
eek_color_new
eek_outline_copy
eek_outline_free
eek_point_copy
eek_point_free
eek_point_rotate
<SUBSECTION Standard>
EEK_TYPE_BOUNDS
EEK_TYPE_COLOR
EEK_TYPE_OUTLINE
EEK_TYPE_POINT
eek_bounds_get_type
eek_color_get_type
eek_outline_get_type
eek_point_get_type
</SECTION>
<SECTION>
<FILE>eek-unicode-keysym-entries</FILE>
</SECTION>
<SECTION>
<FILE>eek-xkb</FILE>
</SECTION>
<SECTION>
<FILE>eek-xkb-layout</FILE>
<TITLE>EekXkbLayout</TITLE>
EekXkbLayout
EekXkbLayoutClass
eek_xkb_layout_get_geometry
eek_xkb_layout_get_keycodes
eek_xkb_layout_get_symbols
eek_xkb_layout_new
eek_xkb_layout_set_geometry
eek_xkb_layout_set_keycodes
eek_xkb_layout_set_names
eek_xkb_layout_set_names_full
eek_xkb_layout_set_names_full_valist
eek_xkb_layout_set_symbols
<SUBSECTION Standard>
EEK_IS_XKB_LAYOUT
EEK_IS_XKB_LAYOUT_CLASS
EEK_TYPE_XKB_LAYOUT
EEK_XKB_LAYOUT
EEK_XKB_LAYOUT_CLASS
EEK_XKB_LAYOUT_GET_CLASS
EekXkbLayoutPrivate
eek_xkb_layout_get_type
</SECTION>
<SECTION>
<FILE>eek-xkeysym-keysym-entries</FILE>
</SECTION>
<SECTION>
<FILE>eek-xkl</FILE>
</SECTION>
<SECTION>
<FILE>eek-xkl-layout</FILE>
<TITLE>EekXklLayout</TITLE>
EekXklLayout
EekXklLayoutClass
eek_xkl_layout_disable_option
eek_xkl_layout_enable_option
eek_xkl_layout_get_layouts
eek_xkl_layout_get_model
eek_xkl_layout_get_option
eek_xkl_layout_get_options
eek_xkl_layout_get_variants
eek_xkl_layout_new
eek_xkl_layout_set_config
eek_xkl_layout_set_config_full
eek_xkl_layout_set_layouts
eek_xkl_layout_set_model
eek_xkl_layout_set_options
eek_xkl_layout_set_variants
<SUBSECTION Standard>
EEK_IS_XKL_LAYOUT
EEK_IS_XKL_LAYOUT_CLASS
EEK_TYPE_XKL_LAYOUT
EEK_XKL_LAYOUT
EEK_XKL_LAYOUT_CLASS
EEK_XKL_LAYOUT_GET_CLASS
EekXklLayoutPrivate
eek_xkl_layout_get_type
</SECTION>
<SECTION>
<FILE>eek-xml</FILE>
EEK_XML_SCHEMA_VERSION
eek_keyboard_output
</SECTION>
<SECTION>
<FILE>eek-xml-layout</FILE>
<TITLE>EekXmlLayout</TITLE>
EekXmlLayout
EekXmlLayoutClass
eek_xml_layout_get_source
eek_xml_layout_new
eek_xml_layout_set_source
<SUBSECTION Standard>
EEK_IS_XML_LAYOUT
EEK_IS_XML_LAYOUT_CLASS
EEK_TYPE_XML_LAYOUT
EEK_XML_LAYOUT
EEK_XML_LAYOUT_CLASS
EEK_XML_LAYOUT_GET_CLASS
EekXmlLayoutPrivate
eek_xml_layout_get_type
</SECTION>

View File

@ -0,0 +1,56 @@
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
[
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
]>
<book id="index">
<bookinfo>
<title>eekboard Reference Manual</title>
<releaseinfo>
for eekboard 0.90.0.
</releaseinfo>
<copyright>
<year>2011</year>
<holder>Daiki Ueno</holder>
</copyright>
<copyright>
<year>2011</year>
<holder>Red Hat, Inc.</holder>
</copyright>
<legalnotice>
<para>
Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License,
Version 1.3 or any later version published by the Free Software
Foundation; with no Invariant Sections, no Front-Cover Texts and
no Back-Cover Texts. A copy of the license is included in the
section entitled "GNU Free Documentation License".
</para>
</legalnotice>
</bookinfo>
<part id="apireference">
<title>API Manual</title>
<chapter>
<title>Client interface to eekboard-server</title>
<xi:include href="xml/eekboard-client.xml"/>
<xi:include href="xml/eekboard-context.xml"/>
</chapter>
<chapter>
<title>Server interface to implement custom eekboard-server</title>
<xi:include href="xml/eekboard-service.xml"/>
<xi:include href="xml/eekboard-context-service.xml"/>
</chapter>
<chapter id="object-tree">
<title>Object Hierarchy</title>
<xi:include href="xml/tree_index.sgml"/>
</chapter>
<index id="api-index-full">
<title>API Index</title>
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
</index>
</part>
</book>

View File

@ -0,0 +1,104 @@
<SECTION>
<FILE>eekboard-client</FILE>
<TITLE>EekboardClient</TITLE>
EekboardClient
EekboardClientClass
eekboard_client_new
eekboard_client_create_context
eekboard_client_push_context
eekboard_client_pop_context
eekboard_client_destroy_context
EekboardClientPrivate
<SUBSECTION Standard>
EEKBOARD_CLIENT
EEKBOARD_IS_CLIENT
EEKBOARD_TYPE_CLIENT
eekboard_client_get_type
EEKBOARD_CLIENT_CLASS
EEKBOARD_IS_CLIENT_CLASS
EEKBOARD_CLIENT_GET_CLASS
</SECTION>
<SECTION>
<FILE>eekboard-service</FILE>
<TITLE>EekboardService</TITLE>
EEKBOARD_SERVICE_PATH
EEKBOARD_SERVICE_INTERFACE
EekboardService
EekboardServiceClass
eekboard_service_new
EekboardServicePrivate
<SUBSECTION Standard>
EEKBOARD_SERVICE
EEKBOARD_IS_SERVICE
EEKBOARD_TYPE_SERVICE
eekboard_service_get_type
EEKBOARD_SERVICE_CLASS
EEKBOARD_IS_SERVICE_CLASS
EEKBOARD_SERVICE_GET_CLASS
</SECTION>
<SECTION>
<FILE>eekboard-context</FILE>
<TITLE>EekboardContext</TITLE>
EekboardContext
EekboardContextClass
eekboard_context_new
eekboard_context_add_keyboard
eekboard_context_remove_keyboard
eekboard_context_set_keyboard
eekboard_context_show_keyboard
eekboard_context_hide_keyboard
eekboard_context_set_group
eekboard_context_get_group
eekboard_context_press_keycode
eekboard_context_release_keycode
eekboard_context_is_keyboard_visible
eekboard_context_set_enabled
eekboard_context_is_enabled
eekboard_context_set_fullscreen
EekboardContextPrivate
<SUBSECTION Standard>
EEKBOARD_CONTEXT
EEKBOARD_IS_CONTEXT
EEKBOARD_TYPE_CONTEXT
eekboard_context_get_type
EEKBOARD_CONTEXT_CLASS
EEKBOARD_IS_CONTEXT_CLASS
EEKBOARD_CONTEXT_GET_CLASS
</SECTION>
<SECTION>
<FILE>eekboard-context-service</FILE>
<TITLE>EekboardContextService</TITLE>
EEKBOARD_CONTEXT_SERVICE_PATH
EEKBOARD_CONTEXT_SERVICE_INTERFACE
EekboardContextService
EekboardContextServiceClass
eekboard_context_service_enable
eekboard_context_service_disable
eekboard_context_service_get_keyboard
eekboard_context_service_get_fullscreen
eekboard_context_service_get_client_name
EekboardContextServicePrivate
<SUBSECTION Standard>
EEKBOARD_CONTEXT_SERVICE
EEKBOARD_IS_CONTEXT_SERVICE
EEKBOARD_TYPE_CONTEXT_SERVICE
eekboard_context_service_get_type
EEKBOARD_CONTEXT_SERVICE_CLASS
EEKBOARD_IS_CONTEXT_SERVICE_CLASS
EEKBOARD_CONTEXT_SERVICE_GET_CLASS
</SECTION>
<SECTION>
<FILE>eekboard-xklutil</FILE>
eekboard_xkl_config_rec_from_string
eekboard_xkl_config_rec_to_string
eekboard_xkl_list_models
eekboard_xkl_list_layouts
eekboard_xkl_list_option_groups
eekboard_xkl_list_layout_variants
eekboard_xkl_list_options
</SECTION>

View File

@ -0,0 +1,4 @@
eekboard_client_get_type
eekboard_context_get_type
eekboard_context_service_get_type
eekboard_service_get_type

View File

@ -34,12 +34,10 @@
#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"
#include "eekboard/eekboard-context-service.h"
#include "src/layout.h"
enum { enum {
PROP_0, PROP_0,
PROP_LAST PROP_LAST
@ -55,15 +53,24 @@ 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;
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,
EekGtkKeyboard *self);
static void on_button_released (struct squeek_button *button,
struct squeek_view *view,
EekGtkKeyboard *self);
static void render_pressed_button (GtkWidget *widget, struct button_place *place); static void render_pressed_button (GtkWidget *widget, struct button_place *place);
static void render_locked_button (GtkWidget *widget,
struct button_place *place);
static void render_released_button (GtkWidget *widget, 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)
@ -74,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);
} }
@ -92,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,
@ -101,10 +107,32 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
gtk_widget_get_scale_factor (self)); gtk_widget_get_scale_factor (self));
} }
// render the keyboard without any key activity (TODO: from a cached buffer)
eek_renderer_render_keyboard (priv->renderer, cr); eek_renderer_render_keyboard (priv->renderer, cr);
// render only a few remaining changes
squeek_layout_draw_all_changed(priv->keyboard->layout, EEK_GTK_KEYBOARD(self)); struct squeek_view *view = priv->keyboard->views[priv->keyboard->level];
/* redraw pressed key */
const GList *list = priv->keyboard->pressed_buttons;
for (const GList *head = list; head; head = g_list_next (head)) {
struct button_place place = squeek_view_find_key(
view, squeek_button_get_key(head->data)
);
if (place.button)
render_pressed_button (self, &place);
}
/* redraw locked key */
list = priv->keyboard->locked_buttons;
for (const GList *head = list; head; head = g_list_next (head)) {
struct button_place place = squeek_view_find_key(
view, squeek_button_get_key(
((EekModifierKey *)head->data)->button
)
);
if (place.button)
render_locked_button (self, &place);
}
return FALSE; return FALSE;
} }
@ -128,24 +156,62 @@ static void depress(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_button *button = eek_renderer_find_button_by_position (priv->renderer, view, x, y);
squeek_layout_depress(priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard, if (button) {
x, y, eek_renderer_get_transformation(priv->renderer), time, self); eek_keyboard_press_button(priv->keyboard, button, time);
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);
squeek_layout_drag(priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard, struct squeek_view *view = level_keyboard_current(priv->keyboard);
x, y, eek_renderer_get_transformation(priv->renderer), time, self); struct squeek_button *button = eek_renderer_find_button_by_position (priv->renderer, view, x, y);
GList *list, *head;
list = g_list_copy(priv->keyboard->pressed_buttons);
if (button) {
gboolean found = FALSE;
for (head = list; head; head = g_list_next (head)) {
if (head->data == button) {
found = TRUE;
} else {
eek_keyboard_release_button(priv->keyboard, head->data, time);
on_button_released(button, view, self);
}
}
g_list_free (list);
if (!found) {
eek_keyboard_press_button(priv->keyboard, button, time);
on_button_pressed(button, view, self);
}
} else {
for (head = list; head; head = g_list_next (head)) {
eek_keyboard_release_button(priv->keyboard, head->data, time);
on_button_released(head->data, view, self);
}
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);
squeek_layout_release(priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard, time, self); struct squeek_view *view = level_keyboard_current(priv->keyboard);
GList *list = g_list_copy(priv->keyboard->pressed_buttons);
for (GList *head = list; head; head = g_list_next (head)) {
struct squeek_button *button = head->data;
eek_keyboard_release_button(priv->keyboard, button, time);
on_button_released(button, view, self);
}
g_list_free (list);
} }
static gboolean static gboolean
@ -188,28 +254,28 @@ 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
touches have already been released. */
if (event->sequence == priv->sequence) {
release(self, event->time); release(self, event->time);
priv->sequence = NULL; priv->sequence = NULL;
} }
}
return TRUE; return TRUE;
} }
@ -220,14 +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) {
squeek_layout_release_all_only( GList *list, *head;
priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard,
gdk_event_get_time(NULL)); /* Make a copy of HEAD before sending "released" signal on
elements, so that the default handler of
EekKeyboard::key-released signal can remove elements from its
internal copy */
list = g_list_copy(priv->keyboard->pressed_buttons);
for (head = list; head; head = g_list_next (head)) {
g_log("squeek", G_LOG_LEVEL_DEBUG, "emit EekKey released");
g_signal_emit_by_name (head->data, "released");
}
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,
@ -250,13 +351,18 @@ 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) {
squeek_layout_release_all_only( GList *list, *head;
priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard,
gdk_event_get_time(NULL)); list = g_list_copy(priv->keyboard->pressed_buttons);
for (head = list; head; head = g_list_next (head)) {
g_log("squeek", G_LOG_LEVEL_DEBUG, "emit EekKey pressed");
g_signal_emit_by_name (head->data, "released", level_keyboard_current(priv->keyboard));
}
g_list_free (list);
priv->keyboard = NULL; priv->keyboard = NULL;
} }
@ -279,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;
@ -287,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:
@ -326,27 +449,27 @@ render_pressed_button (GtkWidget *widget,
cairo_region_destroy (region); cairo_region_destroy (region);
} }
void static void
eek_gtk_render_locked_button (EekGtkKeyboard *self, struct button_place place) render_locked_button (GtkWidget *widget, struct button_place *place)
{ {
EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget);
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
GdkWindow *window = gtk_widget_get_window (GTK_WIDGET(self)); GdkWindow *window = gtk_widget_get_window (widget);
cairo_region_t *region = gdk_window_get_clip_region (window); cairo_region_t *region = gdk_window_get_clip_region (window);
GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region); GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region);
cairo_t *cr = gdk_drawing_context_get_cairo_context (context); cairo_t *cr = gdk_drawing_context_get_cairo_context (context);
eek_renderer_render_button (priv->renderer, cr, &place, 1.0, TRUE); eek_renderer_render_button (priv->renderer, cr, place, 1.0, TRUE);
gdk_window_end_draw_frame (window, context); gdk_window_end_draw_frame (window, context);
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);
@ -364,8 +487,9 @@ render_released_button (GtkWidget *widget,
cairo_region_destroy (region); cairo_region_destroy (region);
} }
void static void
eek_gtk_on_button_pressed (struct button_place place, on_button_pressed (struct squeek_button *button,
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);
@ -374,6 +498,10 @@ eek_gtk_on_button_pressed (struct button_place place,
if (!priv->renderer) if (!priv->renderer)
return; return;
struct button_place place = {
.button = button,
.row = squeek_view_get_row(view, button),
};
if (!place.row) { if (!place.row) {
return; return;
} }
@ -389,8 +517,8 @@ eek_gtk_on_button_pressed (struct button_place place,
#endif #endif
} }
void static void
eek_gtk_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)
{ {

View File

@ -28,7 +28,7 @@
#include <glib.h> #include <glib.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
typedef struct _LevelKeyboard LevelKeyboard; // including causes weird bugs #include "eek-keyboard.h"
G_BEGIN_DECLS G_BEGIN_DECLS
#define EEK_TYPE_GTK_KEYBOARD (eek_gtk_keyboard_get_type()) #define EEK_TYPE_GTK_KEYBOARD (eek_gtk_keyboard_get_type())

26
eek/eek-gtk.h Normal file
View File

@ -0,0 +1,26 @@
/*
* 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
*/
#ifndef EEK_GTK_H
#define EEK_GTK_H 1
#include "eek.h"
#include "eek-gtk-keyboard.h"
#endif /* EEK_GTK_H */

217
eek/eek-keyboard-drawing.c Normal file
View 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);
}

View File

@ -31,15 +31,143 @@
#include <glib/gprintf.h> #include <glib/gprintf.h>
#include "eek-enumtypes.h" #include "eek-enumtypes.h"
#include "eekboard/eekboard-context-service.h"
#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"
EekModifierKey *
eek_modifier_key_copy (EekModifierKey *modkey)
{
return g_slice_dup (EekModifierKey, modkey);
}
void
eek_modifier_key_free (EekModifierKey *modkey)
{
g_slice_free (EekModifierKey, modkey);
}
/// Updates the state of locked keys based on the key that was activated
/// FIXME: make independent of what the key are named,
/// and instead refer to the contained symbols
static guint
set_key_states (LevelKeyboard *keyboard,
struct squeek_button *button,
guint new_level)
{
struct squeek_key *key = squeek_button_get_key(button);
// Keys locking rules hardcoded for the time being...
const gchar *name = squeek_symbol_get_name(squeek_key_get_symbol(key));
// Lock the shift whenever it's pressed on the baselevel
// TODO: need to lock shift on the destination level
if (g_strcmp0(name, "Shift_L") == 0 && keyboard->level == 0) {
EekModifierKey *modifier_key = g_slice_new (EekModifierKey);
modifier_key->modifiers = 0;
modifier_key->button = button;
keyboard->locked_buttons =
g_list_prepend (keyboard->locked_buttons, modifier_key);
squeek_key_set_locked(key, true);
}
if (keyboard->level == 1) {
// Only shift is locked in this state, unlock on any key press
for (GList *head = keyboard->locked_buttons; head; ) {
EekModifierKey *modifier_key = head->data;
GList *next = g_list_next (head);
keyboard->locked_buttons =
g_list_remove_link (keyboard->locked_buttons, head);
squeek_key_set_locked(squeek_button_get_key(modifier_key->button), false);
g_list_free1 (head);
head = next;
}
return 0;
}
return new_level;
}
// FIXME: unhardcode, parse some user information as to which key triggers which view (level)
static void
set_level_from_press (LevelKeyboard *keyboard, struct squeek_button *button)
{
/* The levels are: 0 Letters, 1 Upper case letters, 2 Numbers, 3 Symbols */
guint level = keyboard->level;
/* Handle non-emitting keys */
if (button) {
const gchar *name = squeek_symbol_get_name(squeek_key_get_symbol(squeek_button_get_key(button)));
if (g_strcmp0(name, "show_numbers") == 0) {
level = 2;
} else if (g_strcmp0(name, "show_letters") == 0) {
level = 0;
} else if (g_strcmp0(name, "show_symbols") == 0) {
level = 3;
} else if (g_strcmp0(name, "Shift_L") == 0) {
level ^= 1;
}
}
keyboard->level = set_key_states(keyboard, button, level);
eek_layout_update_layout(keyboard);
}
void eek_keyboard_press_button(LevelKeyboard *keyboard, struct squeek_button *button, guint32 timestamp) {
struct squeek_key *key = squeek_button_get_key(button);
squeek_key_set_pressed(key, TRUE);
keyboard->pressed_buttons = g_list_prepend (keyboard->pressed_buttons, button);
struct squeek_symbol *symbol = squeek_key_get_symbol(key);
if (!symbol)
return;
// Only take action about setting level *after* the key has taken effect, i.e. on release
//set_level_from_press (keyboard, key);
// "Borrowed" from eek-context-service; doesn't influence the state but forwards the event
guint keycode = squeek_key_get_keycode (key);
emit_key_activated(keyboard->manager, keyboard, keycode, TRUE, timestamp);
}
void eek_keyboard_release_button(LevelKeyboard *keyboard,
struct squeek_button *button,
guint32 timestamp) {
for (GList *head = keyboard->pressed_buttons; head; head = g_list_next (head)) {
if (head->data == button) {
keyboard->pressed_buttons = g_list_remove_link (keyboard->pressed_buttons, head);
g_list_free1 (head);
break;
}
}
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
guint keycode = squeek_key_get_keycode (squeek_button_get_key(button));
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) {
@ -47,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];
} }

View File

@ -33,12 +33,27 @@
G_BEGIN_DECLS G_BEGIN_DECLS
struct _EekModifierKey {
/*< public >*/
EekModifierType modifiers;
struct squeek_button *button;
};
typedef struct _EekModifierKey EekModifierKey;
/// Keyboard state holder /// Keyboard state holder
struct _LevelKeyboard { struct _LevelKeyboard {
struct squeek_layout *layout; // owned 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_buttons; // struct squeek_button*
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
@ -46,11 +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
struct button_place {
const struct squeek_row *row;
const struct squeek_button *button;
};
EekOutline *level_keyboard_get_outline
(LevelKeyboard *keyboard,
guint oref);
EekModifierKey *eek_modifier_key_copy
(EekModifierKey *modkey);
void eek_modifier_key_free
(EekModifierKey *modkey);
void eek_keyboard_press_button(LevelKeyboard *keyboard, struct squeek_button *button, guint32 timestamp);
void eek_keyboard_release_button(LevelKeyboard *keyboard, struct squeek_button *button, guint32 timestamp);
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
View 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
View 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 */

View File

@ -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);
}

View File

@ -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 */

View File

@ -24,12 +24,14 @@
#include <string.h> #include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h> #include <gdk-pixbuf/gdk-pixbuf.h>
#include "eek-keyboard.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
}; };
@ -38,9 +40,11 @@ typedef struct _EekRendererPrivate
LevelKeyboard *keyboard; LevelKeyboard *keyboard;
PangoContext *pcontext; PangoContext *pcontext;
GtkCssProvider *css_provider; GtkCssProvider *css_provider;
GtkStyleContext *view_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;
@ -52,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;
@ -62,15 +65,23 @@ 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);
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, EekBounds view_bounds, 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;
@ -100,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, squeek_view_get_bounds(data->view), &place, FALSE, FALSE); render_button (data->renderer, data->cr, &place, FALSE);
cairo_restore (data->cr); cairo_restore (data->cr);
} }
@ -120,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);
} }
@ -131,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 (priv->view_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));
@ -142,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->view_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->view_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);
@ -171,45 +183,60 @@ render_keyboard_surface (EekRenderer *renderer, struct squeek_view *view)
} }
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)
{ {
GtkBorder margin, border; EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
gtk_style_context_get_margin(ctx, GTK_STATE_FLAG_NORMAL, &margin); EekOutline *outline;
gtk_style_context_get_border(ctx, GTK_STATE_FLAG_NORMAL, &border);
gdouble x = margin.left + border.left; guint oref = squeek_button_get_oref(button);
gdouble y = margin.top + border.top; outline = level_keyboard_get_outline (priv->keyboard, oref);
EekBounds position = { if (outline == NULL)
.x = x, return;
.y = y,
.width = bounds.width - x - (margin.right + border.right), EekBounds bounds = squeek_button_get_bounds(button);
.height = bounds.height - y - (margin.bottom + border.bottom), gtk_style_context_set_state(priv->key_context,
}; active ? GTK_STATE_FLAG_ACTIVE : GTK_STATE_FLAG_NORMAL);
gtk_render_background (ctx, cr,
position.x, position.y, position.width, position.height); gtk_render_background (priv->key_context,
gtk_render_frame (ctx, cr, cr, 0, 0, bounds.width, bounds.height);
position.x, position.y, position.width, position.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
gdouble scale, render_button (EekRenderer *self,
gint scale_factor,
cairo_t *cr, cairo_t *cr,
GtkStyleContext *ctx,
EekBounds view_bounds,
struct button_place *place, struct button_place *place,
gboolean active) { gboolean active)
cairo_surface_t *outline_surface = NULL; {
EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
EekOutline *outline;
cairo_surface_t *outline_surface;
GHashTable *outline_surface_cache;
PangoLayout *layout; PangoLayout *layout;
PangoRectangle extents = { 0, }; PangoRectangle extents = { 0, };
EekColor foreground; EekColor foreground;
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);
{ if (active)
outline_surface_cache = priv->active_outline_surface_cache;
else
outline_surface_cache = priv->outline_surface_cache;
outline_surface = g_hash_table_lookup (outline_surface_cache, outline);
if (!outline_surface) {
cairo_t *cr; cairo_t *cr;
// Outline will be drawn on the outside of the button, so the // Outline will be drawn on the outside of the button, so the
@ -225,31 +252,41 @@ static void render_button_in_context(EekRenderer *self,
cairo_paint (cr); cairo_paint (cr);
cairo_save (cr); cairo_save (cr);
eek_renderer_apply_transformation_for_button (cr, view_bounds, 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,
outline,
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_surface_destroy(outline_surface);
cairo_paint (cr); cairo_paint (cr);
eek_renderer_get_foreground_color (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;
cairo_surface_t *icon_surface = cairo_surface_t *icon_surface =
eek_renderer_get_icon_surface (icon_name, 16, scale_factor); eek_renderer_get_icon_surface (self,
squeek_symbol_get_icon_name (symbol),
16 / priv->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);
gint height = cairo_image_surface_get_height (icon_surface); gint height = cairo_image_surface_get_height (icon_surface);
cairo_save (cr); cairo_save (cr);
cairo_translate (cr, cairo_translate (cr,
(bounds.width - (double)width / scale_factor) / 2, (bounds.width - (double)width / scale) / 2,
(bounds.height - (double)height / scale_factor) / 2); (bounds.height - (double)height / scale) / 2);
cairo_rectangle (cr, 0, 0, width, height); cairo_rectangle (cr, 0, 0, width, height);
cairo_clip (cr); cairo_clip (cr);
/* Draw the shape of the icon using the foreground color */ /* Draw the shape of the icon using the foreground color */
@ -258,12 +295,13 @@ static void render_button_in_context(EekRenderer *self,
foreground.blue, foreground.blue,
foreground.alpha); foreground.alpha);
cairo_mask_surface (cr, icon_surface, 0.0, 0.0); cairo_mask_surface (cr, icon_surface, 0.0, 0.0);
cairo_surface_destroy(icon_surface);
cairo_fill (cr); cairo_fill (cr);
cairo_restore (cr); cairo_restore (cr);
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);
@ -280,51 +318,12 @@ 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,
EekBounds view_bounds,
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, priv->scale, priv->scale_factor, cr, ctx, view_bounds, 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");
}
}
/** /**
* eek_renderer_apply_transformation_for_key: * eek_renderer_apply_transformation_for_key:
* @self: The renderer used to render the key * @self: The renderer used to render the key
@ -341,8 +340,8 @@ render_button (EekRenderer *self,
* normal keys for popups. * normal keys for popups.
*/ */
void void
eek_renderer_apply_transformation_for_button (cairo_t *cr, eek_renderer_apply_transformation_for_button (EekRenderer *self,
EekBounds view_bounds, cairo_t *cr,
struct button_place *place, struct button_place *place,
gdouble scale, gdouble scale,
gboolean rotate) gboolean rotate)
@ -350,8 +349,8 @@ eek_renderer_apply_transformation_for_button (cairo_t *cr,
EekBounds bounds, rotated_bounds; EekBounds bounds, rotated_bounds;
gdouble s; gdouble s;
eek_renderer_get_button_bounds (view_bounds, place, &bounds, FALSE); eek_renderer_get_button_bounds (self, place, &bounds, FALSE);
eek_renderer_get_button_bounds (view_bounds, place, &rotated_bounds, TRUE); eek_renderer_get_button_bounds (self, place, &rotated_bounds, TRUE);
gint angle = squeek_row_get_angle (place->row); gint angle = squeek_row_get_angle (place->row);
@ -373,15 +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;
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;
@ -411,10 +413,9 @@ eek_renderer_real_render_button_label (EekRenderer *self,
pango_font_description_free (font); pango_font_description_free (font);
pango_layout_set_text (layout, label, -1); pango_layout_set_text (layout, label, -1);
PangoLayoutLine *line = pango_layout_get_line_readonly(layout, 0); line = pango_layout_get_line (layout, 0);
if (line->resolved_dir == PANGO_DIRECTION_RTL) { if (line->resolved_dir == PANGO_DIRECTION_RTL)
pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
}
pango_layout_set_width (layout, pango_layout_set_width (layout,
PANGO_SCALE * bounds.width * scale); PANGO_SCALE * bounds.width * scale);
} }
@ -440,8 +441,7 @@ eek_renderer_real_render_button (EekRenderer *self,
EekRendererPrivate *priv = eek_renderer_get_instance_private (self); EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
EekBounds bounds; EekBounds bounds;
EekBounds view_bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard)); eek_renderer_get_button_bounds (self, place, &bounds, rotate);
eek_renderer_get_button_bounds (view_bounds, place, &bounds, rotate);
cairo_save (cr); cairo_save (cr);
/* Because this function is called separately from the keyboard rendering /* Because this function is called separately from the keyboard rendering
@ -450,12 +450,11 @@ eek_renderer_real_render_button (EekRenderer *self,
cairo_scale (cr, priv->scale, priv->scale); cairo_scale (cr, priv->scale, priv->scale);
cairo_translate (cr, bounds.x, bounds.y); cairo_translate (cr, bounds.x, bounds.y);
eek_renderer_apply_transformation_for_button (cr, view_bounds, place, scale, rotate); eek_renderer_apply_transformation_for_button (self, cr, place, scale, rotate);
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, view_bounds, place, self, cr, place,
squeek_key_is_pressed(key) != 0, squeek_key_is_pressed(key) || squeek_key_is_locked (key)
squeek_key_is_locked (key) != 0
); );
cairo_restore (cr); cairo_restore (cr);
} }
@ -482,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);
@ -506,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;
@ -582,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 view_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
@ -618,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;
@ -648,6 +635,19 @@ eek_renderer_init (EekRenderer *self)
priv->css_provider = gtk_css_provider_new (); priv->css_provider = gtk_css_provider_new ();
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 keys */
priv->key_context = gtk_style_context_new ();
gtk_style_context_add_class (priv->key_context, "key");
gtk_style_context_add_provider (priv->key_context,
GTK_STYLE_PROVIDER(priv->css_provider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
g_autoptr (GtkWidgetPath) path = NULL;
path = gtk_widget_path_new ();
gtk_widget_path_append_type (path, GTK_TYPE_BUTTON);
gtk_style_context_set_path (priv->key_context, path);
gtk_style_context_set_state (priv->key_context, GTK_STATE_FLAG_NORMAL);
} }
static void static void
@ -669,44 +669,15 @@ 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;
/* Create a style context for the layout */
GtkWidgetPath *path = gtk_widget_path_new();
gtk_widget_path_append_type(path, view_type());
priv->view_context = gtk_style_context_new();
gtk_style_context_set_path(priv->view_context, path);
gtk_widget_path_unref(path);
if (squeek_layout_get_kind(priv->keyboard->layout) == ARRANGEMENT_KIND_WIDE) {
gtk_style_context_add_class(priv->view_context, "wide");
}
gtk_style_context_add_provider (priv->view_context,
GTK_STYLE_PROVIDER(priv->css_provider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
printf("view: %s\n", gtk_style_context_to_string(priv->view_context, GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE));
/* Create a style context for the buttons */
path = gtk_widget_path_new();
gtk_widget_path_append_type(path, view_type());
if (squeek_layout_get_kind(priv->keyboard->layout) == ARRANGEMENT_KIND_WIDE) {
gtk_widget_path_iter_add_class(path, -1, "wide");
}
gtk_widget_path_append_type(path, button_type());
priv->button_context = gtk_style_context_new ();
gtk_style_context_set_path(priv->button_context, path);
gtk_widget_path_unref(path);
gtk_style_context_set_parent(priv->button_context, priv->view_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);
return renderer; return renderer;
} }
@ -758,7 +729,7 @@ eek_renderer_get_size (EekRenderer *renderer,
} }
void void
eek_renderer_get_button_bounds (EekBounds view_bounds, eek_renderer_get_button_bounds (EekRenderer *renderer,
struct button_place *place, struct button_place *place,
EekBounds *bounds, EekBounds *bounds,
gboolean rotate) gboolean rotate)
@ -766,11 +737,15 @@ eek_renderer_get_button_bounds (EekBounds view_bounds,
gint angle = 0; gint angle = 0;
EekPoint points[4], min, max; EekPoint points[4], min, max;
g_return_if_fail (EEK_IS_RENDERER(renderer));
g_return_if_fail (place); g_return_if_fail (place);
g_return_if_fail (bounds != NULL); g_return_if_fail (bounds != NULL);
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
EekBounds button_bounds = squeek_button_get_bounds(place->button); EekBounds button_bounds = squeek_button_get_bounds(place->button);
EekBounds row_bounds = squeek_row_get_bounds (place->row); EekBounds row_bounds = squeek_row_get_bounds (place->row);
EekBounds view_bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard));
if (!rotate) { if (!rotate) {
button_bounds.x += view_bounds.x + row_bounds.x; button_bounds.x += view_bounds.x + row_bounds.x;
@ -793,7 +768,7 @@ eek_renderer_get_button_bounds (EekBounds view_bounds,
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;
@ -840,19 +815,28 @@ eek_renderer_create_pango_layout (EekRenderer *renderer)
} }
cairo_surface_t * cairo_surface_t *
eek_renderer_get_icon_surface (const gchar *icon_name, eek_renderer_get_icon_surface (EekRenderer *renderer,
const gchar *icon_name,
gint size, gint size,
gint scale) gint scale)
{ {
GError *error = NULL; GError *error = NULL;
cairo_surface_t *surface = gtk_icon_theme_load_surface (gtk_icon_theme_get_default (), cairo_surface_t *surface;
g_return_val_if_fail (EEK_IS_RENDERER(renderer), NULL);
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
surface = g_hash_table_lookup (priv->icons, icon_name);
if (!surface) {
surface = gtk_icon_theme_load_surface (gtk_icon_theme_get_default (),
icon_name, icon_name,
size, size,
scale, scale,
NULL, NULL,
0, 0,
&error); &error);
g_hash_table_insert (priv->icons, g_strdup(icon_name), surface);
if (surface == NULL) { if (surface == NULL) {
g_warning ("can't get icon surface for %s: %s", g_warning ("can't get icon surface for %s: %s",
icon_name, icon_name,
@ -860,6 +844,7 @@ eek_renderer_get_icon_surface (const gchar *icon_name,
g_error_free (error); g_error_free (error);
return NULL; return NULL;
} }
}
return surface; return surface;
} }
@ -887,9 +872,35 @@ eek_renderer_render_keyboard (EekRenderer *renderer,
} }
void void
eek_renderer_get_foreground_color (GtkStyleContext *context, 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
eek_renderer_get_foreground_color (EekRenderer *renderer,
GtkStyleContext *context,
EekColor *color) EekColor *color)
{ {
g_return_if_fail (EEK_IS_RENDERER(renderer));
g_return_if_fail (color); g_return_if_fail (color);
GtkStateFlags flags = GTK_STATE_FLAG_NORMAL; GtkStateFlags flags = GTK_STATE_FLAG_NORMAL;
@ -925,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;
@ -949,16 +960,28 @@ eek_are_bounds_inside (EekBounds bounds, EekPoint point, EekPoint origin, int32_
return 0; return 0;
} }
struct transformation /**
eek_renderer_get_transformation (EekRenderer *renderer) { * eek_renderer_find_key_by_position:
struct transformation failed = {0}; * @renderer: The renderer normally used to render the key
g_return_val_if_fail (EEK_IS_RENDERER(renderer), failed); * @x: The horizontal widget coordinate of the position to test for a key
* @y: The vertical widget coordinate of the position to test for a key
*
* Return value: the key located at the position x, y in widget coordinates, or
* NULL if no key can be found at that location
**/
struct squeek_button *
eek_renderer_find_button_by_position (EekRenderer *renderer,
struct squeek_view *view,
gdouble x,
gdouble y)
{
g_return_val_if_fail (EEK_IS_RENDERER(renderer), NULL);
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer); EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
struct transformation ret = {
.origin_x = priv->origin_x, EekPoint point = {
.origin_y = priv->origin_y, .x = (x - priv->origin_x)/priv->scale,
.scale = priv->scale, .y = (y - priv->origin_y)/priv->scale,
}; };
return ret; return squeek_view_find_button_by_position(view, point);
} }

View File

@ -24,8 +24,8 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <pango/pangocairo.h> #include <pango/pangocairo.h>
#include "eek-keyboard.h"
#include "eek-types.h" #include "eek-types.h"
#include "src/layout.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -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,
@ -65,7 +66,7 @@ void eek_renderer_set_allocation_size
void eek_renderer_get_size (EekRenderer *renderer, void eek_renderer_get_size (EekRenderer *renderer,
gdouble *width, gdouble *width,
gdouble *height); gdouble *height);
void eek_renderer_get_button_bounds (EekBounds view_bounds, void eek_renderer_get_button_bounds (EekRenderer *renderer,
struct button_place *button, struct button_place *button,
EekBounds *bounds, EekBounds *bounds,
gboolean rotate); gboolean rotate);
@ -82,7 +83,8 @@ void eek_renderer_render_button (EekRenderer *renderer,
gdouble scale, gdouble scale,
gboolean rotate); gboolean rotate);
cairo_surface_t *eek_renderer_get_icon_surface(const gchar *icon_name, cairo_surface_t *eek_renderer_get_icon_surface (EekRenderer *renderer,
const gchar *icon_name,
gint size, gint size,
gint scale); gint scale);
@ -96,19 +98,19 @@ void eek_renderer_set_default_background_color
(EekRenderer *renderer, (EekRenderer *renderer,
const EekColor *color); const EekColor *color);
void eek_renderer_get_foreground_color void eek_renderer_get_foreground_color
(GtkStyleContext *context, (EekRenderer *renderer,
GtkStyleContext *context,
EekColor *color); EekColor *color);
void eek_renderer_set_border_width (EekRenderer *renderer, void eek_renderer_set_border_width (EekRenderer *renderer,
gdouble border_width); gdouble border_width);
struct squeek_button *eek_renderer_find_button_by_position(EekRenderer *renderer, struct squeek_view *view,
gdouble x,
gdouble y);
void eek_renderer_apply_transformation_for_button void eek_renderer_apply_transformation_for_button
(cairo_t *cr, (EekRenderer *renderer,
EekBounds view_bounds, cairo_t *cr, struct button_place *place,
struct button_place *place,
gdouble scale, gdouble scale,
gboolean rotate); gboolean rotate);
struct transformation
eek_renderer_get_transformation (EekRenderer *renderer);
G_END_DECLS G_END_DECLS
#endif /* EEK_RENDERER_H */ #endif /* EEK_RENDERER_H */

56
eek/eek-section.c Normal file
View 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
View 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 */

113
eek/eek-symbol.c Normal file
View File

@ -0,0 +1,113 @@
/*
* Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 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-symbol
* @short_description: Base class of a symbol
*
* The #EekSymbolClass class represents a symbol assigned to a key.
*/
#include "config.h"
#include "eek-symbol.h"
#include "eek-enumtypes.h"
EekSymbol *
eek_symbol_new (const gchar *name)
{
EekSymbol *self = g_new0(EekSymbol, 1);
self->name = g_strdup (name);
self->category = EEK_SYMBOL_CATEGORY_UNKNOWN;
return self;
}
/**
* eek_symbol_set_label:
* @symbol: an #EekSymbol
* @label: label text of @symbol
*
* Set the label text of @symbol to @label.
*/
void
eek_symbol_set_label (EekSymbol *symbol,
const gchar *label)
{
g_free (symbol->label);
symbol->label = g_strdup (label);
}
/**
* eek_symbol_set_modifier_mask:
* @symbol: an #EekSymbol
* @mask: an #EekModifierType
*
* Set modifier mask that @symbol can trigger.
*/
void
eek_symbol_set_modifier_mask (EekSymbol *symbol,
EekModifierType mask)
{
symbol->modifier_mask = mask;
}
/**
* eek_symbol_get_modifier_mask:
* @symbol: an #EekSymbol
*
* Get modifier mask that @symbol can trigger.
*/
EekModifierType
eek_symbol_get_modifier_mask (EekSymbol *symbol)
{
return 0;
return symbol->modifier_mask;
}
void
eek_symbol_set_icon_name (EekSymbol *symbol,
const gchar *icon_name)
{
g_free (symbol->icon_name);
symbol->icon_name = g_strdup (icon_name);
}
const gchar *
eek_symbol_get_icon_name (EekSymbol *symbol)
{
return NULL;
}
void
eek_symbol_set_tooltip (EekSymbol *symbol,
const gchar *tooltip)
{
g_free (symbol->tooltip);
symbol->tooltip = g_strdup (tooltip);
}
const gchar *
eek_symbol_get_tooltip (EekSymbol *symbol)
{
return NULL;
if (symbol->tooltip == NULL || *symbol->tooltip == '\0')
return NULL;
return symbol->tooltip;
}

View File

@ -73,6 +73,28 @@ eek_bounds_free (EekBounds *bounds)
g_slice_free (EekBounds, bounds); g_slice_free (EekBounds, bounds);
} }
/* EekOutline */
G_DEFINE_BOXED_TYPE(EekOutline, eek_outline,
eek_outline_copy, eek_outline_free);
EekOutline *
eek_outline_copy (const EekOutline *outline)
{
EekOutline *_outline = g_slice_dup (EekOutline, outline);
_outline->corner_radius = outline->corner_radius;
_outline->num_points = outline->num_points;
_outline->points = g_slice_alloc0 (sizeof (EekPoint) * outline->num_points);
memcpy (_outline->points, outline->points, sizeof (EekPoint) * outline->num_points);
return _outline;
}
void
eek_outline_free (EekOutline *outline)
{
g_slice_free1 (sizeof (EekPoint) * outline->num_points, outline->points);
g_slice_free (EekOutline, outline);
}
/* EekColor */ /* EekColor */
G_DEFINE_BOXED_TYPE(EekColor, eek_color, eek_color_copy, eek_color_free); G_DEFINE_BOXED_TYPE(EekColor, eek_color, eek_color_copy, eek_color_free);
@ -104,3 +126,9 @@ eek_color_new (gdouble red,
return color; return color;
} }
GQuark
eek_error_quark (void)
{
return g_quark_from_static_string ("eek-error-quark");
}

View File

@ -1,7 +1,6 @@
/* /*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org> * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc. * Copyright (C) 2010-2011 Red Hat, Inc.
* Copyright (C) 2019 Purism, SPC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License * modify it under the terms of the GNU Lesser General Public License
@ -34,9 +33,116 @@ G_BEGIN_DECLS
#define EEK_TYPE_POINT (eek_point_get_type ()) #define EEK_TYPE_POINT (eek_point_get_type ())
#define EEK_TYPE_BOUNDS (eek_bounds_get_type ()) #define EEK_TYPE_BOUNDS (eek_bounds_get_type ())
#define EEK_TYPE_OUTLINE (eek_outline_get_type ())
#define EEK_TYPE_COLOR (eek_color_get_type ()) #define EEK_TYPE_COLOR (eek_color_get_type ())
/**
* EekOrientation:
* @EEK_ORIENTATION_VERTICAL: the elements will be arranged vertically
* @EEK_ORIENTATION_HORIZONTAL: the elements will be arranged horizontally
* @EEK_ORIENTATION_INVALID: used for error reporting
*
* Orientation of rows in sections. Elements in a row will be
* arranged with the specified orientation.
*/
typedef enum {
EEK_ORIENTATION_VERTICAL,
EEK_ORIENTATION_HORIZONTAL,
EEK_ORIENTATION_INVALID = -1
} EekOrientation;
/**
* EekModifierBehavior:
* @EEK_MODIFIER_BEHAVIOR_NONE: do nothing when a modifier key is pressed
* @EEK_MODIFIER_BEHAVIOR_LOCK: toggle the modifier status each time a
* modifier key are pressed
* @EEK_MODIFIER_BEHAVIOR_LATCH: enable the modifier when a modifier
* key is pressed and keep it enabled until any key is pressed.
*
* Modifier handling mode.
*/
typedef enum {
EEK_MODIFIER_BEHAVIOR_NONE,
EEK_MODIFIER_BEHAVIOR_LOCK,
EEK_MODIFIER_BEHAVIOR_LATCH
} EekModifierBehavior;
/**
* EekModifierType:
* @EEK_SHIFT_MASK: the Shift key.
* @EEK_LOCK_MASK: a Lock key (depending on the modifier mapping of the
* X server this may either be CapsLock or ShiftLock).
* @EEK_CONTROL_MASK: the Control key.
* @EEK_MOD1_MASK: the fourth modifier key (it depends on the modifier
* mapping of the X server which key is interpreted as this modifier, but
* normally it is the Alt key).
* @EEK_MOD2_MASK: the fifth modifier key (it depends on the modifier
* mapping of the X server which key is interpreted as this modifier).
* @EEK_MOD3_MASK: the sixth modifier key (it depends on the modifier
* mapping of the X server which key is interpreted as this modifier).
* @EEK_MOD4_MASK: the seventh modifier key (it depends on the modifier
* mapping of the X server which key is interpreted as this modifier).
* @EEK_MOD5_MASK: the eighth modifier key (it depends on the modifier
* mapping of the X server which key is interpreted as this modifier).
* @EEK_BUTTON1_MASK: the first mouse button.
* @EEK_BUTTON2_MASK: the second mouse button.
* @EEK_BUTTON3_MASK: the third mouse button.
* @EEK_BUTTON4_MASK: the fourth mouse button.
* @EEK_BUTTON5_MASK: the fifth mouse button.
* @EEK_SUPER_MASK: the Super modifier. Since 2.10
* @EEK_HYPER_MASK: the Hyper modifier. Since 2.10
* @EEK_META_MASK: the Meta modifier. Since 2.10
* @EEK_RELEASE_MASK: not used in EEK itself. GTK+ uses it to differentiate
* between (keyval, modifiers) pairs from key press and release events.
* @EEK_MODIFIER_MASK: a mask covering all modifier types.
*/
typedef enum
{
EEK_SHIFT_MASK = 1 << 0,
EEK_LOCK_MASK = 1 << 1,
EEK_CONTROL_MASK = 1 << 2,
EEK_MOD1_MASK = 1 << 3,
EEK_MOD2_MASK = 1 << 4,
EEK_MOD3_MASK = 1 << 5,
EEK_MOD4_MASK = 1 << 6,
EEK_MOD5_MASK = 1 << 7,
EEK_BUTTON1_MASK = 1 << 8,
EEK_BUTTON2_MASK = 1 << 9,
EEK_BUTTON3_MASK = 1 << 10,
EEK_BUTTON4_MASK = 1 << 11,
EEK_BUTTON5_MASK = 1 << 12,
/* The next few modifiers are used by XKB, so we skip to the end.
* Bits 15 - 25 are currently unused. Bit 29 is used internally.
*/
EEK_SUPER_MASK = 1 << 26,
EEK_HYPER_MASK = 1 << 27,
EEK_META_MASK = 1 << 28,
EEK_RELEASE_MASK = 1 << 30,
EEK_MODIFIER_MASK = 0x5c001fff
} EekModifierType;
/**
* EEK_INVALID_KEYCODE:
*
* Pseudo keycode used for error reporting.
*/
#define EEK_INVALID_KEYCODE (0)
typedef struct _EekElement EekElement;
typedef struct _EekSymbol EekSymbol;
typedef struct _EekText EekText;
typedef struct _EekTheme EekTheme;
typedef struct _EekThemeContext EekThemeContext;
typedef struct _EekThemeNode EekThemeNode;
typedef struct _EekSymbolMatrix EekSymbolMatrix;
typedef struct _EekBounds EekBounds; typedef struct _EekBounds EekBounds;
typedef struct _EekOutline EekOutline;
typedef struct _EekColor EekColor; typedef struct _EekColor EekColor;
typedef struct _EekboardContextService EekboardContextService; typedef struct _EekboardContextService EekboardContextService;
@ -85,6 +191,26 @@ GType eek_bounds_get_type (void) G_GNUC_CONST;
EekBounds *eek_bounds_copy (const EekBounds *bounds); EekBounds *eek_bounds_copy (const EekBounds *bounds);
void eek_bounds_free (EekBounds *bounds); void eek_bounds_free (EekBounds *bounds);
/**
* EekOutline:
* @corner_radius: radius of corners of rounded polygon
* @points: an array of points represents a polygon
* @num_points: the length of @points
*
* 2D rounded polygon used to draw key shape
*/
struct _EekOutline
{
/*< public >*/
gdouble corner_radius;
EekPoint *points;
guint num_points;
};
GType eek_outline_get_type (void) G_GNUC_CONST;
EekOutline *eek_outline_copy (const EekOutline *outline);
void eek_outline_free (EekOutline *outline);
/** /**
* EekColor: * EekColor:
* @red: red component of color, between 0.0 and 1.0 * @red: red component of color, between 0.0 and 1.0
@ -112,10 +238,20 @@ EekColor *eek_color_new (gdouble red,
EekColor *eek_color_copy (const EekColor *color); EekColor *eek_color_copy (const EekColor *color);
void eek_color_free (EekColor *color); void eek_color_free (EekColor *color);
struct transformation { typedef enum {
gdouble origin_x; EEK_GRADIENT_NONE,
gdouble origin_y; EEK_GRADIENT_VERTICAL,
gdouble scale; EEK_GRADIENT_HORIZONTAL,
}; EEK_GRADIENT_RADIAL
} EekGradientType;
GQuark eek_error_quark (void);
#define EEK_ERROR eek_error_quark ()
typedef enum {
EEK_ERROR_LAYOUT_ERROR,
EEK_ERROR_FAILED
} EekErrorEnum;
G_END_DECLS G_END_DECLS
#endif /* EEK_TYPES_H */ #endif /* EEK_TYPES_H */

File diff suppressed because it is too large Load Diff

View File

@ -23,14 +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 "src/layout.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);
enum squeek_arrangement_kind t);
G_END_DECLS G_END_DECLS
#endif /* EEK_XML_LAYOUT_H */ #endif /* EEK_XML_LAYOUT_H */

View File

@ -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
View 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")

View File

@ -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\
};";

View File

@ -3,12 +3,15 @@
* SPDX-License-Identifier: GPL-3.0+ * SPDX-License-Identifier: GPL-3.0+
* Author: Guido Günther <agx@sigxcpu.org> * Author: Guido Günther <agx@sigxcpu.org>
*/ */
/* /*
WARNING: this file is taken directly from phosh, with no modificaions apart from this message. Please update phosh instead of changing this file. Please copy the file back here afterwards, with the same notice. WARNING: this file is taken directly from phosh, with no modificaions apart from this message. Please update phosh instead of changing this file. Please copy the file back here afterwards, with the same notice.
*/ */
#define G_LOG_DOMAIN "phosh-layer-surface" #define G_LOG_DOMAIN "phosh-layer-surface"
#include "config.h" #include "config.h"
@ -24,14 +27,8 @@ enum {
PHOSH_LAYER_SURFACE_PROP_LAYER, PHOSH_LAYER_SURFACE_PROP_LAYER,
PHOSH_LAYER_SURFACE_PROP_KBD_INTERACTIVITY, PHOSH_LAYER_SURFACE_PROP_KBD_INTERACTIVITY,
PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE, PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE,
PHOSH_LAYER_SURFACE_PROP_MARGIN_TOP,
PHOSH_LAYER_SURFACE_PROP_MARGIN_BOTTOM,
PHOSH_LAYER_SURFACE_PROP_MARGIN_LEFT,
PHOSH_LAYER_SURFACE_PROP_MARGIN_RIGHT,
PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH, PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH,
PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT, PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT,
PHOSH_LAYER_SURFACE_PROP_CONFIGURED_WIDTH,
PHOSH_LAYER_SURFACE_PROP_CONFIGURED_HEIGHT,
PHOSH_LAYER_SURFACE_PROP_NAMESPACE, PHOSH_LAYER_SURFACE_PROP_NAMESPACE,
PHOSH_LAYER_SURFACE_PROP_LAST_PROP PHOSH_LAYER_SURFACE_PROP_LAST_PROP
}; };
@ -53,10 +50,7 @@ typedef struct {
guint layer; guint layer;
gboolean kbd_interactivity; gboolean kbd_interactivity;
gint exclusive_zone; gint exclusive_zone;
gint margin_top, margin_bottom;
gint margin_left, margin_right;
gint width, height; gint width, height;
gint configured_width, configured_height;
gchar *namespace; gchar *namespace;
struct zwlr_layer_shell_v1 *layer_shell; struct zwlr_layer_shell_v1 *layer_shell;
struct wl_output *wl_output; struct wl_output *wl_output;
@ -71,24 +65,10 @@ static void layer_surface_configure(void *data,
uint32_t height) uint32_t height)
{ {
PhoshLayerSurface *self = data; PhoshLayerSurface *self = data;
PhoshLayerSurfacePrivate *priv;
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
priv = phosh_layer_surface_get_instance_private (self);
gtk_window_resize (GTK_WINDOW (self), width, height); gtk_window_resize (GTK_WINDOW (self), width, height);
zwlr_layer_surface_v1_ack_configure(surface, serial); zwlr_layer_surface_v1_ack_configure(surface, serial);
if (priv->configured_height != height) {
priv->configured_height = height;
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_CONFIGURED_HEIGHT]);
}
if (priv->configured_width != width) {
priv->configured_width = width;
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_CONFIGURED_WIDTH]);
}
g_debug("Configured %p", self);
g_signal_emit (self, signals[CONFIGURED], 0); g_signal_emit (self, signals[CONFIGURED], 0);
} }
@ -118,7 +98,6 @@ phosh_layer_surface_set_property (GObject *object,
{ {
PhoshLayerSurface *self = PHOSH_LAYER_SURFACE (object); PhoshLayerSurface *self = PHOSH_LAYER_SURFACE (object);
PhoshLayerSurfacePrivate *priv = phosh_layer_surface_get_instance_private (self); PhoshLayerSurfacePrivate *priv = phosh_layer_surface_get_instance_private (self);
gint width, height;
switch (property_id) { switch (property_id) {
case PHOSH_LAYER_SURFACE_PROP_LAYER_SHELL: case PHOSH_LAYER_SURFACE_PROP_LAYER_SHELL:
@ -134,46 +113,16 @@ phosh_layer_surface_set_property (GObject *object,
priv->layer = g_value_get_uint (value); priv->layer = g_value_get_uint (value);
break; break;
case PHOSH_LAYER_SURFACE_PROP_KBD_INTERACTIVITY: case PHOSH_LAYER_SURFACE_PROP_KBD_INTERACTIVITY:
phosh_layer_surface_set_kbd_interactivity (self, g_value_get_boolean (value)); priv->kbd_interactivity = g_value_get_boolean (value);
break; break;
case PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE: case PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE:
phosh_layer_surface_set_exclusive_zone (self, g_value_get_int (value)); priv->exclusive_zone = g_value_get_int (value);
break;
case PHOSH_LAYER_SURFACE_PROP_MARGIN_TOP:
phosh_layer_surface_set_margins (self,
g_value_get_int (value),
priv->margin_right,
priv->margin_bottom,
priv->margin_left);
break;
case PHOSH_LAYER_SURFACE_PROP_MARGIN_BOTTOM:
phosh_layer_surface_set_margins (self,
priv->margin_top,
priv->margin_right,
g_value_get_int (value),
priv->margin_left);
break;
case PHOSH_LAYER_SURFACE_PROP_MARGIN_LEFT:
phosh_layer_surface_set_margins (self,
priv->margin_top,
priv->margin_right,
priv->margin_bottom,
g_value_get_int (value));
break;
case PHOSH_LAYER_SURFACE_PROP_MARGIN_RIGHT:
phosh_layer_surface_set_margins (self,
priv->margin_top,
g_value_get_int (value),
priv->margin_bottom,
priv->margin_left);
break; break;
case PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH: case PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH:
width = g_value_get_uint (value); priv->width = g_value_get_uint (value);
phosh_layer_surface_set_size(self, width, priv->height);
break; break;
case PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT: case PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT:
height = g_value_get_uint (value); priv->height = g_value_get_uint (value);
phosh_layer_surface_set_size(self, priv->width, height);
break; break;
case PHOSH_LAYER_SURFACE_PROP_NAMESPACE: case PHOSH_LAYER_SURFACE_PROP_NAMESPACE:
g_free (priv->namespace); g_free (priv->namespace);
@ -212,19 +161,7 @@ phosh_layer_surface_get_property (GObject *object,
g_value_set_boolean (value, priv->kbd_interactivity); g_value_set_boolean (value, priv->kbd_interactivity);
break; break;
case PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE: case PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE:
g_value_set_int (value, priv->exclusive_zone); g_value_set_boolean (value, priv->exclusive_zone);
break;
case PHOSH_LAYER_SURFACE_PROP_MARGIN_TOP:
g_value_set_int (value, priv->margin_top);
break;
case PHOSH_LAYER_SURFACE_PROP_MARGIN_BOTTOM:
g_value_set_int (value, priv->margin_bottom);
break;
case PHOSH_LAYER_SURFACE_PROP_MARGIN_LEFT:
g_value_set_int (value, priv->margin_left);
break;
case PHOSH_LAYER_SURFACE_PROP_MARGIN_RIGHT:
g_value_set_int (value, priv->margin_right);
break; break;
case PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH: case PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH:
g_value_set_uint (value, priv->width); g_value_set_uint (value, priv->width);
@ -232,12 +169,6 @@ phosh_layer_surface_get_property (GObject *object,
case PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT: case PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT:
g_value_set_uint (value, priv->height); g_value_set_uint (value, priv->height);
break; break;
case PHOSH_LAYER_SURFACE_PROP_CONFIGURED_WIDTH:
g_value_set_uint (value, priv->configured_width);
break;
case PHOSH_LAYER_SURFACE_PROP_CONFIGURED_HEIGHT:
g_value_set_uint (value, priv->configured_height);
break;
case PHOSH_LAYER_SURFACE_PROP_NAMESPACE: case PHOSH_LAYER_SURFACE_PROP_NAMESPACE:
g_value_set_string (value, priv->namespace); g_value_set_string (value, priv->namespace);
break; break;
@ -290,11 +221,6 @@ on_phosh_layer_surface_mapped (PhoshLayerSurface *self, gpointer unused)
zwlr_layer_surface_v1_set_exclusive_zone(priv->layer_surface, priv->exclusive_zone); zwlr_layer_surface_v1_set_exclusive_zone(priv->layer_surface, priv->exclusive_zone);
zwlr_layer_surface_v1_set_size(priv->layer_surface, priv->width, priv->height); zwlr_layer_surface_v1_set_size(priv->layer_surface, priv->width, priv->height);
zwlr_layer_surface_v1_set_anchor(priv->layer_surface, priv->anchor); zwlr_layer_surface_v1_set_anchor(priv->layer_surface, priv->anchor);
zwlr_layer_surface_v1_set_margin(priv->layer_surface,
priv->margin_top,
priv->margin_right,
priv->margin_bottom,
priv->margin_left);
zwlr_layer_surface_v1_set_keyboard_interactivity(priv->layer_surface, priv->kbd_interactivity); zwlr_layer_surface_v1_set_keyboard_interactivity(priv->layer_surface, priv->kbd_interactivity);
zwlr_layer_surface_v1_add_listener(priv->layer_surface, zwlr_layer_surface_v1_add_listener(priv->layer_surface,
&layer_surface_listener, &layer_surface_listener,
@ -336,8 +262,6 @@ phosh_layer_surface_constructed (GObject *object)
g_signal_connect (self, "unmap", g_signal_connect (self, "unmap",
G_CALLBACK (on_phosh_layer_surface_unmapped), G_CALLBACK (on_phosh_layer_surface_unmapped),
NULL); NULL);
G_OBJECT_CLASS (phosh_layer_surface_parent_class)->constructed (object);
} }
@ -408,7 +332,7 @@ phosh_layer_surface_class_init (PhoshLayerSurfaceClass *klass)
"Keyboard interactivity", "Keyboard interactivity",
"Whether the surface interacts with the keyboard", "Whether the surface interacts with the keyboard",
FALSE, FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
props[PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE] = props[PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE] =
g_param_spec_int ( g_param_spec_int (
@ -418,47 +342,7 @@ phosh_layer_surface_class_init (PhoshLayerSurfaceClass *klass)
-1, -1,
G_MAXINT, G_MAXINT,
0, 0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
props[PHOSH_LAYER_SURFACE_PROP_MARGIN_LEFT] =
g_param_spec_int (
"margin-left",
"Left margin",
"Distance away from the left anchor point",
G_MININT,
G_MAXINT,
0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
props[PHOSH_LAYER_SURFACE_PROP_MARGIN_RIGHT] =
g_param_spec_int (
"margin-right",
"Right margin",
"Distance away from the right anchor point",
G_MININT,
G_MAXINT,
0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
props[PHOSH_LAYER_SURFACE_PROP_MARGIN_TOP] =
g_param_spec_int (
"margin-top",
"Top margin",
"Distance away from the top anchor point",
G_MININT,
G_MAXINT,
0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
props[PHOSH_LAYER_SURFACE_PROP_MARGIN_BOTTOM] =
g_param_spec_int (
"margin-bottom",
"Bottom margin",
"Distance away from the bottom anchor point",
G_MININT,
G_MAXINT,
0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
props[PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH] = props[PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH] =
g_param_spec_uint ( g_param_spec_uint (
@ -468,7 +352,7 @@ phosh_layer_surface_class_init (PhoshLayerSurfaceClass *klass)
0, 0,
G_MAXUINT, G_MAXUINT,
0, 0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
props[PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT] = props[PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT] =
g_param_spec_uint ( g_param_spec_uint (
@ -478,28 +362,7 @@ phosh_layer_surface_class_init (PhoshLayerSurfaceClass *klass)
0, 0,
G_MAXUINT, G_MAXUINT,
0, 0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
props[PHOSH_LAYER_SURFACE_PROP_CONFIGURED_WIDTH] =
g_param_spec_uint (
"configured-width",
"Configured width",
"The width of the layer surface set by the compositor",
0,
G_MAXUINT,
0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
props[PHOSH_LAYER_SURFACE_PROP_CONFIGURED_HEIGHT] =
g_param_spec_uint (
"configured-height",
"Configured height",
"The height of the layer surface set by the compositor",
0,
G_MAXUINT,
0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
props[PHOSH_LAYER_SURFACE_PROP_NAMESPACE] = props[PHOSH_LAYER_SURFACE_PROP_NAMESPACE] =
g_param_spec_string ( g_param_spec_string (
@ -575,148 +438,3 @@ phosh_layer_surface_get_wl_surface(PhoshLayerSurface *self)
priv = phosh_layer_surface_get_instance_private (self); priv = phosh_layer_surface_get_instance_private (self);
return priv->wl_surface; return priv->wl_surface;
} }
/**
* phosh_layer_surface_set_size:
*
* Set the size of a layer surface. A value of '-1' indicates 'use old value'
*/
void
phosh_layer_surface_set_size(PhoshLayerSurface *self, gint width, gint height)
{
PhoshLayerSurfacePrivate *priv;
gint old_width, old_height;
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
priv = phosh_layer_surface_get_instance_private (self);
if (priv->height == height && priv->width == width)
return;
old_width = priv->width;
old_height = priv->height;
if (width != -1)
priv->width = width;
if (height != -1)
priv->height = height;
if (gtk_widget_get_mapped (GTK_WIDGET (self))) {
zwlr_layer_surface_v1_set_size(priv->layer_surface, priv->width, priv->height);
}
if (priv->height != old_height)
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT]);
if (priv->width != old_width)
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH]);
}
/**
* phosh_layer_surface_set_margins:
*
* Set anchor margins of a layer surface.
*/
void
phosh_layer_surface_set_margins(PhoshLayerSurface *self, gint top, gint right, gint bottom, gint left)
{
PhoshLayerSurfacePrivate *priv;
gint old_top, old_bottom, old_left, old_right;
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
priv = phosh_layer_surface_get_instance_private (self);
old_top = priv->margin_top;
old_left = priv->margin_left;
old_right = priv->margin_right;
old_bottom = priv->margin_bottom;
if (old_top == top && old_left == left && old_right == right && old_bottom == bottom)
return;
priv->margin_top = top;
priv->margin_left = left;
priv->margin_right = right;
priv->margin_bottom = bottom;
if (priv->layer_surface)
zwlr_layer_surface_v1_set_margin(priv->layer_surface, top, right, bottom, left);
if (old_top != top)
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_MARGIN_TOP]);
if (old_bottom != bottom)
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_MARGIN_BOTTOM]);
if (old_left != left)
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_MARGIN_LEFT]);
if (old_right != right)
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_MARGIN_RIGHT]);
}
/**
* phosh_layer_surface_set_exclusive_zone:
*
* Set exclusive zone of a layer surface.
*/
void
phosh_layer_surface_set_exclusive_zone(PhoshLayerSurface *self, gint zone)
{
PhoshLayerSurfacePrivate *priv;
gint old_zone;
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
priv = phosh_layer_surface_get_instance_private (self);
old_zone = priv->exclusive_zone;
if (old_zone == zone)
return;
priv->exclusive_zone = zone;
if (priv->layer_surface)
zwlr_layer_surface_v1_set_exclusive_zone(priv->layer_surface, zone);
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE]);
}
/**
* phosh_layer_surface_set_keyboard_interactivity:
*
* Set keyboard ineractivity a layer surface.
*/
void
phosh_layer_surface_set_kbd_interactivity (PhoshLayerSurface *self, gboolean interactivity)
{
PhoshLayerSurfacePrivate *priv;
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
priv = phosh_layer_surface_get_instance_private (self);
if (priv->kbd_interactivity == interactivity)
return;
priv->kbd_interactivity = interactivity;
if (priv->layer_surface)
zwlr_layer_surface_v1_set_keyboard_interactivity (priv->layer_surface, interactivity);
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_KBD_INTERACTIVITY]);
}
/**
* phosh_layer_surface_wl_surface_commit:
*
* Forces a commit of layer surface's state.
*/
void
phosh_layer_surface_wl_surface_commit (PhoshLayerSurface *self)
{
PhoshLayerSurfacePrivate *priv;
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
priv = phosh_layer_surface_get_instance_private (self);
if (priv->wl_surface)
wl_surface_commit (priv->wl_surface);
}

View File

@ -11,6 +11,7 @@ WARNING: this file is taken directly from phosh, with no modificaions apart from
*/ */
#pragma once #pragma once
#include <gtk/gtk.h> #include <gtk/gtk.h>
@ -38,16 +39,3 @@ GtkWidget *phosh_layer_surface_new (gpointer layer_shell,
gpointer wl_output); gpointer wl_output);
struct zwlr_layer_surface_v1 *phosh_layer_surface_get_layer_surface(PhoshLayerSurface *self); struct zwlr_layer_surface_v1 *phosh_layer_surface_get_layer_surface(PhoshLayerSurface *self);
struct wl_surface *phosh_layer_surface_get_wl_surface(PhoshLayerSurface *self); struct wl_surface *phosh_layer_surface_get_wl_surface(PhoshLayerSurface *self);
void phosh_layer_surface_set_size(PhoshLayerSurface *self,
gint width,
gint height);
void phosh_layer_surface_set_margins(PhoshLayerSurface *self,
gint top,
gint right,
gint bottom,
gint left);
void phosh_layer_surface_set_exclusive_zone(PhoshLayerSurface *self,
gint zone);
void phosh_layer_surface_set_kbd_interactivity(PhoshLayerSurface *self,
gboolean interactivity);
void phosh_layer_surface_wl_surface_commit (PhoshLayerSurface *self);

View File

@ -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'),
]

File diff suppressed because it is too large Load Diff

View File

@ -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
@ -41,14 +40,17 @@
#include "wayland.h" #include "wayland.h"
#include "eek/eek-xml-layout.h" #include "eek/eek-xml-layout.h"
#include "src/server-context-service.h"
#include "eekboard/eekboard-context-service.h" #include "eekboard/eekboard-context-service.h"
#define CSW 640
#define CSH 480
enum { 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
}; };
@ -67,10 +69,15 @@ 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
// TODO: make use of repeating buttons
guint repeat_timeout_id;
gboolean repeat_triggered;
GSettings *settings; GSettings *settings;
uint32_t hint; uint32_t hint;
uint32_t purpose; uint32_t purpose;
@ -80,20 +87,68 @@ G_DEFINE_TYPE_WITH_PRIVATE (EekboardContextService, eekboard_context_service, G_
static LevelKeyboard * 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)
enum squeek_arrangement_kind t)
{ {
LevelKeyboard *keyboard = eek_xml_layout_real_create_keyboard(keyboard_type, self, t); 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);
@ -101,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;
@ -110,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...
} }
@ -128,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;
} }
@ -163,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;
@ -184,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;
@ -226,8 +290,8 @@ settings_get_layout(GSettings *settings, char **type, char **layout)
g_variant_unref(inputs); g_variant_unref(inputs);
} }
void static void
eekboard_context_service_update_layout(EekboardContextService *context, enum squeek_arrangement_kind t) settings_update_layout(EekboardContextService *context)
{ {
g_autofree gchar *keyboard_type = NULL; g_autofree gchar *keyboard_type = NULL;
g_autofree gchar *keyboard_layout = NULL; g_autofree gchar *keyboard_layout = NULL;
@ -257,7 +321,7 @@ eekboard_context_service_update_layout(EekboardContextService *context, enum squ
GUINT_TO_POINTER(keyboard_id)); GUINT_TO_POINTER(keyboard_id));
// create a keyboard // create a keyboard
if (!keyboard) { if (!keyboard) {
keyboard = eekboard_context_service_real_create_keyboard(context, keyboard_layout, t); keyboard = eekboard_context_service_real_create_keyboard(context, keyboard_layout);
g_hash_table_insert (context->priv->keyboard_hash, g_hash_table_insert (context->priv->keyboard_hash,
GUINT_TO_POINTER(keyboard_id), GUINT_TO_POINTER(keyboard_id),
@ -267,14 +331,11 @@ eekboard_context_service_update_layout(EekboardContextService *context, enum squ
} }
// set as current // set as current
context->priv->keyboard = keyboard; context->priv->keyboard = keyboard;
// TODO: this used to save the group, why?
//group = eek_element_get_group (EEK_ELEMENT(context->priv->keyboard));
g_object_notify (G_OBJECT(context), "keyboard"); g_object_notify (G_OBJECT(context), "keyboard");
} }
static void update_layout_and_type(EekboardContextService *context) {
eekboard_context_service_update_layout(context, server_context_service_get_layout_type(context));
}
static gboolean static gboolean
settings_handle_layout_changed(GSettings *s, settings_handle_layout_changed(GSettings *s,
gpointer keys, gint n_keys, gpointer keys, gint n_keys,
@ -283,7 +344,7 @@ settings_handle_layout_changed(GSettings *s,
(void)keys; (void)keys;
(void)n_keys; (void)n_keys;
EekboardContextService *context = user_data; EekboardContextService *context = user_data;
update_layout_and_type(context); settings_update_layout(context);
return TRUE; return TRUE;
} }
@ -297,7 +358,7 @@ eekboard_context_service_constructed (GObject *object)
if (!context->virtual_keyboard) { if (!context->virtual_keyboard) {
g_error("Programmer error: Failed to receive a virtual keyboard instance"); g_error("Programmer error: Failed to receive a virtual keyboard instance");
} }
update_layout_and_type(context); settings_update_layout(context);
} }
static void static void
@ -391,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
@ -500,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)
{ {
@ -516,6 +604,6 @@ void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
if (priv->hint != hint || priv->purpose != purpose) { if (priv->hint != hint || priv->purpose != purpose) {
priv->hint = hint; priv->hint = hint;
priv->purpose = purpose; priv->purpose = purpose;
update_layout_and_type(context); settings_update_layout(context);
} }
} }

View File

@ -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);
@ -105,7 +107,6 @@ void eekboard_context_service_set_keymap(EekboardContextService *context,
void eekboard_context_service_set_hint_purpose(EekboardContextService *context, void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
uint32_t hint, uint32_t hint,
uint32_t purpose); uint32_t purpose);
void
eekboard_context_service_update_layout(EekboardContextService *context, enum squeek_arrangement_kind t);
G_END_DECLS G_END_DECLS
#endif /* EEKBOARD_CONTEXT_SERVICE_H */ #endif /* EEKBOARD_CONTEXT_SERVICE_H */

654
eekboard/eekboard-context.c Normal file
View 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);
}
}

View 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 */

View File

@ -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
@ -131,6 +134,7 @@ emit_key_activated (EekboardContextService *manager,
*/ */
SeatEmitter emitter = {0}; SeatEmitter emitter = {0};
emitter.virtual_keyboard = manager->virtual_keyboard; emitter.virtual_keyboard = manager->virtual_keyboard;
emitter.keymap = keyboard->keymap;
update_modifier_info (&emitter); update_modifier_info (&emitter);
send_fake_key (&emitter, keyboard, keycode, pressed, timestamp); send_fake_key (&emitter, keyboard, keycode, pressed, timestamp);
} }

View File

@ -0,0 +1,47 @@
#!/usr/bin/python
# Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
# Copyright (C) 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/>.
import eekboard
import glib
class SimpleClient(object):
def __init__(self):
client = eekboard.Client()
self.__context = client.create_context('simple-client')
client.push_context(self.__context)
keyboard_id = self.__context.add_keyboard('us')
self.__context.set_keyboard(keyboard_id)
def __key_pressed_cb(self, c, keyname, symbol, modifiers):
print (keyname, symbol, modifiers)
def __notify_visible_cb(self, c, p, mainloop):
if not c.props.visible:
mainloop.quit()
def run(self):
mainloop = glib.MainLoop()
self.__context.connect('key-pressed', self.__key_pressed_cb)
self.__context.connect('notify::visible', self.__notify_visible_cb,
mainloop)
self.__context.show_keyboard();
mainloop.run()
if __name__ == '__main__':
client = SimpleClient()
client.run()

View File

@ -1,52 +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);
let keymap_str = layout.keymap_str
.clone()
.into_string().expect("Failed to decode keymap string");
let keymap = xkb::Keymap::new_from_string(
&context,
keymap_str.clone(),
xkb::KEYMAP_FORMAT_TEXT_V1,
xkb::KEYMAP_COMPILE_NO_FLAGS,
).expect("Failed to create keymap");
let state = xkb::State::new(&keymap);
// "Press" each button with keysyms
for view in layout.views.values() {
for row in &view.rows {
for button in &row.buttons {
let keystate = button.state.borrow();
for keycode in &keystate.keycodes {
match state.key_get_one_sym(*keycode) {
xkb::KEY_NoSymbol => {
eprintln!("{}", keymap_str);
panic!("Keysym {} on key {:?} can't be resolved", keycode, button.name);
},
_ => {},
}
}
}
}
}
}
fn main() -> () {
check_layout(env::args().nth(1).expect("No argument given").as_str());
}

View File

@ -1,9 +1,9 @@
project( project(
'squeekboard', 'squeekboard',
'c', 'rust', 'c', 'rust',
version: '1.2.2', 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',
@ -18,7 +18,6 @@ add_project_arguments(
'-Werror=maybe-uninitialized', '-Werror=maybe-uninitialized',
'-Werror=missing-field-initializers', '-Werror=missing-field-initializers',
'-Werror=incompatible-pointer-types', '-Werror=incompatible-pointer-types',
'-Werror=int-conversion',
], ],
language: 'c' language: 'c'
) )
@ -54,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')

View File

@ -1,39 +0,0 @@
/*! The symbol object, defining actions that the key can do when activated */
use std::ffi::CString;
/// Name of the keysym
#[derive(Debug, Clone, PartialEq)]
pub struct KeySym(pub String);
/// Use to switch layouts
type Level = String;
/// Use to send modified keypresses
#[derive(Debug, Clone, PartialEq)]
pub enum Modifier {
Control,
Alt,
}
/// Action to perform on the keypress and, in reverse, on keyrelease
#[derive(Debug, Clone, PartialEq)]
pub enum Action {
/// Switch to this view
SetLevel(Level),
/// Switch to a view and latch
LockLevel {
lock: Level,
/// When unlocked by pressing it or emitting a key
unlock: Level,
},
/// Set this modifier TODO: release?
SetModifier(Modifier),
/// Submit some text
Submit {
/// Text to submit with input-method
text: Option<CString>,
/// The key events this symbol submits when submitting text is not possible
keys: Vec<KeySym>,
},
}

1350
src/bitflags.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,762 +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, PressType,
generate_keymap, generate_keycodes, FormattingError
};
use ::layout::ArrangementKind;
use ::resources;
use ::util::c::as_str;
use ::util::hash_map_map;
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,
type_: u32,
) -> *mut ::layout::Layout {
let type_ = match type_ {
0 => ArrangementKind::Base,
1 => ArrangementKind::Wide,
_ => panic!("Bad enum value"),
};
let name = as_str(&name)
.expect("Bad layout name")
.expect("Empty layout name");
let (kind, layout) = load_layout_data_with_fallback(&name, type_);
let layout = ::layout::Layout::new(layout, kind);
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, Clone, 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),
}
}
}
/// Lists possible sources, with 0 as the most preferred one
/// Trying order: native lang of the right kind, native base,
/// fallback lang of the right kind, fallback base
fn list_layout_sources(
name: &str,
kind: ArrangementKind,
keyboards_path: Option<PathBuf>,
) -> Vec<(ArrangementKind, DataSource)> {
let mut ret = Vec::new();
{
fn name_with_arrangement(name: String, kind: &ArrangementKind)
-> String
{
match kind {
ArrangementKind::Base => name,
ArrangementKind::Wide => name + "_wide",
}
}
let mut add_by_name = |name: &str, kind: &ArrangementKind| {
if let Some(path) = keyboards_path.clone() {
ret.push((
kind.clone(),
DataSource::File(
path.join(name.to_owned()).with_extension("yaml")
)
))
}
ret.push((
kind.clone(),
DataSource::Resource(name.into())
));
};
match &kind {
ArrangementKind::Base => {},
kind => add_by_name(
&name_with_arrangement(name.into(), &kind),
&kind,
),
};
add_by_name(name, &ArrangementKind::Base);
match &kind {
ArrangementKind::Base => {},
kind => add_by_name(
&name_with_arrangement(FALLBACK_LAYOUT_NAME.into(), &kind),
&kind,
),
};
add_by_name(FALLBACK_LAYOUT_NAME, &ArrangementKind::Base);
}
ret
}
fn load_layout_data(source: DataSource)
-> Result<::layout::LayoutData, LoadError>
{
match source {
DataSource::File(path) => {
Layout::from_file(path.clone())
.map_err(LoadError::BadData)
.and_then(|layout|
layout.build().map_err(LoadError::BadKeyMap)
)
},
DataSource::Resource(name) => {
Layout::from_resource(&name)
.and_then(|layout|
layout.build().map_err(LoadError::BadKeyMap)
)
},
}
}
fn load_layout_data_with_fallback(
name: &str,
kind: ArrangementKind,
) -> (ArrangementKind, ::layout::LayoutData) {
let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR")
.map(PathBuf::from)
.or_else(|| xdg::data_path("squeekboard/keyboards"));
for (kind, source) in list_layout_sources(name, kind, path) {
let layout = load_layout_data(source.clone());
match layout {
Err(e) => match (e, source) {
(
LoadError::BadData(Error::Missing(e)),
DataSource::File(file)
) => eprintln!( // TODO: print in debug logging level
"Tried file {:?}, but it's missing: {}",
file, e
),
(e, source) => eprintln!(
"Failed to load layout from {}: {}, skipping",
source, e
),
},
Ok(layout) => return (kind, layout),
}
}
panic!("No useful layout found!");
}
/// The root element describing an entire keyboard
#[derive(Debug, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Layout {
bounds: Bounds,
views: HashMap<String, Vec<ButtonIds>>,
#[serde(default)]
buttons: HashMap<String, ButtonMeta>,
outlines: HashMap<String, Outline>
}
#[derive(Debug, Clone, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
struct Bounds {
x: f64,
y: f64,
width: f64,
height: f64,
}
/// Buttons are embedded in a single string
type ButtonIds = String;
#[derive(Debug, Default, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
struct ButtonMeta {
/// Action other than keysym (conflicts with keysym)
action: Option<Action>,
/// The name of the outline. If not present, will be "default"
outline: Option<String>,
/// FIXME: start using it
keysym: Option<String>,
/// If not present, will be derived from the button ID
label: Option<String>,
/// Conflicts with label
icon: Option<String>,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
enum Action {
#[serde(rename="locking")]
Locking { lock_view: String, unlock_view: String },
#[serde(rename="set_view")]
SetView(String),
#[serde(rename="show_prefs")]
ShowPrefs,
}
#[derive(Debug, Clone, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
struct Outline {
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::LayoutData, 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 button_actions: Vec<(&str, ::action::Action)>
= button_names.iter().map(|name| {(
*name,
create_action(
&self.buttons,
name,
self.views.keys().collect()
)
)}).collect();
let keymap: HashMap<String, u32> = generate_keycodes(
button_actions.iter()
.filter_map(|(_name, action)| {
match action {
::action::Action::Submit {
text: _, keys,
} => Some(keys),
_ => None,
}
})
.flatten()
.map(|named_keysym| named_keysym.0.as_str())
);
let button_states = button_actions.into_iter().map(|(name, action)| {
let keycodes = match &action {
::action::Action::Submit { text: _, keys } => {
keys.iter().map(|named_keycode| {
*keymap.get(named_keycode.0.as_str())
.expect(
format!(
"keycode {} in key {} missing from keymap",
named_keycode.0,
name
).as_str()
)
}).collect()
},
_ => Vec::new(),
};
(
name.into(),
KeyState {
pressed: PressType::Released,
locked: false,
keycodes,
action,
}
)
});
let button_states
= HashMap::<String, KeyState>::from_iter(
button_states
);
// TODO: generate from symbols
let keymap_str = generate_keymap(&button_states)?;
let button_states_cache = hash_map_map(
button_states,
|name, state| {(
name,
Rc::new(RefCell::new(state))
)}
);
let views = HashMap::from_iter(
self.views.iter().map(|(name, view)| {(
name.clone(),
Box::new(::layout::View {
bounds: ::layout::c::Bounds {
x: self.bounds.x,
y: self.bounds.y,
width: self.bounds.width,
height: self.bounds.height,
},
rows: view.iter().map(|row| {
Box::new(::layout::Row {
angle: 0,
bounds: None,
buttons: row.split_ascii_whitespace().map(|name| {
Box::new(create_button(
&self.buttons,
&self.outlines,
name,
button_states_cache.get(name.into())
.expect("Button state not created")
.clone()
))
}).collect(),
})
}).collect(),
})
)})
);
Ok(::layout::LayoutData {
views: views,
keymap_str: {
CString::new(keymap_str)
.expect("Invalid keymap string generated")
},
})
}
}
fn create_action(
button_info: &HashMap<String, ButtonMeta>,
name: &str,
view_names: Vec<&String>,
) -> ::action::Action {
let default_meta = ButtonMeta::default();
let symbol_meta = button_info.get(name)
.unwrap_or(&default_meta);
fn filter_view_name(
button_name: &str,
view_name: String,
view_names: &Vec<&String>
) -> String {
if view_names.contains(&&view_name) {
view_name
} else {
eprintln!(
"Button {} switches to missing view {}",
button_name,
view_name
);
"base".into()
}
}
fn keysym_valid(name: &str) -> bool {
xkb::keysym_from_name(name, xkb::KEYSYM_NO_FLAGS) != xkb::KEY_NoSymbol
}
let keysyms = match &symbol_meta.action {
// Non-submit action
Some(_) => Vec::new(),
// Submit action
None => match &symbol_meta.keysym {
// Keysym given explicitly
Some(keysym) => vec!(match keysym_valid(keysym.as_str()) {
true => keysym.clone(),
false => {
eprintln!("Keysym name invalid: {}", keysym);
"space".into() // placeholder
},
}),
// Keysyms left open to derive
// TODO: when button name is meant diretly as xkb keysym name,
// mark it so, e.g. with a "#"
None => match keysym_valid(name) {
// Button name is actually a valid xkb name
true => vec!(String::from(name)),
// Button name is not a valid xkb name,
// so assume it's a literal string to be submitted
false => {
if name.chars().count() == 0 {
// A name read from yaml with no valid Unicode.
// Highly improbable, but let's be safe.
eprintln!("Key {} doesn't have any characters", name);
vec!("space".into()) // placeholder
} else {
name.chars().map(|codepoint| {
let codepoint_string = codepoint.to_string();
match keysym_valid(codepoint_string.as_str()) {
true => codepoint_string,
false => format!("U{:04X}", codepoint as u32),
}
}).collect()
}
},
},
},
};
match &symbol_meta.action {
Some(Action::SetView(view_name)) => ::action::Action::SetLevel(
filter_view_name(name, view_name.clone(), &view_names)
),
Some(Action::Locking {
lock_view, unlock_view
}) => ::action::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) => ::action::Action::Submit {
text: None,
keys: Vec::new(),
},
None => ::action::Action::Submit {
text: None,
keys: keysyms.into_iter().map(::action::KeySym).collect(),
},
}
}
/// 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 {
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 multiple codepoints
#[test]
fn test_layout_unicode_multi() {
let out = Layout::from_file(PathBuf::from("tests/layout_key3.yaml"))
.unwrap()
.build()
.unwrap();
assert_eq!(
out.views["base"]
.rows[0]
.buttons[0]
.state.borrow()
.keycodes.len(),
2
);
}
#[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 sources = list_layout_sources("nb", ArrangementKind::Base, None);
assert_eq!(
sources,
vec!(
(ArrangementKind::Base, DataSource::Resource("nb".into())),
(
ArrangementKind::Base,
DataSource::Resource(FALLBACK_LAYOUT_NAME.into())
),
)
);
}
#[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_action(
&hashmap!{
".".into() => ButtonMeta {
icon: None,
keysym: None,
action: None,
label: Some("test".into()),
outline: None,
}
},
".",
Vec::new()
),
::action::Action::Submit {
text: None,
keys: vec!(::action::KeySym("U002E".into())),
}
);
}
}

View File

@ -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);

View File

@ -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 {

View File

@ -1,12 +1,25 @@
#ifndef __KEYBOARD_H #ifndef __KEYBOARD_H
#define __KEYBOARD_H #define __KYBOARD_H
#include "inttypes.h"
#include "stdbool.h" #include "stdbool.h"
#include "virtual-keyboard-unstable-v1-client-protocol.h" #include "inttypes.h"
struct squeek_key; struct squeek_key;
struct squeek_key *squeek_key_new(uint32_t keycode);
void squeek_key_free(struct squeek_key *key);
void squeek_key_add_symbol(struct squeek_key* key,
const char *element_name,
const char *text, uint32_t keyval,
const char *label, const char *icon,
const char *tooltip);
uint32_t squeek_key_is_pressed(struct squeek_key *key); uint32_t squeek_key_is_pressed(struct squeek_key *key);
void squeek_key_set_pressed(struct squeek_key *key, uint32_t pressed);
uint32_t squeek_key_is_locked(struct squeek_key *key); uint32_t squeek_key_is_locked(struct squeek_key *key);
void squeek_key_set_locked(struct squeek_key *key, uint32_t pressed);
uint32_t squeek_key_get_keycode(struct squeek_key *key);
void squeek_key_set_keycode(struct squeek_key *key, uint32_t keycode);
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);
#endif #endif

View File

@ -1,198 +1,300 @@
/*! State of the emulated keyboard and keys. use std::vec::Vec;
* Regards the keyboard as if it was composed of switches. */
use std::collections::HashMap; use super::symbol;
use std::fmt;
use std::io;
use std::string::FromUtf8Error;
use ::action::Action;
use std::io::Write;
use std::iter::{ FromIterator, IntoIterator };
use ::util::CloneOwned;
/// 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 };
pub type CKeyState = c::Wrapped<KeyState>; use std::cell::RefCell;
use std::ffi::CString;
use std::os::raw::c_char;
use std::ptr;
use std::rc::Rc;
// traits
use std::borrow::ToOwned;
// The following defined in C
#[no_mangle]
extern "C" {
fn eek_keysym_from_name(name: *const c_char) -> u32;
}
/// The wrapped structure for KeyState suitable for handling in C
/// Since C doesn't respect borrowing rules,
/// RefCell will enforce them dynamically (only 1 writer/many readers)
/// Rc is implied and will ensure timely dropping
#[repr(transparent)]
pub struct CKeyState(*const RefCell<KeyState>);
impl Clone for CKeyState {
fn clone(&self) -> Self {
CKeyState(self.0.clone())
}
}
impl CKeyState {
pub fn wrap(state: Rc<RefCell<KeyState>>) -> CKeyState {
CKeyState(Rc::into_raw(state))
}
pub fn unwrap(self) -> Rc<RefCell<KeyState>> {
unsafe { Rc::from_raw(self.0) }
}
fn to_owned(self) -> KeyState {
let rc = self.unwrap();
let state = rc.borrow().to_owned();
Rc::into_raw(rc); // Prevent dropping
state
}
fn borrow_mut<F, T>(self, f: F) -> T where F: FnOnce(&mut KeyState) -> T {
let rc = self.unwrap();
let ret = {
let mut state = rc.borrow_mut();
f(&mut state)
};
Rc::into_raw(rc); // Prevent dropping
ret
}
}
// TODO: unwrapping
// 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]
pub extern "C"
fn squeek_key_free(key: CKeyState) {
key.unwrap(); // reference dropped
}
#[no_mangle] #[no_mangle]
pub extern "C" pub extern "C"
fn squeek_key_is_pressed(key: CKeyState) -> u32 { fn squeek_key_is_pressed(key: CKeyState) -> u32 {
//let key = unsafe { Rc::from_raw(key.0) }; //let key = unsafe { Rc::from_raw(key.0) };
return key.clone_owned().pressed as u32; return key.to_owned().pressed as u32;
}
#[no_mangle]
pub extern "C"
fn squeek_key_set_pressed(key: CKeyState, pressed: u32) {
key.borrow_mut(|key| key.pressed = pressed != 0);
} }
#[no_mangle] #[no_mangle]
pub extern "C" pub extern "C"
fn squeek_key_is_locked(key: CKeyState) -> u32 { fn squeek_key_is_locked(key: CKeyState) -> u32 {
return key.clone_owned().locked as u32; return key.to_owned().locked as u32;
}
#[no_mangle]
pub extern "C"
fn squeek_key_set_locked(key: CKeyState, locked: u32) {
key.borrow_mut(|key| key.locked = locked != 0);
}
#[no_mangle]
pub extern "C"
fn squeek_key_get_keycode(key: CKeyState) -> u32 {
return key.to_owned().keycode as u32;
}
#[no_mangle]
pub extern "C"
fn squeek_key_set_keycode(key: CKeyState, code: u32) {
key.borrow_mut(|key| key.keycode = code);
}
// TODO: this will receive data from the filesystem,
// so it should handle garbled strings in the future
#[no_mangle]
pub extern "C"
fn squeek_key_add_symbol(
key: CKeyState,
element: *const c_char,
text_raw: *const c_char, keyval: u32,
label: *const c_char, icon: *const c_char,
tooltip: *const c_char,
) {
let element = as_cstr(&element)
.expect("Missing element name");
let text = into_cstring(text_raw)
.unwrap_or_else(|e| {
eprintln!("Text unreadable: {}", e);
None
})
.and_then(|text| {
if text.as_bytes() == b"" {
None
} else {
Some(text)
}
});
let icon = into_cstring(icon)
.unwrap_or_else(|e| {
eprintln!("Icon name unreadable: {}", e);
None
});
use symbol::*;
// Only read label if there's no icon
let label = match icon {
Some(icon) => Label::IconName(icon),
None => Label::Text(
into_cstring(label)
.unwrap_or_else(|e| {
eprintln!("Label unreadable: {}", e);
Some(CString::new(" ").unwrap())
})
.unwrap_or_else(|| {
eprintln!("Label missing");
CString::new(" ").unwrap()
})
),
};
let tooltip = into_cstring(tooltip)
.unwrap_or_else(|e| {
eprintln!("Tooltip unreadable: {}", e);
None
});
key.borrow_mut(|key| {
if let Some(_) = key.symbol {
eprintln!("Key {:?} already has a symbol defined", text);
return;
}
key.symbol = Some(match element.to_bytes() {
b"symbol" => Symbol {
action: Action::Submit {
text: text,
keys: Vec::new(),
},
label: label,
tooltip: tooltip,
},
_ => panic!("unsupported element type {:?}", element),
});
});
}
#[no_mangle]
pub extern "C"
fn squeek_key_get_symbol(key: CKeyState) -> *const symbol::Symbol {
key.borrow_mut(|key| {
match key.symbol {
// This pointer stays after the function exits,
// so it must reference borrowed data and not any copy
Some(ref symbol) => symbol as *const symbol::Symbol,
None => ptr::null(),
}
})
}
#[no_mangle]
pub extern "C"
fn squeek_key_to_keymap_entry(
key_name: *const c_char,
key: CKeyState,
) -> *const c_char {
let key_name = as_cstr(&key_name)
.expect("Missing key name")
.to_str()
.expect("Bad key name");
let symbol_name = match key.to_owned().symbol {
Some(ref symbol) => match &symbol.action {
symbol::Action::Submit { text: Some(text), .. } => {
Some(
text.clone()
.into_string().expect("Bad symbol")
)
},
_ => None
},
None => {
eprintln!("Key {} has no symbol", key_name);
None
},
};
let inner = match symbol_name {
Some(name) => format!("[ {} ]", name),
_ => format!("[ ]"),
};
CString::new(format!(" key <{}> {{ {} }};\n", key_name, inner))
.expect("Couldn't convert string")
.into_raw()
}
#[no_mangle]
pub extern "C"
fn squeek_key_get_action_name(
key_name: *const c_char,
key: CKeyState,
) -> *const c_char {
let key_name = as_cstr(&key_name)
.expect("Missing key name")
.to_str()
.expect("Bad key name");
let symbol_name = match key.to_owned().symbol {
Some(ref symbol) => match &symbol.action {
symbol::Action::Submit { text: Some(text), .. } => {
Some(
text.clone()
.into_string().expect("Bad symbol")
)
},
_ => None
},
None => {
eprintln!("Key {} has no symbol", key_name);
None
},
};
let inner = match symbol_name {
Some(name) => format!("[ {} ]", name),
_ => format!("[ ]"),
};
CString::new(format!(" key <{}> {{ {} }};\n", key_name, inner))
.expect("Couldn't convert string")
.into_raw()
} }
}
#[derive(Debug, Clone, Copy)]
pub enum PressType {
Released = 0,
Pressed = 1,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct KeyState { pub struct KeyState {
pub pressed: PressType, pub pressed: bool,
pub locked: bool, pub locked: bool,
/// A cache of raw keycodes derived from Action::Sumbit given a keymap pub keycode: u32,
pub keycodes: Vec<u32>, // TODO: remove the optionality of a symbol
/// Static description of what the key does when pressed or released pub symbol: Option<symbol::Symbol>,
pub action: Action,
}
/// 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, 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() {
if let Action::Submit { text: _, keys } = &state.action {
if let 0 = keys.len() { eprintln!("Key {} has no keysyms", name); };
for (named_keysym, keycode) in keys.iter().zip(&state.keycodes) {
write!(
buf,
"
<{}> = {};",
named_keysym.0,
keycode,
)?;
}
}
}
writeln!(
buf,
"
}};
xkb_symbols \"squeekboard\" {{
name[Group1] = \"Letters\";
name[Group2] = \"Numbers/Symbols\";"
)?;
for (name, state) in keystates.iter() {
if let Action::Submit { text: _, keys } = &state.action {
for keysym in keys.iter() {
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\" {{
}};
}};"
)?;
//println!("{}", String::from_utf8(buf.clone()).unwrap());
String::from_utf8(buf).map_err(FormattingError::Utf)
}
#[cfg(test)]
mod tests {
use super::*;
use xkbcommon::xkb;
use ::action::KeySym;
#[test]
fn test_keymap_multi() {
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let keymap_str = generate_keymap(&hashmap!{
"ac".into() => KeyState {
action: Action::Submit {
text: None,
keys: vec!(KeySym("a".into()), KeySym("c".into())),
},
keycodes: vec!(9, 10),
locked: false,
pressed: PressType::Released,
},
}).unwrap();
let keymap = xkb::Keymap::new_from_string(
&context,
keymap_str.clone(),
xkb::KEYMAP_FORMAT_TEXT_V1,
xkb::KEYMAP_COMPILE_NO_FLAGS,
).expect("Failed to create keymap");
let state = xkb::State::new(&keymap);
assert_eq!(state.key_get_one_sym(9), xkb::KEY_a);
assert_eq!(state.key_get_one_sym(10), xkb::KEY_c);
}
} }

View File

@ -4,73 +4,75 @@
#include <inttypes.h> #include <inttypes.h>
#include <glib.h> #include <glib.h>
#include "eek/eek-element.h" #include "eek/eek-element.h"
#include "eek/eek-gtk-keyboard.h"
#include "eek/eek-types.h"
#include "src/keyboard.h" #include "src/keyboard.h"
#include "virtual-keyboard-unstable-v1-client-protocol.h"
enum squeek_arrangement_kind {
ARRANGEMENT_KIND_BASE = 0,
ARRANGEMENT_KIND_WIDE = 1,
};
struct squeek_button; struct squeek_button;
struct squeek_row; struct squeek_row;
struct squeek_view; struct squeek_view;
struct squeek_layout;
/// Represents the path to the button within a view
struct button_place {
const struct squeek_row *row;
const struct squeek_button *button;
};
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);
struct button_place squeek_view_find_key(struct squeek_view*, struct squeek_key *state);
typedef void (*ButtonCallback) (struct squeek_button *button, gpointer user_data); typedef void (*ButtonCallback) (struct squeek_button *button, gpointer user_data);
void squeek_row_foreach(struct squeek_row*, void squeek_row_foreach(struct squeek_row*,
ButtonCallback callback, ButtonCallback callback,
gpointer user_data); gpointer user_data);
EekBounds squeek_button_get_bounds(const struct squeek_button*); void squeek_row_free(struct squeek_row*);
const char *squeek_button_get_label(const struct squeek_button*);
const char *squeek_button_get_icon_name(const struct squeek_button*);
const char *squeek_button_get_name(const struct squeek_button*);
const char *squeek_button_get_outline_name(const struct squeek_button*);
/*
struct squeek_button *squeek_buttons_find_by_position(
const struct squeek_buttons *buttons,
double x, double y,
double origin_x, double origin_y,
double angle);
void squeek_buttons_add(struct squeek_buttons*, const struct squeek_button* button);
void squeek_buttons_remove_key(struct squeek_buttons*, const struct squeek_key* key);
*/
struct squeek_button *squeek_button_new(uint32_t keycode, uint32_t oref);
struct squeek_button *squeek_button_new_with_state(const struct squeek_button* source);
uint32_t squeek_button_get_oref(const struct squeek_button*);
EekBounds squeek_button_get_bounds(const struct squeek_button*);
void squeek_button_set_bounds(struct squeek_button* button, EekBounds bounds);
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*,
RowCallback callback, RowCallback callback,
gpointer user_data); gpointer user_data);
struct squeek_row *squeek_view_get_row(struct squeek_view *view,
struct squeek_button *button);
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*);
struct squeek_layout *squeek_load_layout(const char *name, uint32_t type); struct squeek_button *squeek_view_find_button_by_position(struct squeek_view *view, EekPoint point);
const char *squeek_layout_get_keymap(const struct squeek_layout*);
enum squeek_arrangement_kind squeek_layout_get_kind(const struct squeek_layout *);
void squeek_layout_free(struct squeek_layout*);
void squeek_layout_release(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard, uint32_t timestamp, EekGtkKeyboard *ui_keyboard);
void squeek_layout_release_all_only(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard, uint32_t timestamp);
void squeek_layout_depress(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard,
double x_widget, double y_widget,
struct transformation widget_to_layout,
uint32_t timestamp, EekGtkKeyboard *ui_keyboard);
void squeek_layout_drag(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard,
double x_widget, double y_widget,
struct transformation widget_to_layout,
uint32_t timestamp, EekGtkKeyboard *ui_keyboard);
void squeek_layout_draw_all_changed(struct squeek_layout *layout, EekGtkKeyboard *ui_keyboard);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,9 @@
#[macro_use] #[macro_use]
extern crate bitflags; mod bitflags;
#[allow(unused_imports)]
#[macro_use] // only for tests
extern crate maplit;
extern crate serde;
extern crate xkbcommon;
mod action; mod float_ord;
pub mod data; mod imservice;
pub mod float_ord;
pub mod imservice;
mod keyboard; mod keyboard;
mod layout; mod layout;
mod outputs; mod symbol;
mod resources;
mod submission;
mod util; mod util;
mod xdg;

View File

@ -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: [

View File

@ -1,13 +0,0 @@
#ifndef __OUTPUTS_H
#define __OUTPUTS_H
#include "wayland-client-protocol.h"
struct squeek_outputs;
struct squeek_outputs *squeek_outputs_new();
void squeek_outputs_free(struct squeek_outputs*);
void squeek_outputs_register(struct squeek_outputs*, struct wl_output *output);
struct wl_output *squeek_outputs_get_current(struct squeek_outputs*);
int32_t squeek_outputs_get_perceptual_width(struct squeek_outputs*, struct wl_output *output);
#endif

View File

@ -1,322 +0,0 @@
/*! Managing Wayland outputs */
use std::vec::Vec;
/// Gathers stuff defined in C or called by C
pub mod c {
use super::*;
use std::os::raw::{ c_char, c_void };
use ::util::c::COpaquePtr;
// Defined in C
#[repr(transparent)]
#[derive(Clone, PartialEq)]
pub struct WlOutput(*const c_void);
#[repr(C)]
struct WlOutputListener<T: COpaquePtr> {
geometry: extern fn(
T, // data
WlOutput,
i32, // x
i32, // y
i32, // physical_width
i32, // physical_height
i32, // subpixel
*const c_char, // make
*const c_char, // model
i32, // transform
),
mode: extern fn(
T, // data
WlOutput,
u32, // flags
i32, // width
i32, // height
i32, // refresh
),
done: extern fn(
T, // data
WlOutput,
),
scale: extern fn(
T, // data
WlOutput,
i32, // factor
),
}
bitflags!{
/// Map to `wl_output.mode` values
pub struct Mode: u32 {
const NONE = 0x0;
const CURRENT = 0x1;
const PREFERRED = 0x2;
}
}
/// Map to `wl_output.transform` values
#[derive(Clone)]
pub enum Transform {
Normal = 0,
Rotated90 = 1,
Rotated180 = 2,
Rotated270 = 3,
Flipped = 4,
FlippedRotated90 = 5,
FlippedRotated180 = 6,
FlippedRotated270 = 7,
}
impl Transform {
fn from_u32(v: u32) -> Option<Transform> {
use self::Transform::*;
match v {
0 => Some(Normal),
1 => Some(Rotated90),
2 => Some(Rotated180),
3 => Some(Rotated270),
4 => Some(Flipped),
5 => Some(FlippedRotated90),
6 => Some(FlippedRotated180),
7 => Some(FlippedRotated270),
_ => None,
}
}
}
extern "C" {
// Rustc wrongly assumes
// that COutputs allows C direct access to the underlying RefCell
#[allow(improper_ctypes)]
fn squeek_output_add_listener(
wl_output: WlOutput,
listener: *const WlOutputListener<COutputs>,
data: COutputs,
) -> i32;
}
type COutputs = ::util::c::Wrapped<Outputs>;
// Defined in Rust
extern fn outputs_handle_geometry(
outputs: COutputs,
wl_output: WlOutput,
_x: i32, _y: i32,
_phys_width: i32, _phys_height: i32,
_subpixel: i32,
_make: *const c_char, _model: *const c_char,
transform: i32,
) {
let transform = Transform::from_u32(transform as u32).unwrap_or_else(
|| {
eprintln!(
"Warning: received invalid wl_output.transform value"
);
Transform::Normal
}
);
let outputs = outputs.clone_ref();
let mut collection = outputs.borrow_mut();
let output_state: Option<&mut OutputState>
= find_output_mut(&mut collection, wl_output)
.map(|o| &mut o.pending);
match output_state {
Some(state) => { state.transform = Some(transform) },
None => eprintln!("Wayland error: Got mode on unknown output"),
};
}
extern fn outputs_handle_mode(
outputs: COutputs,
wl_output: WlOutput,
flags: u32,
width: i32,
height: i32,
_refresh: i32,
) {
let flags = Mode::from_bits(flags).unwrap_or_else(|| {
eprintln!("Warning: received invalid wl_output.mode flags");
Mode::NONE
});
let outputs = outputs.clone_ref();
let mut collection = outputs.borrow_mut();
let output_state: Option<&mut OutputState>
= find_output_mut(&mut collection, wl_output)
.map(|o| &mut o.pending);
match output_state {
Some(state) => {
if flags.contains(Mode::CURRENT) {
state.current_mode = Some(super::Mode { width, height});
}
},
None => eprintln!("Wayland error: Got mode on unknown output"),
};
}
extern fn outputs_handle_done(
outputs: COutputs,
wl_output: WlOutput,
) {
let outputs = outputs.clone_ref();
let mut collection = outputs.borrow_mut();
let output = find_output_mut(&mut collection, wl_output);
match output {
Some(output) => { output.current = output.pending.clone(); }
None => eprintln!("Wayland error: Got done on unknown output"),
};
}
extern fn outputs_handle_scale(
outputs: COutputs,
wl_output: WlOutput,
factor: i32,
) {
let outputs = outputs.clone_ref();
let mut collection = outputs.borrow_mut();
let output_state: Option<&mut OutputState>
= find_output_mut(&mut collection, wl_output)
.map(|o| &mut o.pending);
match output_state {
Some(state) => { state.scale = factor; }
None => eprintln!("Wayland error: Got done on unknown output"),
};
}
#[no_mangle]
pub extern "C"
fn squeek_outputs_new() -> COutputs {
COutputs::new(Outputs { outputs: Vec::new() })
}
#[no_mangle]
pub extern "C"
fn squeek_outputs_free(outputs: COutputs) {
unsafe { outputs.unwrap() }; // gets dropped
}
#[no_mangle]
pub extern "C"
fn squeek_outputs_register(raw_collection: COutputs, output: WlOutput) {
let collection = raw_collection.clone_ref();
let mut collection = collection.borrow_mut();
collection.outputs.push(Output {
output: output.clone(),
pending: OutputState::uninitialized(),
current: OutputState::uninitialized(),
});
unsafe { squeek_output_add_listener(
output,
&WlOutputListener {
geometry: outputs_handle_geometry,
mode: outputs_handle_mode,
done: outputs_handle_done,
scale: outputs_handle_scale,
} as *const WlOutputListener<COutputs>,
raw_collection,
)};
}
#[no_mangle]
pub extern "C"
fn squeek_outputs_get_current(raw_collection: COutputs) -> WlOutput {
let collection = raw_collection.clone_ref();
let collection = collection.borrow();
collection.outputs[0].output.clone()
}
#[no_mangle]
pub extern "C"
fn squeek_outputs_get_perceptual_width(
raw_collection: COutputs,
wl_output: WlOutput,
) -> i32 {
let collection = raw_collection.clone_ref();
let collection = collection.borrow();
let output_state = find_output(&collection, wl_output)
.map(|o| &o.current);
match output_state {
Some(OutputState {
current_mode: Some(super::Mode { width, height } ),
transform: Some(transform),
scale,
}) => {
match transform {
Transform::Normal
| Transform::Rotated180
| Transform::Flipped
| Transform::FlippedRotated180 => width / scale,
_ => height / scale,
}
},
_ => {
eprintln!("Not enough info registered on output");
0
},
}
}
// TODO: handle unregistration
fn find_output(
collection: &Outputs,
wl_output: WlOutput,
) -> Option<&Output> {
collection.outputs
.iter()
.find_map(|o|
if o.output == wl_output { Some(o) } else { None }
)
}
fn find_output_mut(
collection: &mut Outputs,
wl_output: WlOutput,
) -> Option<&mut Output> {
collection.outputs
.iter_mut()
.find_map(|o|
if o.output == wl_output { Some(o) } else { None }
)
}
}
#[derive(Clone)]
struct Mode {
width: i32,
height: i32,
}
#[derive(Clone)]
pub struct OutputState {
current_mode: Option<Mode>,
transform: Option<c::Transform>,
scale: i32,
}
impl OutputState {
fn uninitialized() -> OutputState {
OutputState {
current_mode: None,
transform: None,
scale: 1,
}
}
}
pub struct Output {
output: c::WlOutput,
pending: OutputState,
current: OutputState,
}
pub struct Outputs {
outputs: Vec<Output>,
}

View File

@ -1,29 +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")),
("us_wide", include_str!("../data/keyboards/us_wide.yaml")),
("de", include_str!("../data/keyboards/de.yaml")),
("el", include_str!("../data/keyboards/el.yaml")),
("es", include_str!("../data/keyboards/es.yaml")),
("it", include_str!("../data/keyboards/it.yaml")),
("ja+kana", include_str!("../data/keyboards/ja+kana.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 }
})
}

View File

@ -20,8 +20,7 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <glib/gi18n.h> #include <glib/gi18n.h>
#include "eek/eek.h" #include "eek/eek-gtk.h"
#include "eek/eek-gtk-keyboard.h"
#include "eek/layersurface.h" #include "eek/layersurface.h"
#include "wayland.h" #include "wayland.h"
@ -39,11 +38,8 @@ typedef struct _ServerContextServiceClass ServerContextServiceClass;
struct _ServerContextService { struct _ServerContextService {
EekboardContextService parent; EekboardContextService parent;
PhoshLayerSurface *window; GtkWidget *window;
GtkWidget *widget; GtkWidget *widget;
guint hiding;
guint last_requested_height;
enum squeek_arrangement_kind last_type;
gdouble size_constraint_landscape[2]; gdouble size_constraint_landscape[2];
gdouble size_constraint_portrait[2]; gdouble size_constraint_portrait[2];
@ -55,12 +51,23 @@ 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)
{ {
ServerContextService *context = user_data; ServerContextService *context = user_data;
g_assert (widget == GTK_WIDGET(context->window)); g_assert (widget == context->window);
context->window = NULL; context->window = NULL;
context->widget = NULL; context->widget = NULL;
@ -100,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,84 +128,70 @@ static void
on_notify_unmap (GObject *object, on_notify_unmap (GObject *object,
ServerContextService *context) ServerContextService *context)
{ {
(void)object;
g_object_set (context, "visible", FALSE, NULL); g_object_set (context, "visible", FALSE, NULL);
} }
static uint32_t
calculate_height(int32_t width)
{
uint32_t height = 180;
if (width < 360 && width > 0) {
height = ((unsigned)width * 7 / 12); // to match 360×210
} else if (width < 540) {
height = 180 + (540 - (unsigned)width) * 30 / 180; // smooth transition
}
return height;
}
enum squeek_arrangement_kind get_type(uint32_t width, uint32_t height) {
(void)height;
if (width < 540) {
return ARRANGEMENT_KIND_BASE;
}
return ARRANGEMENT_KIND_WIDE;
}
static void static void
on_surface_configure(PhoshLayerSurface *surface, ServerContextService *context) set_geometry (ServerContextService *context)
{ {
gint width; GdkScreen *screen = gdk_screen_get_default ();
gint height; GdkWindow *root = gdk_screen_get_root_window (screen);
g_object_get(G_OBJECT(surface), GdkDisplay *display = gdk_display_get_default ();
"configured-width", &width, GdkMonitor *monitor = gdk_display_get_monitor_at_window (display, root);
"configured-height", &height, LevelKeyboard *keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context));
NULL);
// check if the change would switch types GdkRectangle rect;
enum squeek_arrangement_kind new_type = get_type((uint32_t)width, (uint32_t)height);
if (context->last_type != new_type) { gdk_monitor_get_geometry (monitor, &rect);
context->last_type = new_type; EekBounds bounds = squeek_view_get_bounds (level_keyboard_current(keyboard));
eekboard_context_service_update_layout(EEKBOARD_CONTEXT_SERVICE(context), context->last_type);
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];
} }
guint desired_height = calculate_height(width); if (width * bounds.height > height * bounds.width)
guint configured_height = (guint)height; width = (height / bounds.height) * bounds.width;
// if height was already requested once but a different one was given else
// (for the same set of surrounding properties), height = (width / bounds.width) * bounds.height;
// then it's probably not reasonable to ask for it again,
// as it's likely to create pointless loops gtk_window_resize (GTK_WINDOW(context->widget), width, height);
// of request->reject->request_again->...
if (desired_height != configured_height gtk_window_move (GTK_WINDOW(context->window),
&& context->last_requested_height != desired_height) { (rect.width - width) / 2,
context->last_requested_height = desired_height; rect.height - height);
phosh_layer_surface_set_size(surface, 0,
(gint)desired_height); gtk_window_set_decorated (GTK_WINDOW(context->window), FALSE);
phosh_layer_surface_set_exclusive_zone(surface, (gint)desired_height); gtk_window_set_resizable (GTK_WINDOW(context->window), FALSE);
phosh_layer_surface_wl_surface_commit (surface);
} }
} }
#define KEYBOARD_HEIGHT 210
static void static void
make_window (ServerContextService *context) make_window (ServerContextService *context)
{ {
if (context->window) if (context->window)
g_error("Window already present"); g_error("Window already present");
struct wl_output *output = squeek_outputs_get_current(squeek_wayland->outputs);
int32_t width = squeek_outputs_get_perceptual_width(squeek_wayland->outputs, output);
uint32_t height = calculate_height(width);
context->window = g_object_new ( context->window = g_object_new (
PHOSH_TYPE_LAYER_SURFACE, PHOSH_TYPE_LAYER_SURFACE,
"layer-shell", squeek_wayland->layer_shell, "layer-shell", squeek_wayland->layer_shell,
"wl-output", output, "wl-output", g_ptr_array_index(squeek_wayland->outputs, 0), // TODO: select output as needed,
"height", height, "height", KEYBOARD_HEIGHT,
"anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
| ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,
"layer", ZWLR_LAYER_SHELL_V1_LAYER_TOP, "layer", ZWLR_LAYER_SHELL_V1_LAYER_TOP,
"kbd-interactivity", FALSE, "kbd-interactivity", FALSE,
"exclusive-zone", height, "exclusive-zone", KEYBOARD_HEIGHT,
"namespace", "osk", "namespace", "osk",
NULL NULL
); );
@ -198,7 +200,6 @@ make_window (ServerContextService *context)
"signal::destroy", G_CALLBACK(on_destroy), context, "signal::destroy", G_CALLBACK(on_destroy), context,
"signal::map", G_CALLBACK(on_notify_map), context, "signal::map", G_CALLBACK(on_notify_map), context,
"signal::unmap", G_CALLBACK(on_notify_unmap), context, "signal::unmap", G_CALLBACK(on_notify_unmap), context,
"signal::configured", G_CALLBACK(on_surface_configure), context,
NULL); NULL);
// The properties below are just to make hacking easier. // The properties below are just to make hacking easier.
@ -206,7 +207,7 @@ make_window (ServerContextService *context)
// and there's no space in the protocol for others. // and there's no space in the protocol for others.
// Those may still be useful in the future, // Those may still be useful in the future,
// or for hacks with regular windows. // or for hacks with regular windows.
gtk_widget_set_can_focus (GTK_WIDGET(context->window), FALSE); gtk_widget_set_can_focus (context->window, FALSE);
g_object_set (G_OBJECT(context->window), "accept_focus", FALSE, NULL); g_object_set (G_OBJECT(context->window), "accept_focus", FALSE, NULL);
gtk_window_set_title (GTK_WINDOW(context->window), gtk_window_set_title (GTK_WINDOW(context->window),
_("Squeekboard")); _("Squeekboard"));
@ -236,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
@ -243,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)
@ -255,16 +252,7 @@ server_context_service_real_show_keyboard (EekboardContextService *_context)
EEKBOARD_CONTEXT_SERVICE_CLASS (server_context_service_parent_class)-> EEKBOARD_CONTEXT_SERVICE_CLASS (server_context_service_parent_class)->
show_keyboard (_context); show_keyboard (_context);
gtk_widget_show (GTK_WIDGET(context->window)); gtk_widget_show (context->window);
}
static gboolean
on_hide (ServerContextService *context)
{
gtk_widget_hide (GTK_WIDGET(context->window));
context->hiding = 0;
return G_SOURCE_REMOVE;
} }
static void static void
@ -272,8 +260,7 @@ 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);
@ -362,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 *
@ -373,8 +371,3 @@ server_context_service_new ()
{ {
return EEKBOARD_CONTEXT_SERVICE(g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL)); return EEKBOARD_CONTEXT_SERVICE(g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL));
} }
enum squeek_arrangement_kind server_context_service_get_layout_type(EekboardContextService *service)
{
return SERVER_CONTEXT_SERVICE(service)->last_type;
}

View File

@ -19,7 +19,6 @@
#define SERVER_CONTEXT_SERVICE_H 1 #define SERVER_CONTEXT_SERVICE_H 1
#include "eekboard/eekboard-service.h" #include "eekboard/eekboard-service.h"
#include "src/layout.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -34,7 +33,6 @@ G_BEGIN_DECLS
typedef struct _ServerContextService ServerContextService; typedef struct _ServerContextService ServerContextService;
EekboardContextService *server_context_service_new (); EekboardContextService *server_context_service_new ();
enum squeek_arrangement_kind server_context_service_get_layout_type(EekboardContextService*);
G_END_DECLS G_END_DECLS
#endif /* SERVER_CONTEXT_SERVICE_H */ #endif /* SERVER_CONTEXT_SERVICE_H */

51
src/server-context.h Normal file
View 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 */

View File

@ -28,7 +28,6 @@
#include "eekboard/eekboard-service.h" #include "eekboard/eekboard-service.h"
#include "eek/eek.h" #include "eek/eek.h"
#include "imservice.h" #include "imservice.h"
#include "outputs.h"
#include "server-context-service.h" #include "server-context-service.h"
#include "wayland.h" #include "wayland.h"
@ -117,7 +116,7 @@ registry_handle_global (void *data,
} else if (!strcmp (interface, "wl_output")) { } else if (!strcmp (interface, "wl_output")) {
struct wl_output *output = wl_registry_bind (registry, name, struct wl_output *output = wl_registry_bind (registry, name,
&wl_output_interface, 2); &wl_output_interface, 2);
squeek_outputs_register(instance->wayland.outputs, output); g_ptr_array_add (instance->wayland.outputs, output);
} else if (!strcmp(interface, "wl_seat")) { } else if (!strcmp(interface, "wl_seat")) {
instance->wayland.seat = wl_registry_bind(registry, name, instance->wayland.seat = wl_registry_bind(registry, name,
&wl_seat_interface, 1); &wl_seat_interface, 1);

View File

@ -1,68 +0,0 @@
/*! Managing the events belonging to virtual-keyboard interface. */
use ::keyboard::{ KeyState, PressType };
/// Gathers stuff defined in C or called by C
pub mod c {
use std::os::raw::c_void;
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct ZwpVirtualKeyboardV1(*const c_void);
#[no_mangle]
extern "C" {
/// Checks if point falls within bounds,
/// which are relative to origin and rotated by angle (I think)
pub fn eek_virtual_keyboard_v1_key(
virtual_keyboard: ZwpVirtualKeyboardV1,
timestamp: u32,
keycode: u32,
press: u32,
);
}
}
pub struct Timestamp(pub u32);
/// Layout-independent backend. TODO: Have one instance per program or seat
pub struct VirtualKeyboard(pub c::ZwpVirtualKeyboardV1);
impl VirtualKeyboard {
// TODO: split out keyboard state management
pub fn switch(
&self,
key: &mut KeyState,
action: PressType,
timestamp: Timestamp,
) {
key.pressed = action.clone();
let keycodes_count = key.keycodes.len();
for keycode in key.keycodes.iter() {
let keycode = keycode - 8;
match (&key.pressed, keycodes_count) {
// Pressing a key made out of a single keycode is simple:
// press on press, release on release.
(_, 1) => unsafe {
c::eek_virtual_keyboard_v1_key(
self.0, timestamp.0, keycode, action.clone() as u32
);
},
// A key made of multiple keycodes
// has to submit them one after the other
(PressType::Pressed, _) => unsafe {
c::eek_virtual_keyboard_v1_key(
self.0, timestamp.0, keycode, PressType::Pressed as u32
);
c::eek_virtual_keyboard_v1_key(
self.0, timestamp.0, keycode, PressType::Released as u32
);
},
// Design choice here: submit multiple all at press time
// and do nothing at release time
(PressType::Released, _) => {},
}
}
}
}

24
src/symbol.h Normal file
View 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

Some files were not shown because too many files have changed in this diff Show More