diff --git a/cros-keyboard-map/.gitignore b/cros-keyboard-map/.gitignore
new file mode 100644
index 0000000..540682e
--- /dev/null
+++ b/cros-keyboard-map/.gitignore
@@ -0,0 +1,2 @@
+cros.conf
+pkg.log
diff --git a/cros-keyboard-map/LICENSE b/cros-keyboard-map/LICENSE
new file mode 100644
index 0000000..67b6ad2
--- /dev/null
+++ b/cros-keyboard-map/LICENSE
@@ -0,0 +1,28 @@
+BSD 3-Clause License
+
+Copyright (c) 2023, WeirdTreeThing
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/cros-keyboard-map/README.md b/cros-keyboard-map/README.md
new file mode 100644
index 0000000..6061e97
--- /dev/null
+++ b/cros-keyboard-map/README.md
@@ -0,0 +1,18 @@
+
Utility to generate keyd configurations for use on Chromebooks
+
+## List of supported distributions
+- Alpine
+- Arch Linux
+- Chimera Linux
+- Debian
+- Fedora
+- openSUSE
+- Ubuntu
+- Void Linux
+
+### Instructions
+1. git clone https://github.com/WeirdTreeThing/cros-keyboard-map
+2. cd cros-keyboard-map
+3. ./install.sh
+
+Thanks to rvaiya for creating [keyd](https://github.com/rvaiya/keyd).
diff --git a/cros-keyboard-map/configs/61-pixel-keyboard.hwdb b/cros-keyboard-map/configs/61-pixel-keyboard.hwdb
new file mode 100644
index 0000000..1761e21
--- /dev/null
+++ b/cros-keyboard-map/configs/61-pixel-keyboard.hwdb
@@ -0,0 +1,3 @@
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnGoogle:pn*:pvr*
+ KEYBOARD_KEY_d8=leftmeta
+
diff --git a/cros-keyboard-map/configs/cros-pixel.conf b/cros-keyboard-map/configs/cros-pixel.conf
new file mode 100644
index 0000000..ce91e39
--- /dev/null
+++ b/cros-keyboard-map/configs/cros-pixel.conf
@@ -0,0 +1,44 @@
+[ids]
+# Pixelbook and Pixelbook Go use AT Keyboard (0001:0001)
+# Nocturne uses Google hammer (18d1:5030)
+0001:0001
+18d1:5030
+
+[main]
+f1 = back
+f2 = refresh
+f3 = f11
+f4 = scale
+f5 = brightnessdown
+f6 = brightnessup
+f7 = playpause
+f8 = mute
+f9 = volumedown
+f10 = volumeup
+f13 = f13
+
+[meta]
+f1 = f1
+f2 = f2
+f3 = f3
+f4 = f4
+f5 = f5
+f6 = f6
+f7 = f7
+f8 = f8
+f9 = f9
+f10 = f10
+f13 = f13
+
+
+[alt]
+backspace = delete
+f5 = kbdillumdown
+f6 = kbdillumup
+
+[control]
+f5 = print
+
+
+[control+alt]
+backspace = C-A-delete
diff --git a/cros-keyboard-map/configs/cros-sarien.conf b/cros-keyboard-map/configs/cros-sarien.conf
new file mode 100644
index 0000000..521faf0
--- /dev/null
+++ b/cros-keyboard-map/configs/cros-sarien.conf
@@ -0,0 +1,39 @@
+# Config for Sarien and its variant, Arcada
+[ids]
+# AT keyboard is device 0001:0001
+0001:0001
+
+[main]
+back = back
+refresh = refresh
+zoom = f11
+scale = scale
+print = print
+camera = brightnessdown
+prog1 = brightnessup
+mute = mute
+volumedown = volumedown
+volumeup = volumeup
+sleep = coffee
+
+[meta]
+back = f1
+refresh = f2
+zoom = f3
+scale = f4
+camera = f5
+prog1 = f6
+mute = f7
+volumedown = f8
+volumeup = f9
+switchvideomode = f12
+
+
+[alt]
+backspace = delete
+meta = capslock
+camera = kbdillumdown
+prog1 = kbdillumup
+
+[control+alt]
+backspace = C-A-delete
diff --git a/cros-keyboard-map/cros-keyboard-map.py b/cros-keyboard-map/cros-keyboard-map.py
new file mode 100644
index 0000000..89fe57f
--- /dev/null
+++ b/cros-keyboard-map/cros-keyboard-map.py
@@ -0,0 +1,186 @@
+#!/usr/bin/env python3
+
+import argparse
+import platform
+
+device_ids = {
+ "k:0000:0000", # cros_ec keyboard
+ "k:0001:0001", # AT keyboard
+ "k:18d1:503c", # Google Inc. Hammer
+ "k:18d1:5050", # Google Inc. Hammer
+ "k:18d1:504c", # Google Inc. Hammer
+ "k:18d1:5052", # Google Inc. Hammer
+ "k:18d1:5057", # Google Inc. Hammer
+ "k:18d1:505b", # Google Inc. Hammer
+ "k:18d1:5030", # Google Inc. Hammer
+ "k:18d1:503d", # Google Inc. Hammer
+ "k:18d1:5044", # Google Inc. Hammer
+ "k:18d1:5061", # Google Inc. Hammer
+ "k:18d1:502b", # Google Inc. Hammer
+}
+
+vivaldi_keys = {
+ "x86_64": {
+ "90": "previoussong",
+ "91": "zoom",
+ "92": "scale",
+ "93": "sysrq",
+ "94": "brightnessdown",
+ "95": "brightnessup",
+ "97": "kbdillumdown",
+ "98": "kbdillumup",
+ "99": "nextsong",
+ "9A": "playpause",
+ "9B": "micmute",
+ "9E": "kbdillumtoggle",
+ "A0": "mute",
+ "AE": "volumedown",
+ "B0": "volumeup",
+ "E9": "forward",
+ "EA": "back",
+ "E7": "refresh",
+ },
+ "arm": {
+ "158": "back",
+ "159": "forward",
+ "173": "refresh",
+ "372": "zoom",
+ "120": "scale",
+ "224": "brightnessdown",
+ "225": "brightnessup",
+ "113": "mute",
+ "114": "volumedown",
+ "115": "volumeup",
+ "99" : "sysrq",
+ }
+}
+
+def get_arch():
+ return platform.uname().machine
+
+def get_ids_string(device_ids):
+ return "\n".join(device_ids)
+
+def get_dt_layout():
+ keys = []
+ keycodes = []
+
+ fdt = libfdt.Fdt(open("/sys/firmware/fdt", "rb").read())
+ currentnode = fdt.first_subnode(0)
+
+ while True:
+ try:
+ if fdt.get_name(currentnode) == "keyboard-controller":
+ prop = fdt.getprop(currentnode, "linux,keymap")
+ keys = prop.as_uint32_list()
+ currentnode = fdt.next_node(currentnode, 10)[0]
+ except:
+ break
+
+ if not keys:
+ return ""
+
+ for key in keys:
+ keycode = str(key & 0xFFFF)
+ if keycode in vivaldi_keys["arm"]:
+ keycodes.append(keycode)
+ return keycodes
+
+def get_physmap_data():
+ if get_arch() == "x86_64":
+ try:
+ with open("/sys/bus/platform/devices/i8042/serio0/function_row_physmap", "r") as file:
+ return file.read().strip().split()
+ except FileNotFoundError:
+ return ""
+ else:
+ return get_dt_layout()
+
+def get_functional_row(physmap, use_vivaldi, super_is_held, super_inverted):
+ arch = get_arch()
+ if arch != "x86_64":
+ arch = "arm"
+
+ i = 0
+ result = ""
+ for code in physmap:
+ i += 1
+ # Map zoom to f11 since most applications wont listen to zoom
+ mapping = "f11" if vivaldi_keys[arch][code] == "zoom" \
+ else vivaldi_keys[arch][code]
+
+ match [super_is_held, use_vivaldi, super_inverted]:
+ case [True, True, False] | [False, True, True]:
+ result += f"{vivaldi_keys[arch][code]} = f{i}\n"
+ case [True, False, False] | [False, False, True]:
+ result += f"f{i} = f{i}\n"
+ case [False, True, False] | [True, True, True]:
+ result += f"{vivaldi_keys[arch][code]} = {mapping}\n"
+ case [False, False, False] | [True, False, True]:
+ result += f"f{i} = {mapping}\n"
+
+ return result
+
+def get_keyd_config(physmap, inverted):
+ config = f"""\
+[ids]
+{get_ids_string(device_ids)}
+
+[main]
+{get_functional_row(physmap, use_vivaldi=False, super_is_held=False, super_inverted=inverted)}
+{get_functional_row(physmap, use_vivaldi=True, super_is_held=False, super_inverted=inverted)}
+f13=coffee
+sleep=coffee
+
+[meta]
+{get_functional_row(physmap, use_vivaldi=False, super_is_held=True, super_inverted=inverted)}
+{get_functional_row(physmap, use_vivaldi=True, super_is_held=True, super_inverted=inverted)}
+
+[alt]
+backspace = delete
+brightnessdown = kbdillumdown
+brightnessup = kbdillumup
+f6 = kbdillumdown
+f7 = kbdillumup
+
+[control]
+f5 = sysrq
+scale = sysrq
+
+[altgr]
+backspace = delete
+left = home
+right = end
+up = pageup
+down = pagedown
+
+[control+alt]
+backspace = C-A-delete
+"""
+ return config
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-f", "--file", default="cros.conf", help="path to save config (default: cros.conf)")
+ parser.add_argument("-i", "--inverted", action="store_true",
+ help="use functional keys by default and media keys when super is held")
+ args = vars(parser.parse_args())
+
+
+
+ physmap = get_physmap_data()
+ if not physmap:
+ print("no function row mapping found, using default mapping")
+ if get_arch() == "x86_64":
+ physmap = ['EA', 'E9', 'E7', '91', '92', '94', '95', 'A0', 'AE', 'B0']
+ else:
+ physmap = ['158', '159', '173', '372', '120', '224', '225', '113', '114', '115']
+
+ config = get_keyd_config(physmap, args["inverted"])
+ with open(args["file"], "w") as conf:
+ conf.write(config)
+
+if __name__ == "__main__":
+ if get_arch() != "x86_64":
+ import libfdt
+ main()
diff --git a/cros-keyboard-map/install.sh b/cros-keyboard-map/install.sh
new file mode 100755
index 0000000..c7eb9ba
--- /dev/null
+++ b/cros-keyboard-map/install.sh
@@ -0,0 +1,167 @@
+#!/bin/bash
+
+set -e
+
+# void, alpine, arch, and suse have packages
+# need to build on fedora (without terra) and debian/ubuntu
+
+ROOT=$(pwd)
+
+# fancy color
+printf "\033[94m"
+
+if [ -f /usr/bin/apt ]; then
+ distro="deb"
+elif [ -f /usr/bin/zypper ]; then
+ distro="suse"
+elif [ -f /usr/bin/pacman ]; then
+ distro="arch"
+elif [ -f /usr/bin/dnf4 ]; then
+ distro="fedora"
+elif [ -f /sbin/apk ]; then
+ distro="alpine"
+elif [ -f /bin/xbps-install ]; then
+ distro="void"
+elif grep 'ID=nixos' /etc/os-release &>> pkg.log; then
+ echo "WARNING: This script will not install keyd on NixOS, but can install the configuration for you."
+ printf "Continue? (y/N) "
+ read -r NIXINSTALL
+ [[ $NIXINSTALL =~ ^[Yy]$ ]] || exit 1
+ distro="nixos"
+fi
+
+if which sudo &>/dev/null; then
+ privesc="sudo"
+elif which doas &>/dev/null; then
+ privesc="doas"
+elif which run0 &>/dev/null; then
+ privesc="run0"
+fi
+
+echo "Installing, this may take some time...."
+
+# Fedora with the terra repo (Ultramarine) has keyd packaged
+[ "$distro" = "fedora" ] && dnf4 info keyd -y&>> pkg.log && FEDORA_HAS_KEYD=1
+
+if ! which keyd &>/dev/null && [ "$distro" != "nixos" ] ; then
+ build_keyd=1
+ # if keyd isnt installed
+
+ # Debian-based distros and Fedora don't have keyd in the repos, ask the user to compile it from source.
+ if [ "distro" = "fedora" ] && [ ! "$FEDORA_HAS_KEYD" = "1" ] || [ "$distro" = "deb" ]; then
+ echo "This script can compile keyd for you or you can choose to get it from another source."
+ printf "Compile keyd? (Y/n) "
+ read -r COMPKEYD
+ [[ $COMPKEYD =~ ^[Nn]$ ]] && build_keyd=0
+ fi
+
+ if [ "$build_keyd" = "1" ]; then
+ echo "Installing keyd dependencies"
+ case $distro in
+ deb)
+ $privesc apt install -y build-essential git &>> pkg.log
+ ;;
+ fedora)
+ [ ! "$FEDORA_HAS_KEYD" = "1" ] && $privesc dnf4 install -y kernel-headers gcc make &>> pkg.log
+ ;;
+ esac
+ fi
+
+ if ( [ "distro" = "fedora" ] && [ ! "$FEDORA_HAS_KEYD" = "1" ] || [ "$distro" = "deb" ] ) && [ "$build_keyd" = "1" ]; then
+ echo "Compiling keyd"
+ git clone https://github.com/rvaiya/keyd &>> pkg.log
+ cd keyd
+ make &>> pkg.log
+ $privesc make install
+ cd ..
+ else
+ echo "Installing keyd"
+ case $distro in
+ suse)
+ $privesc zypper --non-interactive install keyd &>> pkg.log
+ ;;
+ arch)
+ $privesc pacman -S --noconfirm keyd &>> pkg.log
+ ;;
+ alpine)
+ $privesc apk add --no-interactive keyd &>> pkg.log
+ ;;
+ void)
+ $privesc xbps-install -S keyd -y &>> pkg.log
+ ;;
+ fedora)
+ $privesc dnf4 install -y keyd &>> pkg.log
+ ;;
+ esac
+ fi
+fi
+
+echo "Generating config"
+# Handle any special cases
+if (grep -E "^(Nocturne|Atlas|Eve)$" /sys/class/dmi/id/product_name &> /dev/null)
+then
+ cp configs/cros-pixel.conf cros.conf
+ $privesc mkdir -p /etc/udev/hwdb.d/
+ $privesc cp configs/61-pixel-keyboard.hwdb /etc/udev/hwdb.d/
+ $privesc udevadm hwdb --update
+ $privesc udevadm trigger
+elif (grep -E "^(Sarien|Arcada)$" /sys/class/dmi/id/product_name &> /dev/null)
+then
+ cp configs/cros-sarien.conf cros.conf
+else
+ printf "By default, the top row keys will do their special function (brightness, volume, browser control, etc).\n"
+ printf "Holding the search key will make the top row keys act like fn keys (f1, f2, f3, etc).\n"
+ printf "Would you like to invert this? (y/N) "
+ read -r INVERT
+ if [ "$distro" == "nixos" ] && ! which python3 &>/dev/null; then
+ [[ $INVERT =~ ^[Yy]$ ]] && nix-shell -p python3 --run "python3 cros-keyboard-map.py -i" ||
+ nix-shell -p python3 --run "python3 cros-keyboard-map.py"
+ else
+ [[ $INVERT =~ ^[Yy]$ ]] && python3 cros-keyboard-map.py -i || python3 cros-keyboard-map.py
+ fi
+fi
+
+echo "Installing config"
+$privesc mkdir -p /etc/keyd
+$privesc cp cros.conf /etc/keyd
+
+echo "Enabling keyd"
+case $distro in
+ alpine)
+ # Chimera uses apk like alpine but uses dinit instead of openrc
+ if [ -f /usr/bin/dinitctl ]; then
+ $privesc dinitctl start keyd
+ $privesc dinitctl enable keyd
+ else
+ $privesc rc-update add keyd
+ $privesc rc-service keyd restart
+ fi
+ ;;
+ void)
+ if [ -f /usr/bin/sv ]; then
+ $privesc ln -s /etc/sv/keyd /var/service
+ $privesc sv enable keyd
+ $privesc sv start keyd
+ else
+ echo "This script can only be used for Void Linux using 'runit' init system. Other init system on Void Linux are currently unsupported."
+ echo "I'M OUTTA HERE!"
+ exit 1
+ fi
+ ;;
+ *)
+ $privesc systemctl enable keyd
+ $privesc systemctl restart keyd
+ ;;
+esac
+
+echo "Installing libinput configuration"
+$privesc mkdir -p /etc/libinput
+if [ -f /etc/libinput/local-overrides.quirks ]; then
+ cat $ROOT/local-overrides.quirks | $privesc tee -a /etc/libinput/local-overrides.quirks > /dev/null
+else
+ $privesc cp $ROOT/local-overrides.quirks /etc/libinput/local-overrides.quirks
+fi
+
+echo "Done"
+# reset color
+printf "\033[0m"
diff --git a/cros-keyboard-map/keyd/.gitattributes b/cros-keyboard-map/keyd/.gitattributes
new file mode 100644
index 0000000..9f7fb19
--- /dev/null
+++ b/cros-keyboard-map/keyd/.gitattributes
@@ -0,0 +1,3 @@
+data/* -diff
+layouts/* -diff
+src/unicode.c -diff
diff --git a/cros-keyboard-map/keyd/.gitignore b/cros-keyboard-map/keyd/.gitignore
new file mode 100644
index 0000000..c5b3b1e
--- /dev/null
+++ b/cros-keyboard-map/keyd/.gitignore
@@ -0,0 +1,11 @@
+*.swp
+*.swn
+*.swo
+*.out
+tags
+bin/
+*.o
+*.gch
+__pycache__
+test.log
+keyd.service
diff --git a/cros-keyboard-map/keyd/CONTRIBUTING.md b/cros-keyboard-map/keyd/CONTRIBUTING.md
new file mode 100644
index 0000000..964d927
--- /dev/null
+++ b/cros-keyboard-map/keyd/CONTRIBUTING.md
@@ -0,0 +1,7 @@
+The best way to contribute is to file an issue with any bugs you find or any
+features you think belong in keyd. Small issues pertaining to things like
+compilation on different platforms can be submitted as PRs but please avoid
+sending in patches which change core functionality without filing an issue
+first. The key logic can be deceptively simple and contains a few subtleties
+that need to be managed properly. Additionally, I reserve the right to reject
+any features which I do not think belong in keyd.
diff --git a/cros-keyboard-map/keyd/LICENSE b/cros-keyboard-map/keyd/LICENSE
new file mode 100644
index 0000000..b10de5c
--- /dev/null
+++ b/cros-keyboard-map/keyd/LICENSE
@@ -0,0 +1,21 @@
+MIT/X Consortium License
+
+© 2020 Raheman Vaiya
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/cros-keyboard-map/keyd/Makefile b/cros-keyboard-map/keyd/Makefile
new file mode 100644
index 0000000..f600179
--- /dev/null
+++ b/cros-keyboard-map/keyd/Makefile
@@ -0,0 +1,114 @@
+.PHONY: all clean install uninstall debug man compose test-harness
+VERSION=2.5.0
+COMMIT=$(shell git describe --no-match --always --abbrev=7 --dirty)
+VKBD=uinput
+PREFIX?=/usr/local
+
+CONFIG_DIR?=/etc/keyd
+SOCKET_PATH=/var/run/keyd.socket
+
+CFLAGS:=-DVERSION=\"v$(VERSION)\ \($(COMMIT)\)\" \
+ -I/usr/local/include \
+ -L/usr/local/lib \
+ -Wall \
+ -Wextra \
+ -Wno-unused \
+ -std=c11 \
+ -DSOCKET_PATH=\"$(SOCKET_PATH)\" \
+ -DCONFIG_DIR=\"$(CONFIG_DIR)\" \
+ -DDATA_DIR=\"$(PREFIX)/share/keyd\" \
+ -D_FORTIFY_SOURCE=2 \
+ -D_DEFAULT_SOURCE \
+ -Werror=format-security \
+ $(CFLAGS)
+
+platform=$(shell uname -s)
+
+ifeq ($(platform), Linux)
+ COMPAT_FILES=
+else
+ LDFLAGS+=-linotify
+ COMPAT_FILES=
+endif
+
+all:
+ -mkdir bin
+ cp scripts/keyd-application-mapper bin/
+ $(CC) $(CFLAGS) -O3 $(COMPAT_FILES) src/*.c src/vkbd/$(VKBD).c -lpthread -o bin/keyd $(LDFLAGS)
+debug:
+ CFLAGS="-g -fsanitize=address -Wunused" $(MAKE)
+compose:
+ -mkdir data
+ ./scripts/generate_xcompose
+man:
+ for f in docs/*.scdoc; do \
+ target=$${f%%.scdoc}.1.gz; \
+ target=data/$${target##*/}; \
+ scdoc < "$$f" | gzip > "$$target"; \
+ done
+install:
+
+ @if [ -e /run/systemd/system ]; then \
+ sed -e 's#@PREFIX@#$(PREFIX)#' keyd.service.in > keyd.service; \
+ mkdir -p $(DESTDIR)$(PREFIX)/lib/systemd/system/; \
+ install -Dm644 keyd.service $(DESTDIR)$(PREFIX)/lib/systemd/system/keyd.service; \
+ else \
+ echo "NOTE: systemd not found, you will need to manually add keyd to your system's init process."; \
+ fi
+
+ @if [ "$(VKBD)" = "usb-gadget" ]; then \
+ sed -e 's#@PREFIX@#$(PREFIX)#' src/vkbd/usb-gadget.service.in > src/vkbd/usb-gadget.service; \
+ install -Dm644 src/vkbd/usb-gadget.service $(DESTDIR)$(PREFIX)/lib/systemd/system/keyd-usb-gadget.service; \
+ install -Dm755 src/vkbd/usb-gadget.sh $(DESTDIR)$(PREFIX)/bin/keyd-usb-gadget.sh; \
+ fi
+
+ mkdir -p $(DESTDIR)$(CONFIG_DIR)
+ mkdir -p $(DESTDIR)$(PREFIX)/bin/
+ mkdir -p $(DESTDIR)$(PREFIX)/share/keyd/
+ mkdir -p $(DESTDIR)$(PREFIX)/share/keyd/layouts/
+ mkdir -p $(DESTDIR)$(PREFIX)/share/man/man1/
+ mkdir -p $(DESTDIR)$(PREFIX)/share/doc/keyd/
+ mkdir -p $(DESTDIR)$(PREFIX)/share/doc/keyd/examples/
+
+ -groupadd keyd
+ install -m755 bin/* $(DESTDIR)$(PREFIX)/bin/
+ install -m644 docs/*.md $(DESTDIR)$(PREFIX)/share/doc/keyd/
+ install -m644 examples/* $(DESTDIR)$(PREFIX)/share/doc/keyd/examples/
+ install -m644 layouts/* $(DESTDIR)$(PREFIX)/share/keyd/layouts
+ cp -r data/gnome-* $(DESTDIR)$(PREFIX)/share/keyd
+ install -m644 data/*.1.gz $(DESTDIR)$(PREFIX)/share/man/man1/
+ install -m644 data/keyd.compose $(DESTDIR)$(PREFIX)/share/keyd/
+
+uninstall:
+ -groupdel keyd
+ rm -rf $(DESTDIR)$(PREFIX)/lib/systemd/system/keyd.service \
+ $(DESTDIR)$(PREFIX)/bin/keyd \
+ $(DESTDIR)$(PREFIX)/bin/keyd-application-mapper \
+ $(DESTDIR)$(PREFIX)/share/doc/keyd/ \
+ $(DESTDIR)$(PREFIX)/share/man/man1/keyd*.gz \
+ $(DESTDIR)$(PREFIX)/share/keyd/ \
+ $(DESTDIR)$(PREFIX)/lib/systemd/system/keyd-usb-gadget.service \
+ $(DESTDIR)$(PREFIX)/bin/keyd-usb-gadget.sh \
+ $(DESTDIR)$(PREFIX)/lib/systemd/system/keyd.service
+clean:
+ -rm -rf bin keyd.service src/vkbd/usb-gadget.service
+test:
+ @cd t; \
+ for f in *.sh; do \
+ ./$$f; \
+ done
+test-io:
+ -mkdir bin
+ $(CC) \
+ -DDATA_DIR= \
+ -o bin/test-io \
+ t/test-io.c \
+ src/keyboard.c \
+ src/string.c \
+ src/macro.c \
+ src/config.c \
+ src/log.c \
+ src/ini.c \
+ src/keys.c \
+ src/unicode.c && \
+ ./bin/test-io t/test.conf t/*.t
diff --git a/cros-keyboard-map/keyd/README.md b/cros-keyboard-map/keyd/README.md
new file mode 100644
index 0000000..4ca16a6
--- /dev/null
+++ b/cros-keyboard-map/keyd/README.md
@@ -0,0 +1,338 @@
+[](https://ko-fi.com/rvaiya)
+
+# Impetus
+
+[](https://repology.org/project/keyd/versions)
+
+Linux lacks a good key remapping solution. In order to achieve satisfactory
+results a medley of tools need to be employed (e.g xcape, xmodmap) with the end
+result often being tethered to a specified environment (X11). keyd attempts to
+solve this problem by providing a flexible system wide daemon which remaps keys
+using kernel level input primitives (evdev, uinput).
+
+# Note on v2
+
+The config format has undergone several iterations since the first
+release. For those migrating their configs from v1 it is best
+to reread the [man page](https://raw.githubusercontent.com/rvaiya/keyd/refs/heads/master/docs/keyd.scdoc) (`man keyd`).
+
+See also: [changelog](docs/CHANGELOG.md).
+
+# Goals
+
+ - Speed (a hand tuned input loop written in C that takes <<1ms)
+ - Simplicity (a [config format](#sample-config) that is intuitive)
+ - Consistency (modifiers that [play nicely with layers](https://github.com/rvaiya/keyd/blob/6dc2d5c4ea76802fd192b143bdd53b1787fd6deb/docs/keyd.scdoc#L128) by default)
+ - Modularity (a UNIXy core extensible through the use of an [IPC](https://github.com/rvaiya/keyd/blob/90973686723522c2e44d8e90bb3508a6da625a20/docs/keyd.scdoc#L391) mechanism)
+
+# Features
+
+keyd has several unique features many of which are traditionally only
+found in custom keyboard firmware like [QMK](https://github.com/qmk/qmk_firmware)
+as well as some which are unique to keyd.
+
+Some of the more interesting ones include:
+
+- Layers (with support for [hybrid modifiers](https://github.com/rvaiya/keyd/blob/6dc2d5c4ea76802fd192b143bdd53b1787fd6deb/docs/keyd.scdoc#L128)).
+- Key overloading (different behaviour on tap/hold).
+- Keyboard specific configuration.
+- Instantaneous remapping (no more flashing :)).
+- A client-server model that facilitates scripting and display server agnostic application remapping. (Currently ships with support for X, sway, and gnome (wayland)).
+- System wide config (works in a VT).
+- First class support for modifier overloading.
+- Unicode support.
+
+### keyd is for people who:
+
+ - Would like to experiment with custom [layers](https://docs.qmk.fm/feature_layers) (i.e custom shift keys)
+ and oneshot modifiers.
+ - Want to have multiple keyboards with different layouts on the same machine.
+ - Want to be able to remap `C-1` without breaking modifier semantics.
+ - Want a keyboard config format which is easy to grok.
+ - Like tiny daemons that adhere to the Unix philosophy.
+ - Want to put the control and escape keys where God intended.
+ - Wish to be able to switch to a VT to debug something without breaking their keymap.
+
+### What keyd isn't:
+
+ - A tool for programming individual key up/down events.
+
+# Dependencies
+
+ - Your favourite C compiler
+ - Linux kernel headers (already present on most systems)
+
+## Optional
+
+ - python (for application specific remapping)
+ - python-xlib (only for X support)
+ - dbus-python (only for KDE support)
+
+# Installation
+
+*Note:* master serves as the development branch, things may occasionally break
+between releases. Releases are [tagged](https://github.com/rvaiya/keyd/tags), and should be considered stable.
+
+## From Source
+
+ git clone https://github.com/rvaiya/keyd
+ cd keyd
+ make && sudo make install
+ sudo systemctl enable --now keyd
+
+# Quickstart
+
+1. Install and start keyd (e.g `sudo systemctl enable keyd --now`)
+
+2. Put the following in `/etc/keyd/default.conf`:
+
+```
+[ids]
+
+*
+
+[main]
+
+# Maps capslock to escape when pressed and control when held.
+capslock = overload(control, esc)
+
+# Remaps the escape key to capslock
+esc = capslock
+```
+
+Key names can be obtained by using the `keyd monitor` command. Note that while keyd is running, the output of this
+command will correspond to keyd's output. The original input events can be seen by first stopping keyd and then
+running the command. See the man page for more details.
+
+3. Run `sudo keyd reload` to reload the config set.
+
+4. See the man page (`man keyd`) for a more comprehensive description.
+
+Config errors will appear in the log output and can be accessed in the usual
+way using your system's service manager (e.g `sudo journalctl -eu keyd`).
+
+*Note*: It is possible to render your machine unusable with a bad config file.
+Should you find yourself in this position, the special key sequence
+`backspace+escape+enter` should cause keyd to terminate.
+
+Some mice (e.g the Logitech MX Master) are capable of emitting keys and
+are consequently matched by the wildcard id. It may be necessary to
+explicitly blacklist these.
+
+## Application Specific Remapping (experimental)
+
+- Add yourself to the keyd group:
+
+ `usermod -aG keyd `
+
+- Populate `~/.config/keyd/app.conf`:
+
+E.G
+
+ [alacritty]
+
+ alt.] = macro(C-g n)
+ alt.[ = macro(C-g p)
+
+ [chromium]
+
+ alt.[ = C-S-tab
+ alt.] = macro(C-tab)
+
+- Run:
+
+ `keyd-application-mapper`
+
+You will probably want to put `keyd-application-mapper -d` somewhere in your
+display server initialization logic (e.g ~/.xinitrc) unless you are running Gnome.
+
+See the man page for more details.
+
+## SBC support
+
+Experimental support for single board computers (SBCs) via usb-gadget
+has been added courtesy of Giorgi Chavchanidze.
+
+See [usb-gadget.md](src/vkbd/usb-gadget.md) for details.
+
+## Packages
+
+Third party packages for the some distributions also exist. If you wish to add
+yours to the list please file a PR. These are kindly maintained by community
+members, no personal responsibility is taken for them.
+
+### Alpine Linux
+
+[keyd](https://pkgs.alpinelinux.org/packages?name=keyd) package maintained by [@jirutka](https://github.com/jirutka).
+
+### Arch
+
+[Arch Linux](https://archlinux.org/packages/extra/x86_64/keyd/) package maintained by Arch packagers.
+
+### Debian
+
+Experimental `keyd` and `keyd-application-mapper` packages can be found in the
+CI build artifacts of the [work-in-progress Debian package
+repository](https://salsa.debian.org/rhansen/keyd):
+
+ * [amd64 (64-bit)](https://salsa.debian.org/rhansen/keyd/-/jobs/artifacts/debian/latest/browse/debian/output?job=build)
+ * [i386 (32-bit)](https://salsa.debian.org/rhansen/keyd/-/jobs/artifacts/debian/latest/browse/debian/output?job=build%20i386)
+
+Any Debian Developer who is willing to review the debianization effort and
+sponsor its upload is encouraged to contact
+[@rhansen](https://github.com/rhansen) (also see the [Debian ITP
+bug](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1060023)).
+
+### Fedora
+
+[COPR](https://copr.fedorainfracloud.org/coprs/alternateved/keyd/) package maintained by [@alternateved](https://github.com/alternateved).
+
+### Gentoo
+
+[GURU](https://gitweb.gentoo.org/repo/proj/guru.git/tree/app-misc/keyd) package maintained by [jack@pngu.org](mailto:jack@pngu.org).
+
+### openSUSE
+[opensuse](https://software.opensuse.org//download.html?project=hardware&package=keyd) package maintained by [@bubbleguuum](https://github.com/bubbleguuum).
+
+Easy install with `sudo zypper in keyd`.
+
+### Ubuntu
+
+Experimental `keyd` and `keyd-application-mapper` packages can be found in the
+[`ppa:keyd-team/ppa`
+archive](https://launchpad.net/~keyd-team/+archive/ubuntu/ppa).
+
+If you wish to help maintain this PPA, please contact
+[@rhansen](https://github.com/rhansen).
+
+### Void Linux
+
+[xbps](https://github.com/void-linux/void-packages/tree/master/srcpkgs/keyd) package maintained by [@Barbaross](https://gitlab.com/Barbaross).
+
+Easy install with `sudo xbps-install -Su keyd`.
+
+# Example 1
+
+ [ids]
+
+ *
+
+ [main]
+
+ leftshift = oneshot(shift)
+ capslock = overload(symbols, esc)
+
+ [symbols]
+
+ d = ~
+ f = /
+ ...
+
+# Example 2
+
+This overrides specific alt combinations macOS users might
+be more familiar with, while keeping the rest intact.
+
+ [ids]
+ *
+
+ [alt]
+
+ x = C-x
+ c = C-c
+ v = C-v
+
+ a = C-a
+ f = C-f
+ r = C-r
+ z = C-z
+
+# Recommended config
+
+Many users will probably not be interested in taking full advantage of keyd.
+For those who seek simple quality of life improvements I can recommend the
+following config:
+
+ [ids]
+
+ *
+
+ [main]
+
+ shift = oneshot(shift)
+ meta = oneshot(meta)
+ control = oneshot(control)
+
+ leftalt = oneshot(alt)
+ rightalt = oneshot(altgr)
+
+ capslock = overload(control, esc)
+ insert = S-insert
+
+This overloads the capslock key to function as both escape (when tapped) and
+control (when held) and remaps all modifiers to 'oneshot' keys. Thus to produce
+the letter A you can now simply tap shift and then a instead of having to hold
+it. Finally it remaps insert to S-insert (paste on X11).
+
+# FAQS
+
+## Why is my trackpad is interfering with input after enabling keyd?
+
+libinput, a higher level input component used by most wayland and X11 setups,
+includes a feature called 'disable-while-typing' that disables the trackpad
+when typing.
+
+In order to achieve this, it needs to distinguish between internal and external
+keyboards, which it does by hard coding a rules for specific hardware
+('quirks'). Since keyd creates a virtual device which subsumes both external
+and integrated keyboards, you will need to instruct libinput to regard the keyd
+virtual device as internal.
+
+This can be achieved by adding the following to `/etc/libinput/local-overrides.quirks` (which may need to be created):
+
+```
+[Serial Keyboards]
+
+MatchUdevType=keyboard
+MatchName=keyd*keyboard
+AttrKeyboardIntegration=internal
+```
+
+Credit to @mark-herbert42 and @canadaduane for the original solution.
+
+## What about xmodmap/setxkbmap/*?
+
+xmodmap and friends are display server level tools with limited functionality.
+keyd is a system level solution which implements advanced features like
+layering and [oneshot](https://docs.qmk.fm/#/one_shot_keys)
+modifiers. While some X tools offer similar functionality I am not aware of
+anything that is as flexible as keyd.
+
+## What about [kmonad](https://github.com/kmonad/kmonad)?
+
+keyd was written several years ago to allow me to easily experiment with
+different layouts on my growing keyboard collection. At the time kmonad did not
+exist and custom keyboard firmware like
+[QMK](https://github.com/qmk/qmk_firmware) (which inspired keyd) was the only
+way to get comparable features. I became aware of kmonad after having published
+keyd. While kmonad is a fine project with similar goals, it takes a different
+approach and has a different design philosophy.
+
+Notably keyd was written entirely in C with performance and simplicitly in
+mind and will likely never be as configurable as kmonad (which is extensible
+in Haskell). Having said that, it supplies (in the author's opinion) the
+most valuable features in less than 2000 lines of C while providing
+a simple language agnostic config format.
+
+## Why doesn't keyd implement feature X?
+
+If you feel something is missing or find a bug you are welcome to file an issue
+on github. keyd has a minimalist (but sane) design philosophy which
+intentionally omits certain features (e.g execing arbitrary executables
+as root). Things which already exist in custom keyboard firmware like QMK are
+good candidates for inclusion.
+
+# Contributing
+
+See [CONTRIBUTING](CONTRIBUTING.md).
+IRC Channel: #keyd on oftc
diff --git a/cros-keyboard-map/keyd/TODO b/cros-keyboard-map/keyd/TODO
new file mode 100644
index 0000000..066adbc
--- /dev/null
+++ b/cros-keyboard-map/keyd/TODO
@@ -0,0 +1,8 @@
+streamline test logic
+organize tests
+cleanup manpage
+[idea] tmux like layer timeouts
+improved mouse support (integrate moused?)
+multi-user support (remove keyd group)
+split up the man page + add FAQ
+add descriptor state + isolate descriptor logic
diff --git a/cros-keyboard-map/keyd/data/gnome-extension-45/extension.js b/cros-keyboard-map/keyd/data/gnome-extension-45/extension.js
new file mode 100644
index 0000000..0d1968b
--- /dev/null
+++ b/cros-keyboard-map/keyd/data/gnome-extension-45/extension.js
@@ -0,0 +1,65 @@
+import * as Main from 'resource:///org/gnome/shell/ui/main.js';
+import GLib from 'gi://GLib';
+import Shell from 'gi://Shell';
+import Gio from 'gi://Gio';
+import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js';
+
+let file = Gio.File.new_for_path(makePipe());
+let pipe = file.append_to_async(0, 0, null, on_pipe_open);
+
+function makePipe() {
+ let runtime_dir = GLib.getenv('XDG_RUNTIME_DIR');
+ if (!runtime_dir)
+ runtime_dir = '/run/user/'+new TextDecoder().decode(
+ GLib.spawn_command_line_sync('id -u')[1]
+ ).trim();
+
+ let path = runtime_dir + '/keyd.fifo';
+ GLib.spawn_command_line_sync('mkfifo ' + path);
+
+ return path;
+}
+
+function send(msg) {
+ if (!pipe)
+ return;
+
+ try {
+ pipe.write(msg, null);
+ } catch {
+ log('pipe closed, reopening...');
+ pipe = null;
+ file.append_to_async(0, 0, null, on_pipe_open);
+ }
+}
+
+function on_pipe_open(file, res) {
+ log('pipe opened');
+ pipe = file.append_to_finish(res);
+}
+
+export default class KeydExtension extends Extension {
+ enable() {
+ Shell.WindowTracker.get_default().connect('notify::focus-app', () => {
+ const win = global.display.focus_window;
+ const cls = win ? win.get_wm_class() : 'root';
+ const title = win ? win.get_title() : '';
+
+ send(`${cls} ${title}\n`);
+ });
+
+ Main.layoutManager.connectObject(
+ 'system-modal-opened', () => {
+ send(`system-modal ${global.stage.get_title()}\n`);
+ },
+ this
+ );
+
+ GLib.spawn_command_line_async('keyd-application-mapper -d');
+ }
+
+ disable() {
+ GLib.spawn_command_line_async('pkill -f keyd-application-mapper');
+ }
+}
+
diff --git a/cros-keyboard-map/keyd/data/gnome-extension-45/metadata.json b/cros-keyboard-map/keyd/data/gnome-extension-45/metadata.json
new file mode 100644
index 0000000..22bfef4
--- /dev/null
+++ b/cros-keyboard-map/keyd/data/gnome-extension-45/metadata.json
@@ -0,0 +1,7 @@
+{
+ "name": "keyd",
+ "description": "Used by keyd to obtain active window information.",
+ "uuid": "keyd",
+ "shell-version": [ "45", "46", "47", "48" ]
+}
+
diff --git a/cros-keyboard-map/keyd/data/gnome-extension/extension.js b/cros-keyboard-map/keyd/data/gnome-extension/extension.js
new file mode 100644
index 0000000..a11f4b6
--- /dev/null
+++ b/cros-keyboard-map/keyd/data/gnome-extension/extension.js
@@ -0,0 +1,65 @@
+const Shell = imports.gi.Shell;
+const GLib = imports.gi.GLib;
+const Gio = imports.gi.Gio;
+const Main = imports.ui.main;
+
+let file = Gio.File.new_for_path(makePipe());
+let pipe = file.append_to_async(0, 0, null, on_pipe_open);
+
+function makePipe() {
+ let runtime_dir = GLib.getenv('XDG_RUNTIME_DIR');
+ if (!runtime_dir)
+ runtime_dir = '/run/user/'+new TextDecoder().decode(
+ GLib.spawn_command_line_sync('id -u')[1]
+ ).trim();
+
+ let path = runtime_dir + '/keyd.fifo';
+ GLib.spawn_command_line_sync('mkfifo ' + path);
+
+ return path;
+}
+
+function send(msg) {
+ if (!pipe)
+ return;
+
+ try {
+ pipe.write(msg, null);
+ } catch {
+ log('pipe closed, reopening...');
+ pipe = null;
+ file.append_to_async(0, 0, null, on_pipe_open);
+ }
+}
+
+function on_pipe_open(file, res) {
+ log('pipe opened');
+ pipe = file.append_to_finish(res);
+}
+
+function init() {
+ return {
+ enable: function() {
+ Shell.WindowTracker.get_default().connect('notify::focus-app', () => {
+ const win = global.display.focus_window;
+ const cls = win ? win.get_wm_class() : 'root';
+ const title = win ? win.get_title() : '';
+
+ send(`${cls} ${title}\n`);
+ });
+
+ Main.layoutManager.connectObject(
+ 'system-modal-opened', () => {
+ send(`system-modal ${global.stage.get_title()}\n`);
+ },
+ this
+ );
+
+ GLib.spawn_command_line_async('keyd-application-mapper -d');
+ },
+
+ disable: function() {
+ GLib.spawn_command_line_async('pkill -f keyd-application-mapper');
+ }
+ }
+}
diff --git a/cros-keyboard-map/keyd/data/gnome-extension/metadata.json b/cros-keyboard-map/keyd/data/gnome-extension/metadata.json
new file mode 100644
index 0000000..dbeff8c
--- /dev/null
+++ b/cros-keyboard-map/keyd/data/gnome-extension/metadata.json
@@ -0,0 +1,7 @@
+{
+ "name": "keyd",
+ "description": "Used by keyd to obtain active window information.",
+ "uuid": "keyd",
+ "shell-version": [ "42", "43", "44" ]
+}
+
diff --git a/cros-keyboard-map/keyd/data/keyd-application-mapper.1.gz b/cros-keyboard-map/keyd/data/keyd-application-mapper.1.gz
new file mode 100644
index 0000000..61d57d4
Binary files /dev/null and b/cros-keyboard-map/keyd/data/keyd-application-mapper.1.gz differ
diff --git a/cros-keyboard-map/keyd/data/keyd.1.gz b/cros-keyboard-map/keyd/data/keyd.1.gz
new file mode 100644
index 0000000..2924840
Binary files /dev/null and b/cros-keyboard-map/keyd/data/keyd.1.gz differ
diff --git a/cros-keyboard-map/keyd/data/keyd.compose b/cros-keyboard-map/keyd/data/keyd.compose
new file mode 100644
index 0000000..f482be5
--- /dev/null
+++ b/cros-keyboard-map/keyd/data/keyd.compose
@@ -0,0 +1,34493 @@
+ <0> <0> <0> : ""
+ <0> <0> <1> : ""
+ <0> <0> <2> : ""
+ <0> <0> <3> : ""
+ <0> <0> <4> : ""
+ <0> <0> <5> : "
"
+ <0> <0> <6> : ""
+ <0> <0> <7> : ""
+ <0> <0> <8> : ""
+ <0> <0> <9> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : ""
+ <0> <0> : " "
+ <0> <0> : "¡"
+ <0> <0> : "¢"
+ <0> <0> : "£"
+ <0> <1> <0> : "¤"
+ <0> <1> <1> : "¥"
+ <0> <1> <2> : "¦"
+ <0> <1> <3> : "§"
+ <0> <1> <4> : "¨"
+ <0> <1> <5> : "©"
+ <0> <1> <6> : "ª"
+ <0> <1> <7> : "«"
+ <0> <1> <8> : "¬"
+ <0> <1> <9> : ""
+ <0> <1> : "®"
+ <0> <1> : "¯"
+ <0> <1> : "°"
+ <0> <1> : "±"
+ <0> <1> : "²"
+ <0> <1> : "³"
+ <0> <1> : "´"
+ <0> <1> : "µ"
+ <0> <1> : "¶"
+ <0> <1> : "·"
+ <0> <1> : "¸"
+ <0> <1> : "¹"
+ <0> <1> : "º"
+ <0> <1> : "»"
+ <0> <1> : "¼"
+ <0> <1> : "½"
+ <0> <1> : "¾"
+ <0> <1> : "¿"
+ <0> <1> : "À"
+ <0> <1> : "Á"
+ <0> <1> : "Â"
+ <0> <1> : "Ã"
+ <0> <1> : "Ä"
+ <0> <1> : "Å"
+ <0> <1> : "Æ"
+ <0> <1> : "Ç"
+ <0> <2> <0> : "È"
+ <0> <2> <1> : "É"
+ <0> <2> <2> : "Ê"
+ <0> <2> <3> : "Ë"
+ <0> <2> <4> : "Ì"
+ <0> <2> <5> : "Í"
+ <0> <2> <6> : "Î"
+ <0> <2> <7> : "Ï"
+ <0> <2> <8> : "Ð"
+ <0> <2> <9> : "Ñ"
+ <0> <2> : "Ò"
+ <0> <2> : "Ó"
+ <0> <2> : "Ô"
+ <0> <2> : "Õ"
+ <0> <2> : "Ö"
+ <0> <2> : "×"
+ <0> <2> : "Ø"
+ <0> <2> : "Ù"
+ <0> <2> : "Ú"
+ <0> <2> : "Û"
+ <0> <2> : "Ü"
+ <0> <2> : "Ý"
+ <0> <2> : "Þ"
+ <0> <2> : "ß"
+ <0> <2> : "à"
+ <0> <2> : "á"
+ <0> <2> : "â"
+ <0> <2> : "ã"
+ <0> <2> : "ä"
+ <0> <2> : "å"
+ <0> <2> : "æ"
+ <0> <2> : "ç"
+ <0> <2> : "è"
+ <0> <2> : "é"
+ <0> <2> : "ê"
+ <0> <2> : "ë"
+ <0> <3> <0> : "ì"
+ <0> <3> <1> : "í"
+ <0> <3> <2> : "î"
+ <0> <3> <3> : "ï"
+ <0> <3> <4> : "ð"
+ <0> <3> <5> : "ñ"
+ <0> <3> <6> : "ò"
+ <0> <3> <7> : "ó"
+ <0> <3> <8> : "ô"
+ <0> <3> <9> : "õ"
+ <0> <3> : "ö"
+ <0> <3> : "÷"
+ <0> <3> : "ø"
+ <0> <3> : "ù"
+ <0> <3> : "ú"
+ <0> <3> : "û"
+ <0> <3> : "ü"
+ <0> <3> : "ý"
+ <0> <3> : "þ"
+ <0> <3> : "ÿ"
+ <0> <3> : "Ā"
+ <0> <3> : "ā"
+ <0> <3> : "Ă"
+ <0> <3> : "ă"
+ <0> <3> : "Ą"
+ <0> <3> : "ą"
+ <0> <3> : "Ć"
+ <0> <3> : "ć"
+ <0> <3> : "Ĉ"
+ <0> <3> : "ĉ"
+ <0> <3> : "Ċ"
+ <0> <3> : "ċ"
+ <0> <3> : "Č"
+ <0> <3> : "č"
+ <0> <3> : "Ď"
+ <0> <3> : "ď"
+ <0> <4> <0> : "Đ"
+ <0> <4> <1> : "đ"
+ <0> <4> <2> : "Ē"
+