Compare commits
	
		
			36 Commits
		
	
	
		
			v1.3.2
			...
			squeekboar
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 3af10285b7 | |||
| 53997abc46 | |||
| 34765be22e | |||
| 8b4c643d3e | |||
| 358b25c431 | |||
| 2749fdb686 | |||
| 8e7909e877 | |||
| afaacd3f68 | |||
| 6a164d8119 | |||
| 3c45e3e53c | |||
| cdf263d984 | |||
| 2ddfcfaff0 | |||
| a901c85bcb | |||
| fdbbe8f126 | |||
| f284627beb | |||
| d45724c462 | |||
| 93d0dcdc99 | |||
| b252f7659b | |||
| af6ad1fce6 | |||
| 4ee8a91dfe | |||
| 6d5f793718 | |||
| 59f6173282 | |||
| 3aec821f92 | |||
| 3ac4caa3b9 | |||
| 80ac591535 | |||
| 034570bfa0 | |||
| 1abca0a44e | |||
| 23693521b7 | |||
| 0179507254 | |||
| 0c7e77a05f | |||
| 0adde1004f | |||
| 9b271a6919 | |||
| 1db561d33a | |||
| 9571adb107 | |||
| f834f174d8 | |||
| 3c0b142c4f | 
@ -4,6 +4,7 @@ version = "0.1.0"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
bitflags = "1.0.*"
 | 
					bitflags = "1.0.*"
 | 
				
			||||||
 | 
					clap = "2.32.*"
 | 
				
			||||||
maplit = "1.0.*"
 | 
					maplit = "1.0.*"
 | 
				
			||||||
regex = "1.1.*"
 | 
					regex = "1.1.*"
 | 
				
			||||||
serde = { version = "1.0.*", features = ["derive"] }
 | 
					serde = { version = "1.0.*", features = ["derive"] }
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								HACKING.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								HACKING.md
									
									
									
									
									
								
							@ -30,7 +30,7 @@ Most common testing is done in CI. Occasionally, and for each release, do perfor
 | 
				
			|||||||
- the application draws correctly
 | 
					- the application draws correctly
 | 
				
			||||||
- it shows when relevant
 | 
					- it shows when relevant
 | 
				
			||||||
- it changes layouts
 | 
					- it changes layouts
 | 
				
			||||||
- it changes levels
 | 
					- it changes views
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Testing with an application:
 | 
					Testing with an application:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -50,10 +50,8 @@ Testing layouts:
 | 
				
			|||||||
Layouts can be selected using the GNOME Settings application.
 | 
					Layouts can be selected using the GNOME Settings application.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
# define all available layouts
 | 
					# define all available layouts. First one is currently selected.
 | 
				
			||||||
$ gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'us'), ('xkb', 'ua')]"
 | 
					$ gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'us'), ('xkb', 'de')]"
 | 
				
			||||||
# choose the active layout
 | 
					 | 
				
			||||||
$ gsettings set org.gnome.desktop.input-sources current 1
 | 
					 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Coding
 | 
					Coding
 | 
				
			||||||
@ -114,7 +112,7 @@ Use the `cargo.sh` script for maintaining the Cargo part of the build. The scrip
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
cd build_dir
 | 
					cd build_dir
 | 
				
			||||||
sh /source_path/cargo.sh '' test
 | 
					sh /source_path/cargo.sh test
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Cargo dependencies
 | 
					### Cargo dependencies
 | 
				
			||||||
@ -125,6 +123,6 @@ Dependencies must be specified in `Cargo.toml` with 2 numbers: "major.minor". Si
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
cd build_dir
 | 
					cd build_dir
 | 
				
			||||||
sh /source_path/cargo.sh '' update
 | 
					sh /source_path/cargo.sh update
 | 
				
			||||||
ninja test
 | 
					ninja test
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										7
									
								
								cargo.sh
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								cargo.sh
									
									
									
									
									
								
							@ -11,14 +11,7 @@ SOURCE_DIR="$(dirname "$SCRIPT_PATH")"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
CARGO_TARGET_DIR="$(pwd)"
 | 
					CARGO_TARGET_DIR="$(pwd)"
 | 
				
			||||||
export CARGO_TARGET_DIR
 | 
					export CARGO_TARGET_DIR
 | 
				
			||||||
if [ -n "${1}" ]; then
 | 
					 | 
				
			||||||
    OUT_PATH="$(realpath "$1")"
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
cd "$SOURCE_DIR"
 | 
					cd "$SOURCE_DIR"
 | 
				
			||||||
shift
 | 
					 | 
				
			||||||
cargo "$@"
 | 
					cargo "$@"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if [ -n "${OUT_PATH}" ]; then
 | 
					 | 
				
			||||||
    cp "${CARGO_TARGET_DIR}"/debug/librs.a "${OUT_PATH}"
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										34
									
								
								cargo_build.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										34
									
								
								cargo_build.sh
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# This script manages Cargo builds
 | 
				
			||||||
 | 
					# 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")"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RELEASE=""
 | 
				
			||||||
 | 
					BINARY_DIR="debug"
 | 
				
			||||||
 | 
					if [ "${1}" = "--release" ]; then
 | 
				
			||||||
 | 
					    shift
 | 
				
			||||||
 | 
					    BINARY_DIR="release"
 | 
				
			||||||
 | 
					    RELEASE="--release"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ "${1}" = "--rename" ]; then
 | 
				
			||||||
 | 
					    shift
 | 
				
			||||||
 | 
					    FILENAME="${1}"
 | 
				
			||||||
 | 
					    shift
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					OUT_PATH="$(realpath "${1}")"
 | 
				
			||||||
 | 
					shift
 | 
				
			||||||
 | 
					OUT_BASENAME="$(basename "${OUT_PATH}")"
 | 
				
			||||||
 | 
					FILENAME="${FILENAME:-"${OUT_BASENAME}"}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sh "$SOURCE_DIR"/cargo.sh build $RELEASE "$@"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ -n "${OUT_PATH}" ]; then
 | 
				
			||||||
 | 
					    cp -a ./"${BINARY_DIR}"/"${FILENAME}" "${OUT_PATH}"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
@ -1,5 +1,4 @@
 | 
				
			|||||||
# German layout by Mark Müller
 | 
					# Maintained by: Mark Müller <markmueller86@gmail.com>
 | 
				
			||||||
# Version 2019111700
 | 
					 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
bounds: { x: 0, y: 1, width: 360, height: 208 }
 | 
					bounds: { x: 0, y: 1, width: 360, height: 208 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -83,7 +82,7 @@ buttons:
 | 
				
			|||||||
    space:
 | 
					    space:
 | 
				
			||||||
        outline: "spaceline"
 | 
					        outline: "spaceline"
 | 
				
			||||||
        label: " "
 | 
					        label: " "
 | 
				
			||||||
        keysym: "space"
 | 
					        text: " "
 | 
				
			||||||
    Return:
 | 
					    Return:
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        icon: "key-enter"
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										88
									
								
								data/keyboards/de_wide.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								data/keyboards/de_wide.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,88 @@
 | 
				
			|||||||
 | 
					# Maintained by: Mark Müller <markmueller86@gmail.com>
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					bounds: { x: 0, y: 1, width: 540, height: 168 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					outlines:
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        bounds: { x: 0, y: 0, width: 48, 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: 48, height: 42 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 preferences         space        , . 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 preferences         space        ! ? Return"
 | 
				
			||||||
 | 
					    numbers:
 | 
				
			||||||
 | 
					        - "1 2 3 4 5 6 7 8 9 0"
 | 
				
			||||||
 | 
					        - "@ # % & - _ + ( ) ß"
 | 
				
			||||||
 | 
					        - "show_symbols   , \" ' : = < >  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters preferences         space        , . Return"
 | 
				
			||||||
 | 
					    symbols:
 | 
				
			||||||
 | 
					        - "~ ` ´  · © ® ÷ × ¶"
 | 
				
			||||||
 | 
					        - "€ £ $ ¥ ^ ° * { } |"
 | 
				
			||||||
 | 
					        - "show_numbers   \\ / § π τ [ ]  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters preferences         space        , . Return"
 | 
				
			||||||
 | 
					    eschars:
 | 
				
			||||||
 | 
					        - "ä è é ö ü Ä È É Ö Ü"
 | 
				
			||||||
 | 
					        - "à â ê î ô À Â È Î Ô"
 | 
				
			||||||
 | 
					        - "show_numbers  « » ç Ç æ œ ß  BackSpace"
 | 
				
			||||||
 | 
					        - "show_letters preferences         space        „ “ Return"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					buttons:
 | 
				
			||||||
 | 
					    Shift_L:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            locking:
 | 
				
			||||||
 | 
					                lock_view: "upper"
 | 
				
			||||||
 | 
					                unlock_view: "base"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        icon: "key-shift"
 | 
				
			||||||
 | 
					    BackSpace:
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        icon: "edit-clear-symbolic"
 | 
				
			||||||
 | 
					        keysym: "BackSpace"
 | 
				
			||||||
 | 
					    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_eschars:
 | 
				
			||||||
 | 
					        action:
 | 
				
			||||||
 | 
					            locking:
 | 
				
			||||||
 | 
					                lock_view: "eschars"
 | 
				
			||||||
 | 
					                unlock_view: "base"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        label: "äÄ"
 | 
				
			||||||
 | 
					    space:
 | 
				
			||||||
 | 
					        outline: "spaceline"
 | 
				
			||||||
 | 
					        text: " "
 | 
				
			||||||
 | 
					    Return:
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
					        keysym: "Return"
 | 
				
			||||||
@ -53,6 +53,7 @@ buttons:
 | 
				
			|||||||
    BackSpace:
 | 
					    BackSpace:
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        icon: "edit-clear-symbolic"
 | 
					        icon: "edit-clear-symbolic"
 | 
				
			||||||
 | 
					        keysym: "BackSpace"
 | 
				
			||||||
    preferences:
 | 
					    preferences:
 | 
				
			||||||
        action: "show_prefs"
 | 
					        action: "show_prefs"
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
@ -86,111 +87,112 @@ buttons:
 | 
				
			|||||||
        label: "αι"
 | 
					        label: "αι"
 | 
				
			||||||
    period:
 | 
					    period:
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        label: "."
 | 
					        text: "."
 | 
				
			||||||
    space:
 | 
					    space:
 | 
				
			||||||
        outline: spaceline
 | 
					        outline: spaceline
 | 
				
			||||||
        label: " "
 | 
					        text: " "
 | 
				
			||||||
    Return:
 | 
					    Return:
 | 
				
			||||||
        outline: "wide"
 | 
					        outline: "wide"
 | 
				
			||||||
        icon: "key-enter"
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
					        keysym: "Return"
 | 
				
			||||||
    aring:
 | 
					    aring:
 | 
				
			||||||
        label: "å"
 | 
					        text: "å"
 | 
				
			||||||
    Aring:
 | 
					    Aring:
 | 
				
			||||||
        label: "Å"
 | 
					        text: "Å"
 | 
				
			||||||
    oslash:
 | 
					    oslash:
 | 
				
			||||||
        label: "ø"
 | 
					        text: "ø"
 | 
				
			||||||
    Oslash:
 | 
					    Oslash:
 | 
				
			||||||
        label: "Ø"
 | 
					        text: "Ø"
 | 
				
			||||||
    ae:
 | 
					    ae:
 | 
				
			||||||
        label: "æ"
 | 
					        text: "æ"
 | 
				
			||||||
    AE:
 | 
					    AE:
 | 
				
			||||||
        label: "Æ"
 | 
					        text: "Æ"
 | 
				
			||||||
    asterisk:
 | 
					    asterisk:
 | 
				
			||||||
        label: "*"
 | 
					        text: "*"
 | 
				
			||||||
    asciitilde:
 | 
					    asciitilde:
 | 
				
			||||||
        label: "~"
 | 
					        text: "~"
 | 
				
			||||||
    quoteleft:
 | 
					    quoteleft:
 | 
				
			||||||
        label: "`"
 | 
					        text: "`"
 | 
				
			||||||
    bar:
 | 
					    bar:
 | 
				
			||||||
        label: "|"
 | 
					        text: "|"
 | 
				
			||||||
    U00B7:
 | 
					    U00B7:
 | 
				
			||||||
        label: "·"
 | 
					        text: "·"
 | 
				
			||||||
    squareroot:
 | 
					    squareroot:
 | 
				
			||||||
        label: "√"
 | 
					        text: "√"
 | 
				
			||||||
    Greek_pi:
 | 
					    Greek_pi:
 | 
				
			||||||
        label: "π"
 | 
					        text: "π"
 | 
				
			||||||
    division:
 | 
					    division:
 | 
				
			||||||
        label: "÷"
 | 
					        text: "÷"
 | 
				
			||||||
    multiply:
 | 
					    multiply:
 | 
				
			||||||
        label: "×"
 | 
					        text: "×"
 | 
				
			||||||
    paragraph:
 | 
					    paragraph:
 | 
				
			||||||
        label: "¶"
 | 
					        text: "¶"
 | 
				
			||||||
    Greek_tau:
 | 
					    Greek_tau:
 | 
				
			||||||
        label: "τ"
 | 
					        text: "τ"
 | 
				
			||||||
    copyright:
 | 
					    copyright:
 | 
				
			||||||
        label: "©"
 | 
					        text: "©"
 | 
				
			||||||
    numbersign:
 | 
					    numbersign:
 | 
				
			||||||
        label: "#"
 | 
					        text: "#"
 | 
				
			||||||
    U00AE:
 | 
					    U00AE:
 | 
				
			||||||
        label: "®"
 | 
					        text: "®"
 | 
				
			||||||
    at:
 | 
					    at:
 | 
				
			||||||
        label: "@"
 | 
					        text: "@"
 | 
				
			||||||
    dollar:
 | 
					    dollar:
 | 
				
			||||||
        label: "$"
 | 
					        text: "$"
 | 
				
			||||||
    U00A3:
 | 
					    U00A3:
 | 
				
			||||||
        label: "£"
 | 
					        text: "£"
 | 
				
			||||||
    percent:
 | 
					    percent:
 | 
				
			||||||
        label: "%"
 | 
					        text: "%"
 | 
				
			||||||
    EuroSign:
 | 
					    EuroSign:
 | 
				
			||||||
        label: "€"
 | 
					        text: "€"
 | 
				
			||||||
    ampersand:
 | 
					    ampersand:
 | 
				
			||||||
        label: "&"
 | 
					        text: "&"
 | 
				
			||||||
    U00A5:
 | 
					    U00A5:
 | 
				
			||||||
        label: "¥"
 | 
					        text: "¥"
 | 
				
			||||||
    minus:
 | 
					    minus:
 | 
				
			||||||
        label: "-"
 | 
					        text: "-"
 | 
				
			||||||
    asciicircum:
 | 
					    asciicircum:
 | 
				
			||||||
        label: "^"
 | 
					        text: "^"
 | 
				
			||||||
    underscore:
 | 
					    underscore:
 | 
				
			||||||
        label: "_"
 | 
					        text: "_"
 | 
				
			||||||
    degree:
 | 
					    degree:
 | 
				
			||||||
        label: "°"
 | 
					        text: "°"
 | 
				
			||||||
    plus:
 | 
					    plus:
 | 
				
			||||||
        label: "+"
 | 
					        text: "+"
 | 
				
			||||||
    equal:
 | 
					    equal:
 | 
				
			||||||
        label: "="
 | 
					        text: "="
 | 
				
			||||||
    parenleft:
 | 
					    parenleft:
 | 
				
			||||||
        label: "("
 | 
					        text: "("
 | 
				
			||||||
    parenright:
 | 
					    parenright:
 | 
				
			||||||
        label: ")"
 | 
					        text: ")"
 | 
				
			||||||
    braceleft:
 | 
					    braceleft:
 | 
				
			||||||
        label: "{"
 | 
					        text: "{"
 | 
				
			||||||
    braceright:
 | 
					    braceright:
 | 
				
			||||||
        label: "}"
 | 
					        text: "}"
 | 
				
			||||||
    comma:
 | 
					    comma:
 | 
				
			||||||
        label: ","
 | 
					        text: ","
 | 
				
			||||||
    backslash:
 | 
					    backslash:
 | 
				
			||||||
        label: "\\"
 | 
					        text: "\\"
 | 
				
			||||||
    slash:
 | 
					    slash:
 | 
				
			||||||
        label: "/"
 | 
					        text: "/"
 | 
				
			||||||
    quotedbl:
 | 
					    quotedbl:
 | 
				
			||||||
        label: "\""
 | 
					        text: "\""
 | 
				
			||||||
    quoteright:
 | 
					    quoteright:
 | 
				
			||||||
        label: "'"
 | 
					        text: "'"
 | 
				
			||||||
    less:
 | 
					    less:
 | 
				
			||||||
        label: "<"
 | 
					        text: "<"
 | 
				
			||||||
    greater:
 | 
					    greater:
 | 
				
			||||||
        label: ">"
 | 
					        text: ">"
 | 
				
			||||||
    colon:
 | 
					    colon:
 | 
				
			||||||
        label: ":"
 | 
					        text: ":"
 | 
				
			||||||
    semicolon:
 | 
					    semicolon:
 | 
				
			||||||
        label: ";"
 | 
					        text: ";"
 | 
				
			||||||
    exclam:
 | 
					    exclam:
 | 
				
			||||||
        label: "!"
 | 
					        text: "!"
 | 
				
			||||||
    question:
 | 
					    question:
 | 
				
			||||||
        label: "?"
 | 
					        text: "?"
 | 
				
			||||||
    bracketleft:
 | 
					    bracketleft:
 | 
				
			||||||
        label: "["
 | 
					        text: "["
 | 
				
			||||||
    bracketright:
 | 
					    bracketright:
 | 
				
			||||||
        label: "]"
 | 
					        text: "]"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -51,6 +51,7 @@ buttons:
 | 
				
			|||||||
    BackSpace:
 | 
					    BackSpace:
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        icon: "edit-clear-symbolic"
 | 
					        icon: "edit-clear-symbolic"
 | 
				
			||||||
 | 
					        keysym: "BackSpace"
 | 
				
			||||||
    preferences:
 | 
					    preferences:
 | 
				
			||||||
        action: "show_prefs"
 | 
					        action: "show_prefs"
 | 
				
			||||||
        outline: "default"
 | 
					        outline: "default"
 | 
				
			||||||
@ -80,14 +81,14 @@ buttons:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    period:
 | 
					    period:
 | 
				
			||||||
        outline: "default"
 | 
					        outline: "default"
 | 
				
			||||||
        label: "."
 | 
					        text: "."
 | 
				
			||||||
    space:
 | 
					    space:
 | 
				
			||||||
        outline: "spaceline"
 | 
					        outline: "spaceline"
 | 
				
			||||||
        label: " "
 | 
					        text: " "
 | 
				
			||||||
    Return:
 | 
					    Return:
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        icon: "key-enter"
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
					        keysym: "Return"
 | 
				
			||||||
    colon:
 | 
					    colon:
 | 
				
			||||||
        label: ":"
 | 
					        text: ":"
 | 
				
			||||||
    "\"":
 | 
					
 | 
				
			||||||
        keysym: "quotedbl"
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -46,6 +46,7 @@ buttons:
 | 
				
			|||||||
    BackSpace:
 | 
					    BackSpace:
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        icon: "edit-clear-symbolic"
 | 
					        icon: "edit-clear-symbolic"
 | 
				
			||||||
 | 
					        keysym: "BackSpace"
 | 
				
			||||||
    preferences:
 | 
					    preferences:
 | 
				
			||||||
        action: "show_prefs"
 | 
					        action: "show_prefs"
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
@ -69,108 +70,109 @@ buttons:
 | 
				
			|||||||
        outline: altline
 | 
					        outline: altline
 | 
				
			||||||
    space:
 | 
					    space:
 | 
				
			||||||
        outline: spaceline
 | 
					        outline: spaceline
 | 
				
			||||||
        label: " "
 | 
					        text: " "
 | 
				
			||||||
    Return:
 | 
					    Return:
 | 
				
			||||||
        outline: "wide"
 | 
					        outline: "wide"
 | 
				
			||||||
        icon: "key-enter"
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
					        keysym: "Return"
 | 
				
			||||||
    aring:
 | 
					    aring:
 | 
				
			||||||
        label: "å"
 | 
					        text: "å"
 | 
				
			||||||
    Aring:
 | 
					    Aring:
 | 
				
			||||||
        label: "Å"
 | 
					        text: "Å"
 | 
				
			||||||
    ouml:
 | 
					    ouml:
 | 
				
			||||||
        label: "ö"
 | 
					        text: "ö"
 | 
				
			||||||
    Ouml:
 | 
					    Ouml:
 | 
				
			||||||
        label: "Ö"
 | 
					        text: "Ö"
 | 
				
			||||||
    auml:
 | 
					    auml:
 | 
				
			||||||
        label: "ä"
 | 
					        text: "ä"
 | 
				
			||||||
    Auml:
 | 
					    Auml:
 | 
				
			||||||
        label: "Ä"
 | 
					        text: "Ä"
 | 
				
			||||||
    asterisk:
 | 
					    asterisk:
 | 
				
			||||||
        label: "*"
 | 
					        text: "*"
 | 
				
			||||||
    asciitilde:
 | 
					    asciitilde:
 | 
				
			||||||
        label: "~"
 | 
					        text: "~"
 | 
				
			||||||
    quoteleft:
 | 
					    quoteleft:
 | 
				
			||||||
        label: "`"
 | 
					        text: "`"
 | 
				
			||||||
    bar:
 | 
					    bar:
 | 
				
			||||||
        label: "|"
 | 
					        text: "|"
 | 
				
			||||||
    U00B7:
 | 
					    U00B7:
 | 
				
			||||||
        label: "·"
 | 
					        text: "·"
 | 
				
			||||||
    squareroot:
 | 
					    squareroot:
 | 
				
			||||||
        label: "√"
 | 
					        text: "√"
 | 
				
			||||||
    Greek_pi:
 | 
					    Greek_pi:
 | 
				
			||||||
        label: "π"
 | 
					        text: "π"
 | 
				
			||||||
    division:
 | 
					    division:
 | 
				
			||||||
        label: "÷"
 | 
					        text: "÷"
 | 
				
			||||||
    multiply:
 | 
					    multiply:
 | 
				
			||||||
        label: "×"
 | 
					        text: "×"
 | 
				
			||||||
    paragraph:
 | 
					    paragraph:
 | 
				
			||||||
        label: "¶"
 | 
					        text: "¶"
 | 
				
			||||||
    Greek_tau:
 | 
					    Greek_tau:
 | 
				
			||||||
        label: "τ"
 | 
					        text: "τ"
 | 
				
			||||||
    copyright:
 | 
					    copyright:
 | 
				
			||||||
        label: "©"
 | 
					        text: "©"
 | 
				
			||||||
    numbersign:
 | 
					    numbersign:
 | 
				
			||||||
        label: "#"
 | 
					        text: "#"
 | 
				
			||||||
    U00AE:
 | 
					    U00AE:
 | 
				
			||||||
        label: "®"
 | 
					        text: "®"
 | 
				
			||||||
    at:
 | 
					    at:
 | 
				
			||||||
        label: "@"
 | 
					        text: "@"
 | 
				
			||||||
    dollar:
 | 
					    dollar:
 | 
				
			||||||
        label: "$"
 | 
					        text: "$"
 | 
				
			||||||
    U00A3:
 | 
					    U00A3:
 | 
				
			||||||
        label: "£"
 | 
					        text: "£"
 | 
				
			||||||
    percent:
 | 
					    percent:
 | 
				
			||||||
        label: "%"
 | 
					        text: "%"
 | 
				
			||||||
    EuroSign:
 | 
					    EuroSign:
 | 
				
			||||||
        label: "€"
 | 
					        text: "€"
 | 
				
			||||||
    ampersand:
 | 
					    ampersand:
 | 
				
			||||||
        label: "&"
 | 
					        text: "&"
 | 
				
			||||||
    U00A5:
 | 
					    U00A5:
 | 
				
			||||||
        label: "¥"
 | 
					        text: "¥"
 | 
				
			||||||
    minus:
 | 
					    minus:
 | 
				
			||||||
        label: "-"
 | 
					        text: "-"
 | 
				
			||||||
    asciicircum:
 | 
					    asciicircum:
 | 
				
			||||||
        label: "^"
 | 
					        text: "^"
 | 
				
			||||||
    underscore:
 | 
					    underscore:
 | 
				
			||||||
        label: "_"
 | 
					        text: "_"
 | 
				
			||||||
    degree:
 | 
					    degree:
 | 
				
			||||||
        label: "°"
 | 
					        text: "°"
 | 
				
			||||||
    plus:
 | 
					    plus:
 | 
				
			||||||
        label: "+"
 | 
					        text: "+"
 | 
				
			||||||
    equal:
 | 
					    equal:
 | 
				
			||||||
        label: "="
 | 
					        text: "="
 | 
				
			||||||
    parenleft:
 | 
					    parenleft:
 | 
				
			||||||
        label: "("
 | 
					        text: "("
 | 
				
			||||||
    parenright:
 | 
					    parenright:
 | 
				
			||||||
        label: ")"
 | 
					        text: ")"
 | 
				
			||||||
    braceleft:
 | 
					    braceleft:
 | 
				
			||||||
        label: "{"
 | 
					        text: "{"
 | 
				
			||||||
    braceright:
 | 
					    braceright:
 | 
				
			||||||
        label: "}"
 | 
					        text: "}"
 | 
				
			||||||
    comma:
 | 
					    comma:
 | 
				
			||||||
        label: ","
 | 
					        text: ","
 | 
				
			||||||
    backslash:
 | 
					    backslash:
 | 
				
			||||||
        label: "\\"
 | 
					        text: "\\"
 | 
				
			||||||
    slash:
 | 
					    slash:
 | 
				
			||||||
        label: "/"
 | 
					        text: "/"
 | 
				
			||||||
    quotedbl:
 | 
					    quotedbl:
 | 
				
			||||||
        label: "\""
 | 
					        text: "\""
 | 
				
			||||||
    quoteright:
 | 
					    quoteright:
 | 
				
			||||||
        label: "'"
 | 
					        text: "'"
 | 
				
			||||||
    less:
 | 
					    less:
 | 
				
			||||||
        label: "<"
 | 
					        text: "<"
 | 
				
			||||||
    greater:
 | 
					    greater:
 | 
				
			||||||
        label: ">"
 | 
					        text: ">"
 | 
				
			||||||
    colon:
 | 
					    colon:
 | 
				
			||||||
        label: ":"
 | 
					        text: ":"
 | 
				
			||||||
    semicolon:
 | 
					    semicolon:
 | 
				
			||||||
        label: ";"
 | 
					        text: ";"
 | 
				
			||||||
    exclam:
 | 
					    exclam:
 | 
				
			||||||
        label: "!"
 | 
					        text: "!"
 | 
				
			||||||
    question:
 | 
					    question:
 | 
				
			||||||
        label: "?"
 | 
					        text: "?"
 | 
				
			||||||
    bracketleft:
 | 
					    bracketleft:
 | 
				
			||||||
        label: "["
 | 
					        text: "["
 | 
				
			||||||
    bracketright:
 | 
					    bracketright:
 | 
				
			||||||
        label: "]"
 | 
					        text: "]"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -53,6 +53,7 @@ buttons:
 | 
				
			|||||||
    BackSpace:
 | 
					    BackSpace:
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        icon: "edit-clear-symbolic"
 | 
					        icon: "edit-clear-symbolic"
 | 
				
			||||||
 | 
					        keysym: "BackSpace"
 | 
				
			||||||
    preferences:
 | 
					    preferences:
 | 
				
			||||||
        action: "show_prefs"
 | 
					        action: "show_prefs"
 | 
				
			||||||
        outline: "default"
 | 
					        outline: "default"
 | 
				
			||||||
@ -91,6 +92,7 @@ buttons:
 | 
				
			|||||||
    Return:
 | 
					    Return:
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        icon: "key-enter"
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
					        keysym: "Return"
 | 
				
			||||||
    colon:
 | 
					    colon:
 | 
				
			||||||
        label: ":"
 | 
					        label: ":"
 | 
				
			||||||
    "\"":
 | 
					    "\"":
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,4 @@
 | 
				
			|||||||
# Japanese Kana layout by Mark Müller
 | 
					# Maintained by: Mark Müller <markmueller86@gmail.com>
 | 
				
			||||||
# Version 2019111800
 | 
					 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
bounds: { x: 0, y: 1, width: 360, height: 208 }
 | 
					bounds: { x: 0, y: 1, width: 360, height: 208 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -221,11 +220,11 @@ buttons:
 | 
				
			|||||||
        action: "show_prefs"
 | 
					        action: "show_prefs"
 | 
				
			||||||
        outline: "special"
 | 
					        outline: "special"
 | 
				
			||||||
        icon: "keyboard-mode-symbolic"
 | 
					        icon: "keyboard-mode-symbolic"
 | 
				
			||||||
    # space button with unicode keysym for ideographic space
 | 
					    # space button using text tag for ideographic space
 | 
				
			||||||
    space:
 | 
					    space:
 | 
				
			||||||
        outline: "default-wide"
 | 
					        outline: "default-wide"
 | 
				
			||||||
        label: "␣"
 | 
					        label: "␣"
 | 
				
			||||||
        keysym: "U3000"
 | 
					        text: " "
 | 
				
			||||||
    # switch to number view
 | 
					    # switch to number view
 | 
				
			||||||
    numbers:
 | 
					    numbers:
 | 
				
			||||||
        action:
 | 
					        action:
 | 
				
			||||||
 | 
				
			|||||||
@ -26,13 +26,13 @@ views:
 | 
				
			|||||||
        - "show_numbers preferences         space        .    Return"
 | 
					        - "show_numbers preferences         space        .    Return"
 | 
				
			||||||
    numbers:
 | 
					    numbers:
 | 
				
			||||||
        - "1 2 3 4 5 6 7 8 9 0"
 | 
					        - "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_symbols   , \" ' : ; ! ?  BackSpace"
 | 
				
			||||||
        - "show_letters preferences         space        .    Return"
 | 
					        - "show_letters preferences         space        .    Return"
 | 
				
			||||||
    symbols:
 | 
					    symbols:
 | 
				
			||||||
        - "asciitilde quoteleft bar U00B7 squareroot Greek_pi Greek_tau division multiply paragraph"
 | 
					        - "~ ` | U00B7 squareroot Greek_pi Greek_tau division multiply paragraph"
 | 
				
			||||||
        - "copyright U00AE U00A3 EuroSign U00A5 asciicircum degree asterisk braceleft braceright"
 | 
					        - "copyright U00AE U00A3 EuroSign U00A5 asciicircum degree * { }"
 | 
				
			||||||
        - "show_numbers   backslash slash less greater equal bracketleft bracketright  BackSpace"
 | 
					        - "show_numbers   \\ / < > = [ ]  BackSpace"
 | 
				
			||||||
        - "show_letters preferences         space        .    Return"
 | 
					        - "show_letters preferences         space        .    Return"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
buttons:
 | 
					buttons:
 | 
				
			||||||
@ -46,6 +46,7 @@ buttons:
 | 
				
			|||||||
    BackSpace:
 | 
					    BackSpace:
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        icon: "edit-clear-symbolic"
 | 
					        icon: "edit-clear-symbolic"
 | 
				
			||||||
 | 
					        keysym: "BackSpace"
 | 
				
			||||||
    preferences:
 | 
					    preferences:
 | 
				
			||||||
        action: "show_prefs"
 | 
					        action: "show_prefs"
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
@ -69,108 +70,37 @@ buttons:
 | 
				
			|||||||
        outline: altline
 | 
					        outline: altline
 | 
				
			||||||
    space:
 | 
					    space:
 | 
				
			||||||
        outline: spaceline
 | 
					        outline: spaceline
 | 
				
			||||||
        label: " "
 | 
					        text: " "
 | 
				
			||||||
    Return:
 | 
					    Return:
 | 
				
			||||||
        outline: "wide"
 | 
					        outline: "wide"
 | 
				
			||||||
        icon: "key-enter"
 | 
					        icon: "key-enter"
 | 
				
			||||||
    aring:
 | 
					        keysym: "Return"
 | 
				
			||||||
        label: "å"
 | 
					 | 
				
			||||||
    Aring:
 | 
					 | 
				
			||||||
        label: "Å"
 | 
					 | 
				
			||||||
    oslash:
 | 
					 | 
				
			||||||
        label: "ø"
 | 
					 | 
				
			||||||
    Oslash:
 | 
					 | 
				
			||||||
        label: "Ø"
 | 
					 | 
				
			||||||
    ae:
 | 
					 | 
				
			||||||
        label: "æ"
 | 
					 | 
				
			||||||
    AE:
 | 
					 | 
				
			||||||
        label: "Æ"
 | 
					 | 
				
			||||||
    asterisk:
 | 
					 | 
				
			||||||
        label: "*"
 | 
					 | 
				
			||||||
    asciitilde:
 | 
					 | 
				
			||||||
        label: "~"
 | 
					 | 
				
			||||||
    quoteleft:
 | 
					 | 
				
			||||||
        label: "`"
 | 
					 | 
				
			||||||
    bar:
 | 
					 | 
				
			||||||
        label: "|"
 | 
					 | 
				
			||||||
    U00B7:
 | 
					    U00B7:
 | 
				
			||||||
        label: "·"
 | 
					        text: "·"
 | 
				
			||||||
    squareroot:
 | 
					    squareroot:
 | 
				
			||||||
        label: "√"
 | 
					        text: "√"
 | 
				
			||||||
    Greek_pi:
 | 
					    Greek_pi:
 | 
				
			||||||
        label: "π"
 | 
					        text: "π"
 | 
				
			||||||
    division:
 | 
					    division:
 | 
				
			||||||
        label: "÷"
 | 
					        text: "÷"
 | 
				
			||||||
    multiply:
 | 
					    multiply:
 | 
				
			||||||
        label: "×"
 | 
					        text: "×"
 | 
				
			||||||
    paragraph:
 | 
					    paragraph:
 | 
				
			||||||
        label: "¶"
 | 
					        text: "¶"
 | 
				
			||||||
    Greek_tau:
 | 
					    Greek_tau:
 | 
				
			||||||
        label: "τ"
 | 
					        text: "τ"
 | 
				
			||||||
    copyright:
 | 
					    copyright:
 | 
				
			||||||
        label: "©"
 | 
					        text: "©"
 | 
				
			||||||
    numbersign:
 | 
					 | 
				
			||||||
        label: "#"
 | 
					 | 
				
			||||||
    U00AE:
 | 
					    U00AE:
 | 
				
			||||||
        label: "®"
 | 
					        text: "®"
 | 
				
			||||||
    at:
 | 
					 | 
				
			||||||
        label: "@"
 | 
					 | 
				
			||||||
    dollar:
 | 
					 | 
				
			||||||
        label: "$"
 | 
					 | 
				
			||||||
    U00A3:
 | 
					    U00A3:
 | 
				
			||||||
        label: "£"
 | 
					        text: "£"
 | 
				
			||||||
    percent:
 | 
					 | 
				
			||||||
        label: "%"
 | 
					 | 
				
			||||||
    EuroSign:
 | 
					    EuroSign:
 | 
				
			||||||
        label: "€"
 | 
					        text: "€"
 | 
				
			||||||
    ampersand:
 | 
					 | 
				
			||||||
        label: "&"
 | 
					 | 
				
			||||||
    U00A5:
 | 
					    U00A5:
 | 
				
			||||||
        label: "¥"
 | 
					        text: "¥"
 | 
				
			||||||
    minus:
 | 
					 | 
				
			||||||
        label: "-"
 | 
					 | 
				
			||||||
    asciicircum:
 | 
					    asciicircum:
 | 
				
			||||||
        label: "^"
 | 
					        text: "^"
 | 
				
			||||||
    underscore:
 | 
					 | 
				
			||||||
        label: "_"
 | 
					 | 
				
			||||||
    degree:
 | 
					    degree:
 | 
				
			||||||
        label: "°"
 | 
					        text: "°"
 | 
				
			||||||
    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: "]"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -22,22 +22,24 @@ buttons:
 | 
				
			|||||||
    BackSpace:
 | 
					    BackSpace:
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        icon: "edit-clear-symbolic"
 | 
					        icon: "edit-clear-symbolic"
 | 
				
			||||||
 | 
					        keysym: "BackSpace"
 | 
				
			||||||
    space:
 | 
					    space:
 | 
				
			||||||
        outline: spaceline
 | 
					        outline: spaceline
 | 
				
			||||||
        label: " "
 | 
					        text: " "
 | 
				
			||||||
    Return:
 | 
					    Return:
 | 
				
			||||||
        outline: outline7
 | 
					        outline: outline7
 | 
				
			||||||
        icon: "key-enter"
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
					        keysym: "BackSpace"
 | 
				
			||||||
    asterisk:
 | 
					    asterisk:
 | 
				
			||||||
        label: "*"
 | 
					        text: "*"
 | 
				
			||||||
    numbersign:
 | 
					    numbersign:
 | 
				
			||||||
        label: "#"
 | 
					        text: "#"
 | 
				
			||||||
    minus:
 | 
					    minus:
 | 
				
			||||||
        label: "-"
 | 
					        text: "-"
 | 
				
			||||||
    plus:
 | 
					    plus:
 | 
				
			||||||
        label: "+"
 | 
					        text: "+"
 | 
				
			||||||
    parenleft:
 | 
					    parenleft:
 | 
				
			||||||
        label: "("
 | 
					        text: "("
 | 
				
			||||||
    parenright:
 | 
					    parenright:
 | 
				
			||||||
        label: ")"
 | 
					        text: ")"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -46,6 +46,7 @@ buttons:
 | 
				
			|||||||
    BackSpace:
 | 
					    BackSpace:
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        icon: "edit-clear-symbolic"
 | 
					        icon: "edit-clear-symbolic"
 | 
				
			||||||
 | 
					        keysym: "BackSpace"
 | 
				
			||||||
    preferences:
 | 
					    preferences:
 | 
				
			||||||
        action: "show_prefs"
 | 
					        action: "show_prefs"
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
@ -69,96 +70,97 @@ buttons:
 | 
				
			|||||||
        outline: altline
 | 
					        outline: altline
 | 
				
			||||||
    space:
 | 
					    space:
 | 
				
			||||||
        outline: spaceline
 | 
					        outline: spaceline
 | 
				
			||||||
        label: " "
 | 
					        text: " "
 | 
				
			||||||
    Return:
 | 
					    Return:
 | 
				
			||||||
        outline: "wide"
 | 
					        outline: "wide"
 | 
				
			||||||
        icon: "key-enter"
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
					        keysym: "Return"
 | 
				
			||||||
    asterisk:
 | 
					    asterisk:
 | 
				
			||||||
        label: "*"
 | 
					        text: "*"
 | 
				
			||||||
    asciitilde:
 | 
					    asciitilde:
 | 
				
			||||||
        label: "~"
 | 
					        text: "~"
 | 
				
			||||||
    quoteleft:
 | 
					    quoteleft:
 | 
				
			||||||
        label: "`"
 | 
					        text: "`"
 | 
				
			||||||
    bar:
 | 
					    bar:
 | 
				
			||||||
        label: "|"
 | 
					        text: "|"
 | 
				
			||||||
    U00B7:
 | 
					    U00B7:
 | 
				
			||||||
        label: "·"
 | 
					        text: "·"
 | 
				
			||||||
    squareroot:
 | 
					    squareroot:
 | 
				
			||||||
        label: "√"
 | 
					        text: "√"
 | 
				
			||||||
    Greek_pi:
 | 
					    Greek_pi:
 | 
				
			||||||
        label: "π"
 | 
					        text: "π"
 | 
				
			||||||
    division:
 | 
					    division:
 | 
				
			||||||
        label: "÷"
 | 
					        text: "÷"
 | 
				
			||||||
    multiply:
 | 
					    multiply:
 | 
				
			||||||
        label: "×"
 | 
					        text: "×"
 | 
				
			||||||
    paragraph:
 | 
					    paragraph:
 | 
				
			||||||
        label: "¶"
 | 
					        text: "¶"
 | 
				
			||||||
    Greek_tau:
 | 
					    Greek_tau:
 | 
				
			||||||
        label: "τ"
 | 
					        text: "τ"
 | 
				
			||||||
    copyright:
 | 
					    copyright:
 | 
				
			||||||
        label: "©"
 | 
					        text: "©"
 | 
				
			||||||
    numbersign:
 | 
					    numbersign:
 | 
				
			||||||
        label: "#"
 | 
					        text: "#"
 | 
				
			||||||
    U00AE:
 | 
					    U00AE:
 | 
				
			||||||
        label: "®"
 | 
					        text: "®"
 | 
				
			||||||
    at:
 | 
					    at:
 | 
				
			||||||
        label: "@"
 | 
					        text: "@"
 | 
				
			||||||
    dollar:
 | 
					    dollar:
 | 
				
			||||||
        label: "$"
 | 
					        text: "$"
 | 
				
			||||||
    U00A3:
 | 
					    U00A3:
 | 
				
			||||||
        label: "£"
 | 
					        text: "£"
 | 
				
			||||||
    percent:
 | 
					    percent:
 | 
				
			||||||
        label: "%"
 | 
					        text: "%"
 | 
				
			||||||
    EuroSign:
 | 
					    EuroSign:
 | 
				
			||||||
        label: "€"
 | 
					        text: "€"
 | 
				
			||||||
    ampersand:
 | 
					    ampersand:
 | 
				
			||||||
        label: "&"
 | 
					        text: "&"
 | 
				
			||||||
    U00A5:
 | 
					    U00A5:
 | 
				
			||||||
        label: "¥"
 | 
					        text: "¥"
 | 
				
			||||||
    minus:
 | 
					    minus:
 | 
				
			||||||
        label: "-"
 | 
					        text: "-"
 | 
				
			||||||
    asciicircum:
 | 
					    asciicircum:
 | 
				
			||||||
        label: "^"
 | 
					        text: "^"
 | 
				
			||||||
    underscore:
 | 
					    underscore:
 | 
				
			||||||
        label: "_"
 | 
					        text: "_"
 | 
				
			||||||
    degree:
 | 
					    degree:
 | 
				
			||||||
        label: "°"
 | 
					        text: "°"
 | 
				
			||||||
    plus:
 | 
					    plus:
 | 
				
			||||||
        label: "+"
 | 
					        text: "+"
 | 
				
			||||||
    equal:
 | 
					    equal:
 | 
				
			||||||
        label: "="
 | 
					        text: "="
 | 
				
			||||||
    parenleft:
 | 
					    parenleft:
 | 
				
			||||||
        label: "("
 | 
					        text: "("
 | 
				
			||||||
    parenright:
 | 
					    parenright:
 | 
				
			||||||
        label: ")"
 | 
					        text: ")"
 | 
				
			||||||
    braceleft:
 | 
					    braceleft:
 | 
				
			||||||
        label: "{"
 | 
					        text: "{"
 | 
				
			||||||
    braceright:
 | 
					    braceright:
 | 
				
			||||||
        label: "}"
 | 
					        text: "}"
 | 
				
			||||||
    comma:
 | 
					    comma:
 | 
				
			||||||
        label: ","
 | 
					        text: ","
 | 
				
			||||||
    backslash:
 | 
					    backslash:
 | 
				
			||||||
        label: "\\"
 | 
					        text: "\\"
 | 
				
			||||||
    slash:
 | 
					    slash:
 | 
				
			||||||
        label: "/"
 | 
					        text: "/"
 | 
				
			||||||
    quotedbl:
 | 
					    quotedbl:
 | 
				
			||||||
        label: "\""
 | 
					        text: "\""
 | 
				
			||||||
    quoteright:
 | 
					    quoteright:
 | 
				
			||||||
        label: "'"
 | 
					        text: "'"
 | 
				
			||||||
    less:
 | 
					    less:
 | 
				
			||||||
        label: "<"
 | 
					        text: "<"
 | 
				
			||||||
    greater:
 | 
					    greater:
 | 
				
			||||||
        label: ">"
 | 
					        text: ">"
 | 
				
			||||||
    colon:
 | 
					    colon:
 | 
				
			||||||
        label: ":"
 | 
					        text: ":"
 | 
				
			||||||
    semicolon:
 | 
					    semicolon:
 | 
				
			||||||
        label: ";"
 | 
					        text: ";"
 | 
				
			||||||
    exclam:
 | 
					    exclam:
 | 
				
			||||||
        label: "!"
 | 
					        text: "!"
 | 
				
			||||||
    question:
 | 
					    question:
 | 
				
			||||||
        label: "?"
 | 
					        text: "?"
 | 
				
			||||||
    bracketleft:
 | 
					    bracketleft:
 | 
				
			||||||
        label: "["
 | 
					        text: "["
 | 
				
			||||||
    bracketright:
 | 
					    bracketright:
 | 
				
			||||||
        label: "]"
 | 
					        text: "]"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -46,6 +46,7 @@ buttons:
 | 
				
			|||||||
    BackSpace:
 | 
					    BackSpace:
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        icon: "edit-clear-symbolic"
 | 
					        icon: "edit-clear-symbolic"
 | 
				
			||||||
 | 
					        keysym: "BackSpace"
 | 
				
			||||||
    preferences:
 | 
					    preferences:
 | 
				
			||||||
        action: "show_prefs"
 | 
					        action: "show_prefs"
 | 
				
			||||||
        outline: "special"
 | 
					        outline: "special"
 | 
				
			||||||
@ -72,14 +73,13 @@ buttons:
 | 
				
			|||||||
        label: "*/="
 | 
					        label: "*/="
 | 
				
			||||||
    period:
 | 
					    period:
 | 
				
			||||||
        outline: "special"
 | 
					        outline: "special"
 | 
				
			||||||
        label: "."
 | 
					        text: "."
 | 
				
			||||||
    space:
 | 
					    space:
 | 
				
			||||||
        outline: "spaceline"
 | 
					        outline: "spaceline"
 | 
				
			||||||
        label: " "
 | 
					        text: " "
 | 
				
			||||||
    Return:
 | 
					    Return:
 | 
				
			||||||
        outline: "wide"
 | 
					        outline: "wide"
 | 
				
			||||||
        icon: "key-enter"
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
					        keysym: "Return"
 | 
				
			||||||
    colon:
 | 
					    colon:
 | 
				
			||||||
        label: ":"
 | 
					        text: ":"
 | 
				
			||||||
    "\"":
 | 
					 | 
				
			||||||
        keysym: "quotedbl"
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -18,22 +18,22 @@ views:
 | 
				
			|||||||
        - "q w e r t y u i o p"
 | 
					        - "q w e r t y u i o p"
 | 
				
			||||||
        - "a s d f g h j k l"
 | 
					        - "a s d f g h j k l"
 | 
				
			||||||
        - "Shift_L   z x c v b n m  BackSpace"
 | 
					        - "Shift_L   z x c v b n m  BackSpace"
 | 
				
			||||||
        - "show_numbers preferences         space        period Return"
 | 
					        - "show_numbers preferences         space        . Return"
 | 
				
			||||||
    upper:
 | 
					    upper:
 | 
				
			||||||
        - "Q W E R T Y U I O P"
 | 
					        - "Q W E R T Y U I O P"
 | 
				
			||||||
        - "A S D F G H J K L"
 | 
					        - "A S D F G H J K L"
 | 
				
			||||||
        - "Shift_L   Z X C V B N M  BackSpace"
 | 
					        - "Shift_L   Z X C V B N M  BackSpace"
 | 
				
			||||||
        - "show_numbers preferences         space        period Return"
 | 
					        - "show_numbers preferences         space        . Return"
 | 
				
			||||||
    numbers:
 | 
					    numbers:
 | 
				
			||||||
        - "1 2 3 4 5 6 7 8 9 0"
 | 
					        - "1 2 3 4 5 6 7 8 9 0"
 | 
				
			||||||
        - "@ # $ % & - _ + ( )"
 | 
					        - "@ # $ % & - _ + ( )"
 | 
				
			||||||
        - "show_symbols   , \" ' colon ; ! ?  BackSpace"
 | 
					        - "show_symbols   , \" ' colon ; ! ?  BackSpace"
 | 
				
			||||||
        - "show_letters preferences         space        period Return"
 | 
					        - "show_letters preferences         space        . Return"
 | 
				
			||||||
    symbols:
 | 
					    symbols:
 | 
				
			||||||
        - "~ ` | · √ π τ ÷ × ¶"
 | 
					        - "~ ` | · √ π τ ÷ × ¶"
 | 
				
			||||||
        - "© ® £ € ¥ ^ ° * { }"
 | 
					        - "© ® £ € ¥ ^ ° * { }"
 | 
				
			||||||
        - "show_numbers_from_symbols   \\ / < > = [ ]  BackSpace"
 | 
					        - "show_numbers_from_symbols   \\ / < > = [ ]  BackSpace"
 | 
				
			||||||
        - "show_letters preferences         space        period Return"
 | 
					        - "show_letters preferences         space        . Return"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
buttons:
 | 
					buttons:
 | 
				
			||||||
    Shift_L:
 | 
					    Shift_L:
 | 
				
			||||||
@ -46,6 +46,7 @@ buttons:
 | 
				
			|||||||
    BackSpace:
 | 
					    BackSpace:
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        icon: "edit-clear-symbolic"
 | 
					        icon: "edit-clear-symbolic"
 | 
				
			||||||
 | 
					        keysym: "BackSpace"
 | 
				
			||||||
    preferences:
 | 
					    preferences:
 | 
				
			||||||
        action: "show_prefs"
 | 
					        action: "show_prefs"
 | 
				
			||||||
        outline: "special"
 | 
					        outline: "special"
 | 
				
			||||||
@ -70,16 +71,15 @@ buttons:
 | 
				
			|||||||
            set_view: "symbols"
 | 
					            set_view: "symbols"
 | 
				
			||||||
        outline: "altline"
 | 
					        outline: "altline"
 | 
				
			||||||
        label: "*/="
 | 
					        label: "*/="
 | 
				
			||||||
    period:
 | 
					    ".":
 | 
				
			||||||
        outline: "special"
 | 
					        outline: "special"
 | 
				
			||||||
        label: "."
 | 
					        text: "."
 | 
				
			||||||
    space:
 | 
					    space:
 | 
				
			||||||
        outline: "spaceline"
 | 
					        outline: "spaceline"
 | 
				
			||||||
        label: " "
 | 
					        text: " "
 | 
				
			||||||
    Return:
 | 
					    Return:
 | 
				
			||||||
        outline: "wide"
 | 
					        outline: "wide"
 | 
				
			||||||
        icon: "key-enter"
 | 
					        icon: "key-enter"
 | 
				
			||||||
 | 
					        keysym: "Return"
 | 
				
			||||||
    colon:
 | 
					    colon:
 | 
				
			||||||
        label: ":"
 | 
					        text: ":"
 | 
				
			||||||
    "\"":
 | 
					 | 
				
			||||||
        keysym: "quotedbl"
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										8
									
								
								data/langs/ja-JP.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								data/langs/ja-JP.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					us 英語 (US)
 | 
				
			||||||
 | 
					de ドイツ語
 | 
				
			||||||
 | 
					el ギリシャ語
 | 
				
			||||||
 | 
					es スペイン語
 | 
				
			||||||
 | 
					it イタリア語
 | 
				
			||||||
 | 
					jp+kana 日本語 (かな)
 | 
				
			||||||
 | 
					nb ノルウェー語
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2,6 +2,7 @@
 | 
				
			|||||||
<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">style-Adwaita:dark.css</file>
 | 
				
			||||||
   <file compressed="true" preprocess="xml-stripblanks">popup.ui</file>
 | 
					   <file compressed="true" preprocess="xml-stripblanks">popup.ui</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>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										46
									
								
								data/style-Adwaita:dark.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								data/style-Adwaita:dark.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					sq_view {
 | 
				
			||||||
 | 
					    background-color: rgba(0, 0, 0, 255);
 | 
				
			||||||
 | 
					    color: #ffffff;
 | 
				
			||||||
 | 
					    font-family: cantarell, sans-serif;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sq_view sq_button {
 | 
				
			||||||
 | 
					    color: #deddda;
 | 
				
			||||||
 | 
					    background: #464448;
 | 
				
			||||||
 | 
					    border-style: solid;
 | 
				
			||||||
 | 
					    border-width: 1px;
 | 
				
			||||||
 | 
					    border-color: #5e5c64;
 | 
				
			||||||
 | 
					    border-radius: 3px;
 | 
				
			||||||
 | 
					    margin: 4px 2px 4px 2px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sq_view.wide sq_button {
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					    border-color: #3584e4;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,15 +1,15 @@
 | 
				
			|||||||
sq_view {
 | 
					sq_view {
 | 
				
			||||||
    background-color: rgba(0, 0, 0, 255);
 | 
					    background-color: @theme_base_color; /*rgba(0, 0, 0, 255);*/
 | 
				
			||||||
    color: #ffffff;
 | 
					    color: @theme_text_color; /*#ffffff;*/
 | 
				
			||||||
    font-family: cantarell, sans-serif;
 | 
					    font-family: cantarell, sans-serif;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sq_view sq_button {
 | 
					sq_view sq_button {
 | 
				
			||||||
    color: #deddda;
 | 
					    color: @theme_fg_color; /*#deddda;*/
 | 
				
			||||||
    background: #464448;
 | 
					    background: mix(@theme_bg_color, @theme_base_color, -0.5); /* #464448; */
 | 
				
			||||||
    border-style: solid;
 | 
					    border-style: solid;
 | 
				
			||||||
    border-width: 1px;
 | 
					    border-width: 1px;
 | 
				
			||||||
    border-color: #5e5c64;
 | 
					    border-color: @borders; /* #5e5c64;*/
 | 
				
			||||||
    border-radius: 3px;
 | 
					    border-radius: 3px;
 | 
				
			||||||
    margin: 4px 2px 4px 2px;
 | 
					    margin: 4px 2px 4px 2px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -18,29 +18,32 @@ sq_view.wide sq_button {
 | 
				
			|||||||
    margin: 1px 1px 1px 1px;
 | 
					    margin: 1px 1px 1px 1px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sq_button:active {
 | 
					sq_button:active,
 | 
				
			||||||
    background: #747077;
 | 
					sq_button.altline:active,
 | 
				
			||||||
    border-color: #96949d;
 | 
					sq_button.special:active,
 | 
				
			||||||
 | 
					sq_button.wide:active {
 | 
				
			||||||
 | 
					    background: mix(@theme_bg_color, @theme_selected_bg_color, 0.4);/* #747077; */
 | 
				
			||||||
 | 
					    border-color: mix(@borders, @theme_selected_fg_color, 0.5);/* #96949d; */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sq_button.altline,
 | 
					sq_button.altline,
 | 
				
			||||||
sq_button.special,
 | 
					sq_button.special,
 | 
				
			||||||
sq_button.wide {
 | 
					sq_button.wide {
 | 
				
			||||||
    background: #2b292f;
 | 
					    background: mix(@theme_bg_color, @theme_base_color, 0.5); /*#2b292f;*/
 | 
				
			||||||
    border-color: #3e3a44;
 | 
					    border-color: @borders; /* #3e3a44; */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sq_button.locked {
 | 
					sq_button.locked {
 | 
				
			||||||
    background: #ffffff;
 | 
					    background: @theme_fg_color; /*#ffffff;*/
 | 
				
			||||||
    color: #2b292f;
 | 
					    color: @theme_bg_color; /*#2b292f;*/
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Return {
 | 
					#Return {
 | 
				
			||||||
    background: #1c71d8;
 | 
					    background: @theme_selected_bg_color; /* #1c71d8; */
 | 
				
			||||||
    border-color: #1a5fb4;
 | 
					    border-color: @borders; /*#1a5fb4;*/
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Return:active {
 | 
					#Return:active {
 | 
				
			||||||
    background: #1c71d8;
 | 
					    background: mix(@theme_selected_bg_color, @theme_bg_color, 0.4); /*#1c71d8;*/
 | 
				
			||||||
    border-color: #3584e4;
 | 
					    border-color: @borders; /*#3584e4;*/
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										7
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@ -1,3 +1,10 @@
 | 
				
			|||||||
 | 
					squeekboard (1.4.0) amber-phone; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  * "text" property in layouts
 | 
				
			||||||
 | 
					  * Adjusts to user's color scheme
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Mon, 02 Dec 2019 19:37:01 +0000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
squeekboard (1.3.2) amber-phone; urgency=medium
 | 
					squeekboard (1.3.2) amber-phone; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * Make sure all key presses get accepted by the compositor
 | 
					  * Make sure all key presses get accepted by the compositor
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										11
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@ -12,6 +12,7 @@ Build-Depends:
 | 
				
			|||||||
 libgtk-3-dev,
 | 
					 libgtk-3-dev,
 | 
				
			||||||
 libcroco3-dev,
 | 
					 libcroco3-dev,
 | 
				
			||||||
 librust-bitflags-1-dev (>= 1.0),
 | 
					 librust-bitflags-1-dev (>= 1.0),
 | 
				
			||||||
 | 
					 librust-clap-2+default-dev (>= 2.32),
 | 
				
			||||||
 librust-gio+v2-44-dev,
 | 
					 librust-gio+v2-44-dev,
 | 
				
			||||||
 librust-glib+v2-44-dev,
 | 
					 librust-glib+v2-44-dev,
 | 
				
			||||||
 librust-glib-sys-dev,
 | 
					 librust-glib-sys-dev,
 | 
				
			||||||
@ -40,3 +41,13 @@ Depends:
 | 
				
			|||||||
 ${misc:Depends}
 | 
					 ${misc:Depends}
 | 
				
			||||||
Description: On-screen keyboard for Wayland
 | 
					Description: On-screen keyboard for Wayland
 | 
				
			||||||
 Virtual keyboard supporting Wayland, built primarily for the Librem 5 phone.
 | 
					 Virtual keyboard supporting Wayland, built primarily for the Librem 5 phone.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Package: squeekboard-devel
 | 
				
			||||||
 | 
					Architecture: linux-any
 | 
				
			||||||
 | 
					Depends:
 | 
				
			||||||
 | 
					 ${shlibs:Depends}
 | 
				
			||||||
 | 
					 ${misc:Depends}
 | 
				
			||||||
 | 
					Description: Resources for making Squeekboard layouts
 | 
				
			||||||
 | 
					 Tools for creating Squeekboard layouts:
 | 
				
			||||||
 | 
					 .
 | 
				
			||||||
 | 
					  * squeekboard-test-layout
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1
									
								
								debian/squeekboard-devel.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								debian/squeekboard-devel.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					usr/bin/squeekboard-test-layout /usr/bin
 | 
				
			||||||
							
								
								
									
										2
									
								
								debian/squeekboard.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								debian/squeekboard.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					tools/squeekboard-restyled usr/bin
 | 
				
			||||||
 | 
					usr/bin/squeekboard /usr/bin
 | 
				
			||||||
							
								
								
									
										2
									
								
								debian/squeekboard.lintian-overrides
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/squeekboard.lintian-overrides
									
									
									
									
										vendored
									
									
								
							@ -1,2 +1,2 @@
 | 
				
			|||||||
# yaml-rust 0.4.3 shares some roots with libyaml, including the string which lintian checks, creating a false positive
 | 
					# 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-real: libyaml
 | 
					squeekboard binary: embedded-library usr/bin/squeekboard: libyaml
 | 
				
			||||||
 | 
				
			|||||||
@ -158,6 +158,8 @@ eek_gtk_keyboard_real_button_press_event (GtkWidget      *self,
 | 
				
			|||||||
    return TRUE;
 | 
					    return TRUE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: this belongs more in gtk_keyboard, with a way to find out which key to re-render
 | 
					// TODO: this belongs more in gtk_keyboard, with a way to find out which key to re-render
 | 
				
			||||||
static gboolean
 | 
					static gboolean
 | 
				
			||||||
eek_gtk_keyboard_real_button_release_event (GtkWidget      *self,
 | 
					eek_gtk_keyboard_real_button_release_event (GtkWidget      *self,
 | 
				
			||||||
@ -170,6 +172,18 @@ eek_gtk_keyboard_real_button_release_event (GtkWidget      *self,
 | 
				
			|||||||
    return TRUE;
 | 
					    return TRUE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static gboolean
 | 
				
			||||||
 | 
					eek_gtk_keyboard_leave_event (GtkWidget      *self,
 | 
				
			||||||
 | 
					                              GdkEventCrossing *event)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (event->type == GDK_LEAVE_NOTIFY) {
 | 
				
			||||||
 | 
					        // TODO: can the event have different coords than the previous move event?
 | 
				
			||||||
 | 
					        release(EEK_GTK_KEYBOARD(self), event->time);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return TRUE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static gboolean
 | 
					static gboolean
 | 
				
			||||||
eek_gtk_keyboard_real_motion_notify_event (GtkWidget      *self,
 | 
					eek_gtk_keyboard_real_motion_notify_event (GtkWidget      *self,
 | 
				
			||||||
                                           GdkEventMotion *event)
 | 
					                                           GdkEventMotion *event)
 | 
				
			||||||
@ -279,6 +293,9 @@ 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->leave_notify_event =
 | 
				
			||||||
 | 
					        eek_gtk_keyboard_leave_event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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;
 | 
				
			||||||
 | 
				
			|||||||
@ -26,6 +26,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "eek-keyboard.h"
 | 
					#include "eek-keyboard.h"
 | 
				
			||||||
#include "eek-renderer.h"
 | 
					#include "eek-renderer.h"
 | 
				
			||||||
 | 
					#include "src/style.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
    PROP_0,
 | 
					    PROP_0,
 | 
				
			||||||
@ -623,10 +624,7 @@ eek_renderer_init (EekRenderer *self)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    gtk_icon_theme_add_resource_path (theme, "/sm/puri/squeekboard/icons");
 | 
					    gtk_icon_theme_add_resource_path (theme, "/sm/puri/squeekboard/icons");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Create a default CSS provider and load a style sheet */
 | 
					    priv->css_provider = squeek_load_style();
 | 
				
			||||||
    priv->css_provider = gtk_css_provider_new ();
 | 
					 | 
				
			||||||
    gtk_css_provider_load_from_resource (priv->css_provider,
 | 
					 | 
				
			||||||
        "/sm/puri/squeekboard/style.css");
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
 | 
				
			|||||||
@ -207,22 +207,8 @@ static void
 | 
				
			|||||||
settings_get_layout(GSettings *settings, char **type, char **layout)
 | 
					settings_get_layout(GSettings *settings, char **type, char **layout)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    GVariant *inputs = g_settings_get_value(settings, "sources");
 | 
					    GVariant *inputs = g_settings_get_value(settings, "sources");
 | 
				
			||||||
    guint32 index;
 | 
					    // current layout is always first
 | 
				
			||||||
    g_settings_get(settings, "current", "u", &index);
 | 
					    g_variant_get_child(inputs, 0, "(ss)", type, layout);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    GVariantIter *iter;
 | 
					 | 
				
			||||||
    g_variant_get(inputs, "a(ss)", &iter);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (unsigned i = 0;
 | 
					 | 
				
			||||||
         g_variant_iter_loop(iter, "(ss)", type, layout);
 | 
					 | 
				
			||||||
         i++) {
 | 
					 | 
				
			||||||
        if (i == index) {
 | 
					 | 
				
			||||||
            //printf("Found layout %s %s\n", *type, *layout);
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    g_variant_iter_free(iter);
 | 
					 | 
				
			||||||
    g_variant_unref(inputs);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
 | 
				
			|||||||
@ -1,52 +1,10 @@
 | 
				
			|||||||
extern crate rs;
 | 
					extern crate rs;
 | 
				
			||||||
extern crate xkbcommon;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use rs::tests::check_builtin_layout;
 | 
				
			||||||
use std::env;
 | 
					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() -> () {
 | 
					fn main() -> () {
 | 
				
			||||||
    check_layout(env::args().nth(1).expect("No argument given").as_str());
 | 
					    check_builtin_layout(
 | 
				
			||||||
 | 
					        env::args().nth(1).expect("No argument given").as_str()
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										10
									
								
								meson.build
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								meson.build
									
									
									
									
									
								
							@ -1,7 +1,7 @@
 | 
				
			|||||||
project(
 | 
					project(
 | 
				
			||||||
    'squeekboard',
 | 
					    'squeekboard',
 | 
				
			||||||
    'c', 'rust',
 | 
					    'c', 'rust',
 | 
				
			||||||
    version: '1.3.2',
 | 
					    version: '1.4.0',
 | 
				
			||||||
    license: 'GPLv3',
 | 
					    license: 'GPLv3',
 | 
				
			||||||
    meson_version: '>=0.51.0',
 | 
					    meson_version: '>=0.51.0',
 | 
				
			||||||
    default_options: [
 | 
					    default_options: [
 | 
				
			||||||
@ -33,6 +33,11 @@ endif
 | 
				
			|||||||
if get_option('buildtype') != 'plain'
 | 
					if get_option('buildtype') != 'plain'
 | 
				
			||||||
    add_project_arguments('-fstack-protector-strong', language: 'c')
 | 
					    add_project_arguments('-fstack-protector-strong', language: 'c')
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					if get_option('buildtype') == 'release'
 | 
				
			||||||
 | 
					    cargo_build_flags = ['--release'] # for artifacts
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					    cargo_build_flags = []
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
prefix = get_option('prefix')
 | 
					prefix = get_option('prefix')
 | 
				
			||||||
datadir = join_paths(prefix, get_option('datadir'))
 | 
					datadir = join_paths(prefix, get_option('datadir'))
 | 
				
			||||||
@ -54,8 +59,9 @@ summary = [
 | 
				
			|||||||
]
 | 
					]
 | 
				
			||||||
message('\n'.join(summary))
 | 
					message('\n'.join(summary))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cargo = find_program('cargo')
 | 
					dep_cargo = find_program('cargo')
 | 
				
			||||||
cargo_script = find_program('cargo.sh')
 | 
					cargo_script = find_program('cargo.sh')
 | 
				
			||||||
 | 
					cargo_build = find_program('cargo_build.sh')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
subdir('data')
 | 
					subdir('data')
 | 
				
			||||||
subdir('protocols')
 | 
					subdir('protocols')
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										16
									
								
								src/bin/test_layout.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/bin/test_layout.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					#[macro_use]
 | 
				
			||||||
 | 
					extern crate clap;
 | 
				
			||||||
 | 
					extern crate rs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use rs::tests::check_layout_file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() -> () {
 | 
				
			||||||
 | 
					    let matches = clap_app!(test_layout =>
 | 
				
			||||||
 | 
					        (name: "squeekboard-test-layout")
 | 
				
			||||||
 | 
					        (about: "Test keyboard layout for errors. Returns OK or an error message containing further information.")
 | 
				
			||||||
 | 
					        (@arg INPUT: +required "Yaml keyboard layout file to test")
 | 
				
			||||||
 | 
					    ).get_matches();
 | 
				
			||||||
 | 
					    if check_layout_file(matches.value_of("INPUT").unwrap()) == () {
 | 
				
			||||||
 | 
					        println!("Test result: OK");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										282
									
								
								src/data.rs
									
									
									
									
									
								
							
							
						
						
									
										282
									
								
								src/data.rs
									
									
									
									
									
								
							@ -26,8 +26,8 @@ use ::xdg;
 | 
				
			|||||||
// traits, derives
 | 
					// traits, derives
 | 
				
			||||||
use std::io::BufReader;
 | 
					use std::io::BufReader;
 | 
				
			||||||
use std::iter::FromIterator;
 | 
					use std::iter::FromIterator;
 | 
				
			||||||
 | 
					 | 
				
			||||||
use serde::Deserialize;
 | 
					use serde::Deserialize;
 | 
				
			||||||
 | 
					use util::WarningHandler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Gathers stuff defined in C or called by C
 | 
					/// Gathers stuff defined in C or called by C
 | 
				
			||||||
@ -151,21 +151,30 @@ fn list_layout_sources(
 | 
				
			|||||||
    ret
 | 
					    ret
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct PrintWarnings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl WarningHandler for PrintWarnings {
 | 
				
			||||||
 | 
					    fn handle(&mut self, warning: &str) {
 | 
				
			||||||
 | 
					        println!("{}", warning);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn load_layout_data(source: DataSource)
 | 
					fn load_layout_data(source: DataSource)
 | 
				
			||||||
    -> Result<::layout::LayoutData, LoadError>
 | 
					    -> Result<::layout::LayoutData, LoadError>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    let handler = PrintWarnings{};
 | 
				
			||||||
    match source {
 | 
					    match source {
 | 
				
			||||||
        DataSource::File(path) => {
 | 
					        DataSource::File(path) => {
 | 
				
			||||||
            Layout::from_file(path.clone())
 | 
					            Layout::from_file(path.clone())
 | 
				
			||||||
                .map_err(LoadError::BadData)
 | 
					                .map_err(LoadError::BadData)
 | 
				
			||||||
                .and_then(|layout|
 | 
					                .and_then(|layout|
 | 
				
			||||||
                    layout.build().map_err(LoadError::BadKeyMap)
 | 
					                    layout.build(handler).0.map_err(LoadError::BadKeyMap)
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        DataSource::Resource(name) => {
 | 
					        DataSource::Resource(name) => {
 | 
				
			||||||
            Layout::from_resource(&name)
 | 
					            Layout::from_resource(&name)
 | 
				
			||||||
                .and_then(|layout|
 | 
					                .and_then(|layout|
 | 
				
			||||||
                    layout.build().map_err(LoadError::BadKeyMap)
 | 
					                    layout.build(handler).0.map_err(LoadError::BadKeyMap)
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -225,22 +234,28 @@ struct Bounds {
 | 
				
			|||||||
/// Buttons are embedded in a single string
 | 
					/// Buttons are embedded in a single string
 | 
				
			||||||
type ButtonIds = String;
 | 
					type ButtonIds = String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// All info about a single button
 | 
				
			||||||
 | 
					/// Buttons can have multiple instances though.
 | 
				
			||||||
#[derive(Debug, Default, Deserialize, PartialEq)]
 | 
					#[derive(Debug, Default, Deserialize, PartialEq)]
 | 
				
			||||||
#[serde(deny_unknown_fields)]
 | 
					#[serde(deny_unknown_fields)]
 | 
				
			||||||
struct ButtonMeta {
 | 
					struct ButtonMeta {
 | 
				
			||||||
    /// Action other than keysym (conflicts with keysym)
 | 
					    /// Special action to perform on activation. Conflicts with keysym, text.
 | 
				
			||||||
    action: Option<Action>,
 | 
					    action: Option<Action>,
 | 
				
			||||||
    /// The name of the outline. If not present, will be "default"
 | 
					    /// The name of the XKB keysym to emit on activation.
 | 
				
			||||||
    outline: Option<String>,
 | 
					    /// Conflicts with action, text
 | 
				
			||||||
    /// FIXME: start using it
 | 
					 | 
				
			||||||
    keysym: Option<String>,
 | 
					    keysym: Option<String>,
 | 
				
			||||||
    /// If not present, will be derived from the button ID
 | 
					    /// The text to submit on activation. Will be derived from ID if not present
 | 
				
			||||||
 | 
					    /// Conflicts with action, keysym
 | 
				
			||||||
 | 
					    text: Option<String>,
 | 
				
			||||||
 | 
					    /// If not present, will be derived from text or the button ID
 | 
				
			||||||
    label: Option<String>,
 | 
					    label: Option<String>,
 | 
				
			||||||
    /// Conflicts with label
 | 
					    /// Conflicts with label
 | 
				
			||||||
    icon: Option<String>,
 | 
					    icon: Option<String>,
 | 
				
			||||||
 | 
					    /// The name of the outline. If not present, will be "default"
 | 
				
			||||||
 | 
					    outline: Option<String>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Deserialize, PartialEq)]
 | 
					#[derive(Debug, Deserialize, PartialEq, Clone)]
 | 
				
			||||||
#[serde(deny_unknown_fields)]
 | 
					#[serde(deny_unknown_fields)]
 | 
				
			||||||
enum Action {
 | 
					enum Action {
 | 
				
			||||||
    #[serde(rename="locking")]
 | 
					    #[serde(rename="locking")]
 | 
				
			||||||
@ -296,7 +311,7 @@ impl Layout {
 | 
				
			|||||||
                    .map_err(LoadError::BadResource)
 | 
					                    .map_err(LoadError::BadResource)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn from_file(path: PathBuf) -> Result<Layout, Error> {
 | 
					    pub fn from_file(path: PathBuf) -> Result<Layout, Error> {
 | 
				
			||||||
        let infile = BufReader::new(
 | 
					        let infile = BufReader::new(
 | 
				
			||||||
            fs::OpenOptions::new()
 | 
					            fs::OpenOptions::new()
 | 
				
			||||||
                .read(true)
 | 
					                .read(true)
 | 
				
			||||||
@ -305,8 +320,8 @@ impl Layout {
 | 
				
			|||||||
        serde_yaml::from_reader(infile).map_err(Error::Yaml)
 | 
					        serde_yaml::from_reader(infile).map_err(Error::Yaml)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn build(self)
 | 
					    pub fn build<H: WarningHandler>(self, mut warning_handler: H)
 | 
				
			||||||
        -> Result<::layout::LayoutData, FormattingError>
 | 
					        -> (Result<::layout::LayoutData, FormattingError>, H)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        let button_names = self.views.values()
 | 
					        let button_names = self.views.values()
 | 
				
			||||||
            .flat_map(|rows| {
 | 
					            .flat_map(|rows| {
 | 
				
			||||||
@ -323,7 +338,8 @@ impl Layout {
 | 
				
			|||||||
                create_action(
 | 
					                create_action(
 | 
				
			||||||
                    &self.buttons,
 | 
					                    &self.buttons,
 | 
				
			||||||
                    name,
 | 
					                    name,
 | 
				
			||||||
                    self.views.keys().collect()
 | 
					                    self.views.keys().collect(),
 | 
				
			||||||
 | 
					                    &mut warning_handler,
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            )}).collect();
 | 
					            )}).collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -368,13 +384,15 @@ impl Layout {
 | 
				
			|||||||
            )
 | 
					            )
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let button_states
 | 
					        let button_states = HashMap::<String, KeyState>::from_iter(
 | 
				
			||||||
            = HashMap::<String, KeyState>::from_iter(
 | 
					            button_states
 | 
				
			||||||
                button_states
 | 
					        );
 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // TODO: generate from symbols
 | 
					        // TODO: generate from symbols
 | 
				
			||||||
        let keymap_str = generate_keymap(&button_states)?;
 | 
					        let keymap_str = match generate_keymap(&button_states) {
 | 
				
			||||||
 | 
					            Err(e) => { return (Err(e), warning_handler) },
 | 
				
			||||||
 | 
					            Ok(v) => v,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let button_states_cache = hash_map_map(
 | 
					        let button_states_cache = hash_map_map(
 | 
				
			||||||
            button_states,
 | 
					            button_states,
 | 
				
			||||||
@ -405,7 +423,8 @@ impl Layout {
 | 
				
			|||||||
                                    name,
 | 
					                                    name,
 | 
				
			||||||
                                    button_states_cache.get(name.into())
 | 
					                                    button_states_cache.get(name.into())
 | 
				
			||||||
                                        .expect("Button state not created")
 | 
					                                        .expect("Button state not created")
 | 
				
			||||||
                                        .clone()
 | 
					                                        .clone(),
 | 
				
			||||||
 | 
					                                    &mut warning_handler,
 | 
				
			||||||
                                ))
 | 
					                                ))
 | 
				
			||||||
                            }).collect(),
 | 
					                            }).collect(),
 | 
				
			||||||
                        })
 | 
					                        })
 | 
				
			||||||
@ -414,116 +433,148 @@ impl Layout {
 | 
				
			|||||||
            )})
 | 
					            )})
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(::layout::LayoutData {
 | 
					        (
 | 
				
			||||||
            views: views,
 | 
					            Ok(::layout::LayoutData {
 | 
				
			||||||
            keymap_str: {
 | 
					                views: views,
 | 
				
			||||||
                CString::new(keymap_str)
 | 
					                keymap_str: {
 | 
				
			||||||
                    .expect("Invalid keymap string generated")
 | 
					                    CString::new(keymap_str)
 | 
				
			||||||
            },
 | 
					                        .expect("Invalid keymap string generated")
 | 
				
			||||||
        })
 | 
					                },
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            warning_handler,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn create_action(
 | 
					fn create_action<H: WarningHandler>(
 | 
				
			||||||
    button_info: &HashMap<String, ButtonMeta>,
 | 
					    button_info: &HashMap<String, ButtonMeta>,
 | 
				
			||||||
    name: &str,
 | 
					    name: &str,
 | 
				
			||||||
    view_names: Vec<&String>,
 | 
					    view_names: Vec<&String>,
 | 
				
			||||||
 | 
					    warning_handler: &mut H,
 | 
				
			||||||
) -> ::action::Action {
 | 
					) -> ::action::Action {
 | 
				
			||||||
    let default_meta = ButtonMeta::default();
 | 
					    let default_meta = ButtonMeta::default();
 | 
				
			||||||
    let symbol_meta = button_info.get(name)
 | 
					    let symbol_meta = button_info.get(name)
 | 
				
			||||||
        .unwrap_or(&default_meta);
 | 
					        .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 {
 | 
					    fn keysym_valid(name: &str) -> bool {
 | 
				
			||||||
        xkb::keysym_from_name(name, xkb::KEYSYM_NO_FLAGS) != xkb::KEY_NoSymbol
 | 
					        xkb::keysym_from_name(name, xkb::KEYSYM_NO_FLAGS) != xkb::KEY_NoSymbol
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    let keysyms = match &symbol_meta.action {
 | 
					    enum SubmitData {
 | 
				
			||||||
        // Non-submit action
 | 
					        Action(Action),
 | 
				
			||||||
        Some(_) => Vec::new(),
 | 
					        Text(String),
 | 
				
			||||||
        // Submit action
 | 
					        Keysym(String),
 | 
				
			||||||
        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 {
 | 
					    let submission = match (
 | 
				
			||||||
        Some(Action::SetView(view_name)) => ::action::Action::SetLevel(
 | 
					        &symbol_meta.action,
 | 
				
			||||||
            filter_view_name(name, view_name.clone(), &view_names)
 | 
					        &symbol_meta.keysym,
 | 
				
			||||||
 | 
					        &symbol_meta.text
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        (Some(action), None, None) => SubmitData::Action(action.clone()),
 | 
				
			||||||
 | 
					        (None, Some(keysym), None) => SubmitData::Keysym(keysym.clone()),
 | 
				
			||||||
 | 
					        (None, None, Some(text)) => SubmitData::Text(text.clone()),
 | 
				
			||||||
 | 
					        (None, None, None) => SubmitData::Text(name.into()),
 | 
				
			||||||
 | 
					        _ => {
 | 
				
			||||||
 | 
					            warning_handler.handle(&format!(
 | 
				
			||||||
 | 
					                "Button {} has more than one of (action, keysym, text)",
 | 
				
			||||||
 | 
					                name
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
 | 
					            SubmitData::Text("".into())
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn filter_view_name<H: WarningHandler>(
 | 
				
			||||||
 | 
					        button_name: &str,
 | 
				
			||||||
 | 
					        view_name: String,
 | 
				
			||||||
 | 
					        view_names: &Vec<&String>,
 | 
				
			||||||
 | 
					        warning_handler: &mut H,
 | 
				
			||||||
 | 
					    ) -> String {
 | 
				
			||||||
 | 
					        if view_names.contains(&&view_name) {
 | 
				
			||||||
 | 
					            view_name
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            warning_handler.handle(&format!("Button {} switches to missing view {}",
 | 
				
			||||||
 | 
					                button_name,
 | 
				
			||||||
 | 
					                view_name,
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
 | 
					            "base".into()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    match submission {
 | 
				
			||||||
 | 
					        SubmitData::Action(
 | 
				
			||||||
 | 
					            Action::SetView(view_name)
 | 
				
			||||||
 | 
					        ) => ::action::Action::SetLevel(
 | 
				
			||||||
 | 
					            filter_view_name(
 | 
				
			||||||
 | 
					                name, view_name.clone(), &view_names,
 | 
				
			||||||
 | 
					                warning_handler,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        Some(Action::Locking {
 | 
					        SubmitData::Action(Action::Locking {
 | 
				
			||||||
            lock_view, unlock_view
 | 
					            lock_view, unlock_view
 | 
				
			||||||
        }) => ::action::Action::LockLevel {
 | 
					        }) => ::action::Action::LockLevel {
 | 
				
			||||||
            lock: filter_view_name(name, lock_view.clone(), &view_names),
 | 
					            lock: filter_view_name(
 | 
				
			||||||
 | 
					                name,
 | 
				
			||||||
 | 
					                lock_view.clone(),
 | 
				
			||||||
 | 
					                &view_names,
 | 
				
			||||||
 | 
					                warning_handler,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
            unlock: filter_view_name(
 | 
					            unlock: filter_view_name(
 | 
				
			||||||
                name,
 | 
					                name,
 | 
				
			||||||
                unlock_view.clone(),
 | 
					                unlock_view.clone(),
 | 
				
			||||||
                &view_names
 | 
					                &view_names,
 | 
				
			||||||
 | 
					                warning_handler,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        Some(Action::ShowPrefs) => ::action::Action::ShowPreferences,
 | 
					        SubmitData::Action(
 | 
				
			||||||
        None => ::action::Action::Submit {
 | 
					            Action::ShowPrefs
 | 
				
			||||||
 | 
					        ) => ::action::Action::ShowPreferences,
 | 
				
			||||||
 | 
					        SubmitData::Keysym(keysym) => ::action::Action::Submit {
 | 
				
			||||||
            text: None,
 | 
					            text: None,
 | 
				
			||||||
            keys: keysyms.into_iter().map(::action::KeySym).collect(),
 | 
					            keys: vec!(::action::KeySym(
 | 
				
			||||||
 | 
					                match keysym_valid(keysym.as_str()) {
 | 
				
			||||||
 | 
					                    true => keysym.clone(),
 | 
				
			||||||
 | 
					                    false => {
 | 
				
			||||||
 | 
					                        warning_handler.handle(&format!(
 | 
				
			||||||
 | 
					                            "Keysym name invalid: {}",
 | 
				
			||||||
 | 
					                            keysym,
 | 
				
			||||||
 | 
					                        ));
 | 
				
			||||||
 | 
					                        "space".into() // placeholder
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            )),
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        SubmitData::Text(text) => ::action::Action::Submit {
 | 
				
			||||||
 | 
					            text: {
 | 
				
			||||||
 | 
					                CString::new(text.clone())
 | 
				
			||||||
 | 
					                    .map_err(|e| {
 | 
				
			||||||
 | 
					                        warning_handler.handle(&format!(
 | 
				
			||||||
 | 
					                            "Text {} contains problems: {:?}",
 | 
				
			||||||
 | 
					                            text,
 | 
				
			||||||
 | 
					                            e
 | 
				
			||||||
 | 
					                        ));
 | 
				
			||||||
 | 
					                        e
 | 
				
			||||||
 | 
					                    }).ok()
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            keys: text.chars().map(|codepoint| {
 | 
				
			||||||
 | 
					                let codepoint_string = codepoint.to_string();
 | 
				
			||||||
 | 
					                ::action::KeySym(match keysym_valid(codepoint_string.as_str()) {
 | 
				
			||||||
 | 
					                    true => codepoint_string,
 | 
				
			||||||
 | 
					                    false => format!("U{:04X}", codepoint as u32),
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            }).collect(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// TODO: Since this will receive user-provided data,
 | 
					/// TODO: Since this will receive user-provided data,
 | 
				
			||||||
/// all .expect() on them should be turned into soft fails
 | 
					/// all .expect() on them should be turned into soft fails
 | 
				
			||||||
fn create_button(
 | 
					fn create_button<H: WarningHandler>(
 | 
				
			||||||
    button_info: &HashMap<String, ButtonMeta>,
 | 
					    button_info: &HashMap<String, ButtonMeta>,
 | 
				
			||||||
    outlines: &HashMap<String, Outline>,
 | 
					    outlines: &HashMap<String, Outline>,
 | 
				
			||||||
    name: &str,
 | 
					    name: &str,
 | 
				
			||||||
    state: Rc<RefCell<KeyState>>,
 | 
					    state: Rc<RefCell<KeyState>>,
 | 
				
			||||||
 | 
					    warning_handler: &mut H,
 | 
				
			||||||
) -> ::layout::Button {
 | 
					) -> ::layout::Button {
 | 
				
			||||||
    let cname = CString::new(name.clone())
 | 
					    let cname = CString::new(name.clone())
 | 
				
			||||||
        .expect("Bad name");
 | 
					        .expect("Bad name");
 | 
				
			||||||
@ -539,6 +590,18 @@ fn create_button(
 | 
				
			|||||||
    } else if let Some(icon) = &button_meta.icon {
 | 
					    } else if let Some(icon) = &button_meta.icon {
 | 
				
			||||||
        ::layout::Label::IconName(CString::new(icon.as_str())
 | 
					        ::layout::Label::IconName(CString::new(icon.as_str())
 | 
				
			||||||
            .expect("Bad icon"))
 | 
					            .expect("Bad icon"))
 | 
				
			||||||
 | 
					    } else if let Some(text) = &button_meta.text {
 | 
				
			||||||
 | 
					        ::layout::Label::Text(
 | 
				
			||||||
 | 
					            CString::new(text.as_str())
 | 
				
			||||||
 | 
					                .unwrap_or_else(|e| {
 | 
				
			||||||
 | 
					                    warning_handler.handle(&format!(
 | 
				
			||||||
 | 
					                        "Text {} is invalid: {}",
 | 
				
			||||||
 | 
					                        text,
 | 
				
			||||||
 | 
					                        e,
 | 
				
			||||||
 | 
					                    ));
 | 
				
			||||||
 | 
					                    CString::new("").unwrap()
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        ::layout::Label::Text(cname.clone())
 | 
					        ::layout::Label::Text(cname.clone())
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@ -548,7 +611,7 @@ fn create_button(
 | 
				
			|||||||
            if outlines.contains_key(outline) {
 | 
					            if outlines.contains_key(outline) {
 | 
				
			||||||
                outline.clone()
 | 
					                outline.clone()
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                eprintln!("Outline named {} does not exist! Using default for button {}", outline, name);
 | 
					                warning_handler.handle(&format!("Outline named {} does not exist! Using default for button {}", outline, name));
 | 
				
			||||||
                "default".into()
 | 
					                "default".into()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -558,7 +621,9 @@ fn create_button(
 | 
				
			|||||||
    let outline = outlines.get(&outline_name)
 | 
					    let outline = outlines.get(&outline_name)
 | 
				
			||||||
        .map(|outline| (*outline).clone())
 | 
					        .map(|outline| (*outline).clone())
 | 
				
			||||||
        .unwrap_or_else(|| {
 | 
					        .unwrap_or_else(|| {
 | 
				
			||||||
            eprintln!("No default outline defied Using 1x1!");
 | 
					            warning_handler.handle(
 | 
				
			||||||
 | 
					                &format!("No default outline defined! Using 1x1!")
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
            Outline {
 | 
					            Outline {
 | 
				
			||||||
                bounds: Bounds { x: 0f64, y: 0f64, width: 1f64, height: 1f64 },
 | 
					                bounds: Bounds { x: 0f64, y: 0f64, width: 1f64, height: 1f64 },
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -585,6 +650,14 @@ mod tests {
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    use std::error::Error as ErrorTrait;
 | 
					    use std::error::Error as ErrorTrait;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct PanicWarn;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    impl WarningHandler for PanicWarn {
 | 
				
			||||||
 | 
					        fn handle(&mut self, warning: &str) {
 | 
				
			||||||
 | 
					            panic!("{}", warning);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn test_parse_path() {
 | 
					    fn test_parse_path() {
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
@ -599,6 +672,7 @@ mod tests {
 | 
				
			|||||||
                        icon: None,
 | 
					                        icon: None,
 | 
				
			||||||
                        keysym: None,
 | 
					                        keysym: None,
 | 
				
			||||||
                        action: None,
 | 
					                        action: None,
 | 
				
			||||||
 | 
					                        text: None,
 | 
				
			||||||
                        label: Some("test".into()),
 | 
					                        label: Some("test".into()),
 | 
				
			||||||
                        outline: None,
 | 
					                        outline: None,
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@ -656,7 +730,7 @@ mod tests {
 | 
				
			|||||||
    fn test_layout_punctuation() {
 | 
					    fn test_layout_punctuation() {
 | 
				
			||||||
        let out = Layout::from_file(PathBuf::from("tests/layout_key1.yaml"))
 | 
					        let out = Layout::from_file(PathBuf::from("tests/layout_key1.yaml"))
 | 
				
			||||||
            .unwrap()
 | 
					            .unwrap()
 | 
				
			||||||
            .build()
 | 
					            .build(PanicWarn).0
 | 
				
			||||||
            .unwrap();
 | 
					            .unwrap();
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            out.views["base"]
 | 
					            out.views["base"]
 | 
				
			||||||
@ -671,7 +745,7 @@ mod tests {
 | 
				
			|||||||
    fn test_layout_unicode() {
 | 
					    fn test_layout_unicode() {
 | 
				
			||||||
        let out = Layout::from_file(PathBuf::from("tests/layout_key2.yaml"))
 | 
					        let out = Layout::from_file(PathBuf::from("tests/layout_key2.yaml"))
 | 
				
			||||||
            .unwrap()
 | 
					            .unwrap()
 | 
				
			||||||
            .build()
 | 
					            .build(PanicWarn).0
 | 
				
			||||||
            .unwrap();
 | 
					            .unwrap();
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            out.views["base"]
 | 
					            out.views["base"]
 | 
				
			||||||
@ -687,7 +761,7 @@ mod tests {
 | 
				
			|||||||
    fn test_layout_unicode_multi() {
 | 
					    fn test_layout_unicode_multi() {
 | 
				
			||||||
        let out = Layout::from_file(PathBuf::from("tests/layout_key3.yaml"))
 | 
					        let out = Layout::from_file(PathBuf::from("tests/layout_key3.yaml"))
 | 
				
			||||||
            .unwrap()
 | 
					            .unwrap()
 | 
				
			||||||
            .build()
 | 
					            .build(PanicWarn).0
 | 
				
			||||||
            .unwrap();
 | 
					            .unwrap();
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            out.views["base"]
 | 
					            out.views["base"]
 | 
				
			||||||
@ -702,7 +776,7 @@ mod tests {
 | 
				
			|||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn parsing_fallback() {
 | 
					    fn parsing_fallback() {
 | 
				
			||||||
        assert!(Layout::from_resource(FALLBACK_LAYOUT_NAME)
 | 
					        assert!(Layout::from_resource(FALLBACK_LAYOUT_NAME)
 | 
				
			||||||
            .and_then(|layout| layout.build().map_err(LoadError::BadKeyMap))
 | 
					            .map(|layout| layout.build(PanicWarn).0.unwrap())
 | 
				
			||||||
            .is_ok()
 | 
					            .is_ok()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -742,18 +816,20 @@ mod tests {
 | 
				
			|||||||
                    ".".into() => ButtonMeta {
 | 
					                    ".".into() => ButtonMeta {
 | 
				
			||||||
                        icon: None,
 | 
					                        icon: None,
 | 
				
			||||||
                        keysym: None,
 | 
					                        keysym: None,
 | 
				
			||||||
 | 
					                        text: None,
 | 
				
			||||||
                        action: None,
 | 
					                        action: None,
 | 
				
			||||||
                        label: Some("test".into()),
 | 
					                        label: Some("test".into()),
 | 
				
			||||||
                        outline: None,
 | 
					                        outline: None,
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                ".",
 | 
					                ".",
 | 
				
			||||||
                Vec::new()
 | 
					                Vec::new(),
 | 
				
			||||||
 | 
					                &mut PanicWarn,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            ::action::Action::Submit {
 | 
					            ::action::Action::Submit {
 | 
				
			||||||
                text: None,
 | 
					                text: Some(CString::new(".").unwrap()),
 | 
				
			||||||
                keys: vec!(::action::KeySym("U002E".into())),
 | 
					                keys: vec!(::action::KeySym("U002E".into())),
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -51,6 +51,15 @@ pub struct KeyState {
 | 
				
			|||||||
    pub action: Action,
 | 
					    pub action: Action,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Sorts an iterator by converting it to a Vector and back
 | 
				
			||||||
 | 
					fn sorted<'a, I: Iterator<Item=&'a str>>(
 | 
				
			||||||
 | 
					    iter: I
 | 
				
			||||||
 | 
					) -> impl Iterator<Item=&'a str> {
 | 
				
			||||||
 | 
					    let mut v: Vec<&'a str> = iter.collect();
 | 
				
			||||||
 | 
					    v.sort();
 | 
				
			||||||
 | 
					    v.into_iter()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Generates a mapping where each key gets a keycode, starting from ~~8~~
 | 
					/// Generates a mapping where each key gets a keycode, starting from ~~8~~
 | 
				
			||||||
/// HACK: starting from 9, because 8 results in keycode 0,
 | 
					/// HACK: starting from 9, because 8 results in keycode 0,
 | 
				
			||||||
/// which the compositor likes to discard
 | 
					/// which the compositor likes to discard
 | 
				
			||||||
@ -58,7 +67,8 @@ pub fn generate_keycodes<'a, C: IntoIterator<Item=&'a str>>(
 | 
				
			|||||||
    key_names: C
 | 
					    key_names: C
 | 
				
			||||||
) -> HashMap<String, u32> {
 | 
					) -> HashMap<String, u32> {
 | 
				
			||||||
    HashMap::from_iter(
 | 
					    HashMap::from_iter(
 | 
				
			||||||
        key_names.into_iter()
 | 
					        // sort to remove a source of indeterminism in keycode assignment
 | 
				
			||||||
 | 
					        sorted(key_names.into_iter())
 | 
				
			||||||
            .map(|name| String::from(name))
 | 
					            .map(|name| String::from(name))
 | 
				
			||||||
            .zip(9..)
 | 
					            .zip(9..)
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
				
			|||||||
@ -24,5 +24,7 @@ mod outputs;
 | 
				
			|||||||
mod popover;
 | 
					mod popover;
 | 
				
			||||||
mod resources;
 | 
					mod resources;
 | 
				
			||||||
mod submission;
 | 
					mod submission;
 | 
				
			||||||
mod util;
 | 
					mod style;
 | 
				
			||||||
 | 
					pub mod tests;
 | 
				
			||||||
 | 
					pub mod util;
 | 
				
			||||||
mod xdg;
 | 
					mod xdg;
 | 
				
			||||||
 | 
				
			|||||||
@ -58,7 +58,7 @@ rslibs = custom_target(
 | 
				
			|||||||
    output: ['librs.a'],
 | 
					    output: ['librs.a'],
 | 
				
			||||||
    install: false,
 | 
					    install: false,
 | 
				
			||||||
    console: true,
 | 
					    console: true,
 | 
				
			||||||
    command: [cargo_script, '@OUTPUT@', 'build']
 | 
					    command: [cargo_build] + cargo_build_flags + ['@OUTPUT@', '--lib']
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
build_rstests = custom_target(
 | 
					build_rstests = custom_target(
 | 
				
			||||||
@ -72,14 +72,14 @@ build_rstests = custom_target(
 | 
				
			|||||||
    output: ['src'],
 | 
					    output: ['src'],
 | 
				
			||||||
    install: false,
 | 
					    install: false,
 | 
				
			||||||
    console: true,
 | 
					    console: true,
 | 
				
			||||||
    command: [cargo_script, '', 'test', '--no-run'],
 | 
					    command: [cargo_script, 'test', '--no-run'],
 | 
				
			||||||
    depends: rslibs, # no point building tests if the code itself fails
 | 
					    depends: rslibs, # no point building tests if the code itself fails
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test(
 | 
					test(
 | 
				
			||||||
    'rstest',
 | 
					    'rstest',
 | 
				
			||||||
    cargo_script,
 | 
					    cargo_script,
 | 
				
			||||||
    args: ['', 'test'],
 | 
					    args: ['test'],
 | 
				
			||||||
    # this is a whole Carg-based test suite, let it run for a while
 | 
					    # this is a whole Carg-based test suite, let it run for a while
 | 
				
			||||||
    timeout: 900,
 | 
					    timeout: 900,
 | 
				
			||||||
    depends: build_rstests,
 | 
					    depends: build_rstests,
 | 
				
			||||||
@ -97,20 +97,7 @@ libsqueekboard = static_library('libsqueekboard',
 | 
				
			|||||||
    '-DEEK_COMPILATION=1'],
 | 
					    '-DEEK_COMPILATION=1'],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# the straight binary needs to be demoted in favor of the wrapper script
 | 
					squeekboard = executable('squeekboard',
 | 
				
			||||||
# due to styling being inconsistent
 | 
					 | 
				
			||||||
bindir = join_paths(prefix, get_option('bindir'))
 | 
					 | 
				
			||||||
wrapper_conf = configuration_data()
 | 
					 | 
				
			||||||
wrapper_conf.set('bindir', bindir)
 | 
					 | 
				
			||||||
configure_file(
 | 
					 | 
				
			||||||
  input: '../tools/squeekboard.in',
 | 
					 | 
				
			||||||
  output: 'squeekboard',
 | 
					 | 
				
			||||||
  install_dir: bindir,
 | 
					 | 
				
			||||||
  configuration: wrapper_conf,
 | 
					 | 
				
			||||||
  install: true,
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
squeekboard = executable('squeekboard-real',
 | 
					 | 
				
			||||||
  'server-main.c',
 | 
					  'server-main.c',
 | 
				
			||||||
  wl_proto_sources,
 | 
					  wl_proto_sources,
 | 
				
			||||||
  squeekboard_resources,
 | 
					  squeekboard_resources,
 | 
				
			||||||
@ -124,3 +111,17 @@ squeekboard = executable('squeekboard-real',
 | 
				
			|||||||
    '-DEEKBOARD_COMPILATION=1',
 | 
					    '-DEEKBOARD_COMPILATION=1',
 | 
				
			||||||
    '-DEEK_COMPILATION=1'],
 | 
					    '-DEEK_COMPILATION=1'],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bindir = join_paths(prefix, get_option('bindir'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_layout = custom_target('squeekboard-test-layout',
 | 
				
			||||||
 | 
					    build_by_default: true,
 | 
				
			||||||
 | 
					    # meson doesn't track all inputs, cargo does
 | 
				
			||||||
 | 
					    build_always_stale: true,
 | 
				
			||||||
 | 
					    output: ['squeekboard-test-layout'],
 | 
				
			||||||
 | 
					    console: true,
 | 
				
			||||||
 | 
					    command: [cargo_build] + cargo_build_flags
 | 
				
			||||||
 | 
					        + ['--rename', 'test_layout', '@OUTPUT@', '--bin', 'test_layout'],
 | 
				
			||||||
 | 
					    install: true,
 | 
				
			||||||
 | 
					    install_dir: bindir,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										115
									
								
								src/popover.rs
									
									
									
									
									
								
							
							
						
						
									
										115
									
								
								src/popover.rs
									
									
									
									
									
								
							@ -7,9 +7,9 @@ use ::locale::compare_current_locale;
 | 
				
			|||||||
use ::locale_config::system_locale;
 | 
					use ::locale_config::system_locale;
 | 
				
			||||||
use ::resources;
 | 
					use ::resources;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use gio::ActionExt;
 | 
					 | 
				
			||||||
use gio::ActionMapExt;
 | 
					use gio::ActionMapExt;
 | 
				
			||||||
use gio::SettingsExt;
 | 
					use gio::SettingsExt;
 | 
				
			||||||
 | 
					use gio::SimpleActionExt;
 | 
				
			||||||
use glib::translate::FromGlibPtrNone;
 | 
					use glib::translate::FromGlibPtrNone;
 | 
				
			||||||
use glib::variant::ToVariant;
 | 
					use glib::variant::ToVariant;
 | 
				
			||||||
use gtk::PopoverExt;
 | 
					use gtk::PopoverExt;
 | 
				
			||||||
@ -18,8 +18,11 @@ use std::io::Write;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
mod variants {
 | 
					mod variants {
 | 
				
			||||||
    use glib;
 | 
					    use glib;
 | 
				
			||||||
 | 
					    use glib::Variant;
 | 
				
			||||||
    use glib_sys;
 | 
					    use glib_sys;
 | 
				
			||||||
 | 
					    use std::os::raw::c_char;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    use glib::ToVariant;
 | 
				
			||||||
    use glib::translate::FromGlibPtrFull;
 | 
					    use glib::translate::FromGlibPtrFull;
 | 
				
			||||||
    use glib::translate::ToGlibPtr;
 | 
					    use glib::translate::ToGlibPtr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -49,6 +52,44 @@ mod variants {
 | 
				
			|||||||
            })
 | 
					            })
 | 
				
			||||||
            .collect()
 | 
					            .collect()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// "a(ss)" variant
 | 
				
			||||||
 | 
					    /// Rust doesn't allow implementing existing traits for existing types
 | 
				
			||||||
 | 
					    pub struct ArrayPairString(pub Vec<(String, String)>);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    impl ToVariant for ArrayPairString {
 | 
				
			||||||
 | 
					        fn to_variant(&self) -> Variant {
 | 
				
			||||||
 | 
					            let tspec = "a(ss)".to_glib_none();
 | 
				
			||||||
 | 
					            let builder = unsafe {
 | 
				
			||||||
 | 
					                let vtype = glib_sys::g_variant_type_checked_(tspec.0);
 | 
				
			||||||
 | 
					                glib_sys::g_variant_builder_new(vtype)
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            let ispec = "(ss)".to_glib_none();
 | 
				
			||||||
 | 
					            for (a, b) in &self.0 {
 | 
				
			||||||
 | 
					                let a = a.to_glib_none();
 | 
				
			||||||
 | 
					                let b = b.to_glib_none();
 | 
				
			||||||
 | 
					                // string pointers are weak references
 | 
				
			||||||
 | 
					                // and will get silently invalidated
 | 
				
			||||||
 | 
					                // as soon as the source is out of scope
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    let a: *const c_char = a.0;
 | 
				
			||||||
 | 
					                    let b: *const c_char = b.0;
 | 
				
			||||||
 | 
					                    unsafe {
 | 
				
			||||||
 | 
					                        glib_sys::g_variant_builder_add(
 | 
				
			||||||
 | 
					                            builder,
 | 
				
			||||||
 | 
					                            ispec.0,
 | 
				
			||||||
 | 
					                            a, b
 | 
				
			||||||
 | 
					                        );
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            unsafe {
 | 
				
			||||||
 | 
					                let ret = glib_sys::g_variant_builder_end(builder);
 | 
				
			||||||
 | 
					                glib_sys::g_variant_builder_unref(builder);
 | 
				
			||||||
 | 
					                glib::Variant::from_glib_full(ret)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn make_menu_builder(inputs: Vec<(&str, &str)>) -> gtk::Builder {
 | 
					fn make_menu_builder(inputs: Vec<(&str, &str)>) -> gtk::Builder {
 | 
				
			||||||
@ -88,12 +129,15 @@ fn make_menu_builder(inputs: Vec<(&str, &str)>) -> gtk::Builder {
 | 
				
			|||||||
fn set_layout(kind: String, name: String) {
 | 
					fn set_layout(kind: String, name: String) {
 | 
				
			||||||
    let settings = gio::Settings::new("org.gnome.desktop.input-sources");
 | 
					    let settings = gio::Settings::new("org.gnome.desktop.input-sources");
 | 
				
			||||||
    let inputs = settings.get_value("sources").unwrap();
 | 
					    let inputs = settings.get_value("sources").unwrap();
 | 
				
			||||||
    let inputs = variants::get_tuples(inputs).into_iter();
 | 
					    let current = (kind.clone(), name.clone());
 | 
				
			||||||
    for (index, (ikind, iname)) in inputs.enumerate() {
 | 
					    let inputs = variants::get_tuples(inputs).into_iter()
 | 
				
			||||||
        if (&ikind, &iname) == (&kind, &name) {
 | 
					        .filter(|t| t != ¤t);
 | 
				
			||||||
            settings.set_uint("current", index as u32);
 | 
					    let inputs = vec![(kind, name)].into_iter()
 | 
				
			||||||
        }
 | 
					        .chain(inputs).collect();
 | 
				
			||||||
    }
 | 
					    settings.set_value(
 | 
				
			||||||
 | 
					        "sources",
 | 
				
			||||||
 | 
					        &variants::ArrayPairString(inputs).to_variant()
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
    settings.apply();
 | 
					    settings.apply();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -103,7 +147,6 @@ pub fn show(window: EekGtkKeyboard, position: ::layout::c::Bounds) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    let settings = gio::Settings::new("org.gnome.desktop.input-sources");
 | 
					    let settings = gio::Settings::new("org.gnome.desktop.input-sources");
 | 
				
			||||||
    let inputs = settings.get_value("sources").unwrap();
 | 
					    let inputs = settings.get_value("sources").unwrap();
 | 
				
			||||||
    let current = settings.get_uint("current") as usize;
 | 
					 | 
				
			||||||
    let inputs = variants::get_tuples(inputs);
 | 
					    let inputs = variants::get_tuples(inputs);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    let input_names: Vec<&str> = inputs.iter()
 | 
					    let input_names: Vec<&str> = inputs.iter()
 | 
				
			||||||
@ -152,39 +195,35 @@ pub fn show(window: EekGtkKeyboard, position: ::layout::c::Bounds) {
 | 
				
			|||||||
        height: position.width.floor() as i32,
 | 
					        height: position.width.floor() as i32,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let initial_state = input_names[current].to_variant();
 | 
					    if let Some(current_name) = input_names.get(0) {
 | 
				
			||||||
 | 
					        let current_name = current_name.to_variant();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let layout_action = gio::SimpleAction::new_stateful(
 | 
					        let layout_action = gio::SimpleAction::new_stateful(
 | 
				
			||||||
        "layout",
 | 
					            "layout",
 | 
				
			||||||
        Some(initial_state.type_()),
 | 
					            Some(current_name.type_()),
 | 
				
			||||||
        &initial_state,
 | 
					            ¤t_name,
 | 
				
			||||||
    );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let action_group = gio::SimpleActionGroup::new();
 | 
					        layout_action.connect_change_state(|_action, state| {
 | 
				
			||||||
    action_group.add_action(&layout_action);
 | 
					            match state {
 | 
				
			||||||
 | 
					                Some(v) => {
 | 
				
			||||||
 | 
					                    v.get::<String>()
 | 
				
			||||||
 | 
					                        .or_else(|| {
 | 
				
			||||||
 | 
					                            eprintln!("Variant is not string: {:?}", v);
 | 
				
			||||||
 | 
					                            None
 | 
				
			||||||
 | 
					                        })
 | 
				
			||||||
 | 
					                        .map(|state| set_layout("xkb".into(), state));
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                None => eprintln!("No variant selected"),
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let action_group = gio::SimpleActionGroup::new();
 | 
				
			||||||
 | 
					        action_group.add_action(&layout_action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        menu.insert_action_group("popup", Some(&action_group));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    menu.insert_action_group("popup", Some(&action_group));
 | 
					 | 
				
			||||||
    menu.bind_model(Some(&model), Some("popup"));
 | 
					    menu.bind_model(Some(&model), Some("popup"));
 | 
				
			||||||
 | 
					 | 
				
			||||||
    menu.connect_closed(move |_menu| {
 | 
					 | 
				
			||||||
        let state = match layout_action.get_state() {
 | 
					 | 
				
			||||||
            Some(v) => {
 | 
					 | 
				
			||||||
                let s = v.get::<String>().or_else(|| {
 | 
					 | 
				
			||||||
                    eprintln!("Variant is not string: {:?}", v);
 | 
					 | 
				
			||||||
                    None
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                // FIXME: the `get_state` docs call for unrefing,
 | 
					 | 
				
			||||||
                // but the function is nowhere to be found
 | 
					 | 
				
			||||||
                // glib::Variant::unref(v);
 | 
					 | 
				
			||||||
                s
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            None => {
 | 
					 | 
				
			||||||
                eprintln!("No variant selected");
 | 
					 | 
				
			||||||
                None
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        set_layout("xkb".into(), state.unwrap_or("us".into()));
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    menu.popup();
 | 
					    menu.popup();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@ const KEYBOARDS: &[(*const str, *const str)] = &[
 | 
				
			|||||||
    ("us", include_str!("../data/keyboards/us.yaml")),
 | 
					    ("us", include_str!("../data/keyboards/us.yaml")),
 | 
				
			||||||
    ("us_wide", include_str!("../data/keyboards/us_wide.yaml")),
 | 
					    ("us_wide", include_str!("../data/keyboards/us_wide.yaml")),
 | 
				
			||||||
    ("de", include_str!("../data/keyboards/de.yaml")),
 | 
					    ("de", include_str!("../data/keyboards/de.yaml")),
 | 
				
			||||||
 | 
					    ("de_wide", include_str!("../data/keyboards/de_wide.yaml")),
 | 
				
			||||||
    ("el", include_str!("../data/keyboards/el.yaml")),
 | 
					    ("el", include_str!("../data/keyboards/el.yaml")),
 | 
				
			||||||
    ("es", include_str!("../data/keyboards/es.yaml")),
 | 
					    ("es", include_str!("../data/keyboards/es.yaml")),
 | 
				
			||||||
    ("fi", include_str!("../data/keyboards/fi.yaml")),
 | 
					    ("fi", include_str!("../data/keyboards/fi.yaml")),
 | 
				
			||||||
@ -42,6 +43,7 @@ const LAYOUT_NAMES: &[(*const str, *const str)] = &[
 | 
				
			|||||||
    ("de-DE", include_str!("../data/langs/de-DE.txt")),
 | 
					    ("de-DE", include_str!("../data/langs/de-DE.txt")),
 | 
				
			||||||
    ("en-US", include_str!("../data/langs/en-US.txt")),
 | 
					    ("en-US", include_str!("../data/langs/en-US.txt")),
 | 
				
			||||||
    ("es-ES", include_str!("../data/langs/es-ES.txt")),
 | 
					    ("es-ES", include_str!("../data/langs/es-ES.txt")),
 | 
				
			||||||
 | 
					    ("ja-JP", include_str!("../data/langs/ja-JP.txt")),
 | 
				
			||||||
    ("pl-PL", include_str!("../data/langs/pl-PL.txt")),
 | 
					    ("pl-PL", include_str!("../data/langs/pl-PL.txt")),
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										7
									
								
								src/style.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/style.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					#ifndef __STYLE_H
 | 
				
			||||||
 | 
					#define __STYLE_H
 | 
				
			||||||
 | 
					#include "gtk/gtk.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GtkCssProvider *squeek_load_style();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										124
									
								
								src/style.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								src/style.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,124 @@
 | 
				
			|||||||
 | 
					/* 
 | 
				
			||||||
 | 
					 * Copyright (C) 2000 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, see <http://www.gnu.org/licenses/>.Free
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! CSS data loading */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::env;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use glib::object::ObjectExt;
 | 
				
			||||||
 | 
					use util::Warn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Gathers stuff defined in C or called by C
 | 
				
			||||||
 | 
					pub mod c {
 | 
				
			||||||
 | 
					    use super::*;
 | 
				
			||||||
 | 
					    use gio;
 | 
				
			||||||
 | 
					    use gtk;
 | 
				
			||||||
 | 
					    use gtk_sys;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    use gtk::CssProviderExt;
 | 
				
			||||||
 | 
					    use glib::translate::ToGlibPtr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Loads the layout style based on current theme
 | 
				
			||||||
 | 
					    /// without having to worry about string allocation
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_load_style() -> *const gtk_sys::GtkCssProvider {
 | 
				
			||||||
 | 
					        unsafe { gtk::set_initialized() };
 | 
				
			||||||
 | 
					        let theme = gtk::Settings::get_default()
 | 
				
			||||||
 | 
					            .map(|settings| get_theme_name(&settings));
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        let css_name = path_from_theme(theme);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let resource_name = if gio::resources_get_info(
 | 
				
			||||||
 | 
					            &css_name,
 | 
				
			||||||
 | 
					            gio::ResourceLookupFlags::NONE
 | 
				
			||||||
 | 
					        ).is_ok() {
 | 
				
			||||||
 | 
					            css_name
 | 
				
			||||||
 | 
					        } else { // use default if this path doesn't exist
 | 
				
			||||||
 | 
					            path_from_theme(None)
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let provider = gtk::CssProvider::new();
 | 
				
			||||||
 | 
					        provider.load_from_resource(&resource_name);
 | 
				
			||||||
 | 
					        provider.to_glib_full()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// not Adwaita, but rather fall back to default
 | 
				
			||||||
 | 
					const DEFAULT_THEME_NAME: &str = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct GtkTheme {
 | 
				
			||||||
 | 
					    name: String,
 | 
				
			||||||
 | 
					    variant: Option<String>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Gets theme as determined by the toolkit
 | 
				
			||||||
 | 
					/// Ported from GTK's gtksettings.c
 | 
				
			||||||
 | 
					fn get_theme_name(settings: >k::Settings) -> GtkTheme {
 | 
				
			||||||
 | 
					    let env_theme = env::var("GTK_THEME")
 | 
				
			||||||
 | 
					        .map(|theme| {
 | 
				
			||||||
 | 
					            let mut parts = theme.splitn(2, ":");
 | 
				
			||||||
 | 
					            GtkTheme {
 | 
				
			||||||
 | 
					                // guaranteed at least empty string
 | 
				
			||||||
 | 
					                // as the first result from splitting a string
 | 
				
			||||||
 | 
					                name: parts.next().unwrap().into(),
 | 
				
			||||||
 | 
					                variant: parts.next().map(String::from)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .map_err(|e| {
 | 
				
			||||||
 | 
					            match &e {
 | 
				
			||||||
 | 
					                env::VarError::NotPresent => {},
 | 
				
			||||||
 | 
					                e => eprintln!("GTK_THEME variable invalid: {}", e),
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            e
 | 
				
			||||||
 | 
					        }).ok();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    match env_theme {
 | 
				
			||||||
 | 
					        Some(theme) => theme,
 | 
				
			||||||
 | 
					        None => GtkTheme {
 | 
				
			||||||
 | 
					            name: {
 | 
				
			||||||
 | 
					                settings.get_property("gtk-theme-name")
 | 
				
			||||||
 | 
					                    .ok_warn("No theme name")
 | 
				
			||||||
 | 
					                    .and_then(|value| value.get::<String>())
 | 
				
			||||||
 | 
					                    .unwrap_or(DEFAULT_THEME_NAME.into())
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            variant: {
 | 
				
			||||||
 | 
					                settings.get_property("gtk-application-prefer-dark-theme")
 | 
				
			||||||
 | 
					                    .ok_warn("No settings key")
 | 
				
			||||||
 | 
					                    .and_then(|value| value.get::<bool>())
 | 
				
			||||||
 | 
					                    .and_then(|dark_preferred| match dark_preferred {
 | 
				
			||||||
 | 
					                        true => Some("dark".into()),
 | 
				
			||||||
 | 
					                        false => None,
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn path_from_theme(theme: Option<GtkTheme>) -> String {
 | 
				
			||||||
 | 
					    format!(
 | 
				
			||||||
 | 
					        "/sm/puri/squeekboard/style{}.css",
 | 
				
			||||||
 | 
					        match theme {
 | 
				
			||||||
 | 
					            Some(GtkTheme { name, variant: Some(variant) }) => {
 | 
				
			||||||
 | 
					                format!("-{}:{}", name, variant)
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            Some(GtkTheme { name, variant: None }) => format!("-{}", name),
 | 
				
			||||||
 | 
					            None => "".into(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										78
									
								
								src/tests.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/tests.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					/*! Testing functionality */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use ::data::Layout;
 | 
				
			||||||
 | 
					use xkbcommon::xkb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use ::util::WarningHandler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct CountAndPrint(u32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl WarningHandler for CountAndPrint {
 | 
				
			||||||
 | 
					    fn handle(&mut self, warning: &str) {
 | 
				
			||||||
 | 
					        self.0 = self.0 + 1;
 | 
				
			||||||
 | 
					        println!("{}", warning);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl CountAndPrint {
 | 
				
			||||||
 | 
					    fn new() -> CountAndPrint {
 | 
				
			||||||
 | 
					        CountAndPrint(0)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn check_builtin_layout(name: &str) {
 | 
				
			||||||
 | 
					    check_layout(Layout::from_resource(name).expect("Invalid layout data"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn check_layout_file(path: &str) {
 | 
				
			||||||
 | 
					    check_layout(Layout::from_file(path.into()).expect("Invalid layout file"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn check_layout(layout: Layout) {
 | 
				
			||||||
 | 
					    let handler = CountAndPrint::new();
 | 
				
			||||||
 | 
					    let (layout, handler) = layout.build(handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if handler.0 > 0 {
 | 
				
			||||||
 | 
					        println!("{} mistakes in layout", handler.0)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let layout = layout.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);
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        _ => {},
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if handler.0 > 0 {
 | 
				
			||||||
 | 
					        panic!("Layout contains mistakes");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										21
									
								
								src/util.rs
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								src/util.rs
									
									
									
									
									
								
							@ -177,6 +177,27 @@ impl<T> Borrow<Rc<T>> for Pointer<T> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Sugar for logging errors in results
 | 
				
			||||||
 | 
					pub trait Warn {
 | 
				
			||||||
 | 
					    type Value;
 | 
				
			||||||
 | 
					    fn ok_warn(self, msg: &str) -> Option<Self::Value>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T, E: std::error::Error> Warn for Result<T, E> {
 | 
				
			||||||
 | 
					    type Value = T;
 | 
				
			||||||
 | 
					    fn ok_warn(self, msg: &str) -> Option<T> {
 | 
				
			||||||
 | 
					        self.map_err(|e| {
 | 
				
			||||||
 | 
					            eprintln!("{}: {}", msg, e);
 | 
				
			||||||
 | 
					            e
 | 
				
			||||||
 | 
					        }).ok()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub trait WarningHandler {
 | 
				
			||||||
 | 
					    /// Handle a warning
 | 
				
			||||||
 | 
					    fn handle(&mut self, warning: &str);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
				
			|||||||
@ -49,7 +49,7 @@ endforeach
 | 
				
			|||||||
# and the need to call it manually
 | 
					# and the need to call it manually
 | 
				
			||||||
foreach layout : [
 | 
					foreach layout : [
 | 
				
			||||||
    'us', 'us_wide',
 | 
					    'us', 'us_wide',
 | 
				
			||||||
    'de',
 | 
					    'de', 'de_wide',
 | 
				
			||||||
    'el',
 | 
					    'el',
 | 
				
			||||||
    'es',
 | 
					    'es',
 | 
				
			||||||
    'fi',
 | 
					    'fi',
 | 
				
			||||||
@ -62,7 +62,7 @@ foreach layout : [
 | 
				
			|||||||
    test(
 | 
					    test(
 | 
				
			||||||
        'test_layout_' + layout,
 | 
					        'test_layout_' + layout,
 | 
				
			||||||
        cargo_script,
 | 
					        cargo_script,
 | 
				
			||||||
        args: ['', 'run', '--example', 'test_layout', layout]
 | 
					        args: ['run', '--example', 'test_layout', layout]
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
endforeach
 | 
					endforeach
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -12,4 +12,4 @@ for DIR in ${DIRS}; do
 | 
				
			|||||||
  fi;
 | 
					  fi;
 | 
				
			||||||
done;
 | 
					done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exec @bindir@/squeekboard-real
 | 
					exec $(which squeekboard)
 | 
				
			||||||
		Reference in New Issue
	
	Block a user