mirror of
https://gitlab.freedesktop.org/plymouth/plymouth.git
synced 2026-05-07 11:58:08 +02:00
Merge branch 'dev_input' into 'main'
Add input device support See merge request plymouth/plymouth!177
This commit is contained in:
commit
2165fe4f3b
23 changed files with 1690 additions and 235 deletions
|
|
@ -17,7 +17,7 @@ fedora-x86_64:
|
|||
stage: build
|
||||
image: 'registry.fedoraproject.org/fedora:37'
|
||||
before_script:
|
||||
- dnf install -y gcc gtk3-devel git libpng-devel gettext-devel libxslt docbook-style-xsl cairo-devel systemd-devel systemd-udev kernel-headers libdrm-devel pango-devel make ShellCheck uncrustify patchutils meson binutils-gold
|
||||
- dnf install -y gcc gtk3-devel git libpng-devel gettext-devel libxslt docbook-style-xsl cairo-devel systemd-devel systemd-udev kernel-headers libdrm-devel pango-devel make ShellCheck uncrustify patchutils meson binutils-gold xkeyboard-config-devel libevdev-devel
|
||||
- alternatives --set ld /usr/bin/ld.gold
|
||||
<<: *check-format
|
||||
<<: *meson-build
|
||||
|
|
@ -29,7 +29,7 @@ debian-unstable-x86_64:
|
|||
image: debian:unstable
|
||||
before_script:
|
||||
- apt-get update -qq
|
||||
- apt-get install -y -qq --no-install-recommends bc build-essential docbook-xsl gcc gettext git libdrm-dev libgtk-3-dev libpango1.0-dev libpng-dev libudev-dev make pkg-config libsystemd-dev udev xsltproc shellcheck uncrustify patchutils meson
|
||||
- apt-get install -y -qq --no-install-recommends bc build-essential docbook-xsl gcc gettext git libdrm-dev libgtk-3-dev libpango1.0-dev libpng-dev libudev-dev make pkg-config libsystemd-dev udev xsltproc shellcheck uncrustify patchutils meson xkb-data libevdev-dev
|
||||
<<: *meson-build
|
||||
only:
|
||||
- merge_requests
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@ libpangocairo_dep = dependency('pangocairo', required: get_option('pango'))
|
|||
libfreetype_dep = dependency('freetype2', required: get_option('freetype'))
|
||||
gtk3_dep = dependency('gtk+-3.0', version: '>= 3.14.0', required: get_option('gtk'))
|
||||
libdrm_dep = dependency('libdrm', required: get_option('drm'))
|
||||
libevdev_dep = dependency('libevdev')
|
||||
xkbcommon_dep = dependency('xkbcommon')
|
||||
xkeyboard_config_dep = dependency('xkeyboard-config')
|
||||
|
||||
if get_option('systemd-integration')
|
||||
systemd_dep = dependency('systemd')
|
||||
|
|
|
|||
|
|
@ -3,12 +3,18 @@
|
|||
import cairo
|
||||
import subprocess
|
||||
import math
|
||||
import lxml
|
||||
from lxml import etree
|
||||
|
||||
|
||||
FONT_SIZE = 30
|
||||
MARGIN = int(FONT_SIZE / 3)
|
||||
|
||||
#python3-lxml utility is required
|
||||
|
||||
def get_keymaps():
|
||||
xml = etree.XML(bytes(open('/usr/share/X11/xkb/rules/evdev.xml', 'r').read(), encoding="utf-8"))
|
||||
keymaps_x11 = xml.xpath('//layout/configItem/description/text()')
|
||||
keymaps = subprocess.check_output(["localectl", "list-keymaps"]).decode("utf-8").strip().split()
|
||||
|
||||
# Note when changing this you MUST keep ply_keymap_normalize_keymap()
|
||||
|
|
@ -31,12 +37,17 @@ def get_keymaps():
|
|||
return parts[0]
|
||||
|
||||
keymaps = list(map(normalize_keymaps ,keymaps))
|
||||
|
||||
#Remove duplicates
|
||||
ret = []
|
||||
keymaps_dedupe = []
|
||||
for k in keymaps:
|
||||
if k not in ret:
|
||||
ret.append(k)
|
||||
if k not in keymaps_dedupe:
|
||||
keymaps_dedupe.append(k)
|
||||
|
||||
ret = []
|
||||
for k in keymaps_dedupe:
|
||||
ret.append((k, "PLY_LAYOUT_TERMINAL"))
|
||||
for k in keymaps_x11:
|
||||
ret.append((k, "PLY_LAYOUT_XKB"))
|
||||
return ret
|
||||
|
||||
|
||||
|
|
@ -49,7 +60,8 @@ ct.set_font_size(FONT_SIZE)
|
|||
max_height = 0.0
|
||||
total_width = 0.0
|
||||
for i in get_keymaps():
|
||||
extents = ct.text_extents(i)
|
||||
text=i[0]
|
||||
extents = ct.text_extents(text)
|
||||
h = extents.height
|
||||
if h > max_height:
|
||||
max_height = h
|
||||
|
|
@ -73,9 +85,11 @@ ct.move_to(MARGIN, MARGIN + max_height - descent)
|
|||
current_x, current_y = (MARGIN, MARGIN + max_height - descent)
|
||||
metadata = []
|
||||
for km in get_keymaps():
|
||||
extents = ct.text_extents(km)
|
||||
ct.show_text(km)
|
||||
metadata.append((km, current_x, extents.width + MARGIN * 2))
|
||||
km_text=km[0]
|
||||
km_type=km[1]
|
||||
extents = ct.text_extents(km_text)
|
||||
ct.show_text(km_text)
|
||||
metadata.append((km_text, current_x, extents.width + MARGIN * 2, km_type))
|
||||
current_x += extents.width + (MARGIN * 2)
|
||||
ct.move_to(current_x, current_y)
|
||||
|
||||
|
|
@ -84,16 +98,22 @@ sf.write_to_png("keymap-render.png")
|
|||
print("/* This file is autogenerated by running:")
|
||||
print(" * scripts/keymap-render.py > src/libply-splash-graphics/ply-keymap-metadata.h")
|
||||
print(" */")
|
||||
print("struct ply_keymap_metadata {")
|
||||
print("typedef struct {")
|
||||
print(" const char *name;")
|
||||
print(" int offset;")
|
||||
print(" int width;")
|
||||
print("};")
|
||||
print(" int type;")
|
||||
print("} ply_keymap_metadata_t;")
|
||||
print("")
|
||||
print("static struct ply_keymap_metadata ply_keymap_metadata[] = {")
|
||||
print("typedef enum {")
|
||||
print(" PLY_LAYOUT_TERMINAL,")
|
||||
print(" PLY_LAYOUT_XKB,")
|
||||
print("} ply_layout_types_t;")
|
||||
print("")
|
||||
print("static ply_keymap_metadata_t ply_keymap_metadata[] = {")
|
||||
|
||||
for i in metadata:
|
||||
print((" { \"%s\", %d, %d }," % (i[0],i[1],i[2])))
|
||||
print((" { \"%s\", %d, %d, %s}," % (i[0],i[1],i[2],i[3])))
|
||||
|
||||
print(" { NULL, } /* End of array marker */ ")
|
||||
print("};")
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@ ddebug() {
|
|||
[ "$verbose" = "true" ] && echo "$@"
|
||||
}
|
||||
|
||||
dfatal() {
|
||||
echo "$@" > /proc/self/fd/2
|
||||
}
|
||||
|
||||
# normalize_path <path>
|
||||
# Prints the normalized path, where it removes any duplicated
|
||||
# and trailing slashes.
|
||||
|
|
@ -420,12 +424,13 @@ function usage() {
|
|||
rc=1
|
||||
fi
|
||||
|
||||
echo "usage: plymouth [ --verbose | -v ] { --targetdir | -t } <initrd_directory>" > $output
|
||||
echo "usage: plymouth [ --verbose | -v ] { --targetdir | -t } <initrd_directory> { --x11-directory | -x } <x11_directory>" > $output
|
||||
exit $rc
|
||||
}
|
||||
|
||||
verbose=false
|
||||
INITRDDIR=""
|
||||
X11_DIRECTORY="/usr/share/X11"
|
||||
while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
--verbose|-v)
|
||||
|
|
@ -438,6 +443,10 @@ while [ $# -gt 0 ]; do
|
|||
--help|-h)
|
||||
usage normal
|
||||
;;
|
||||
--x11-directory|-x)
|
||||
shift
|
||||
X11_DIRECTORY="$1"
|
||||
;;
|
||||
*)
|
||||
usage error
|
||||
break
|
||||
|
|
@ -465,6 +474,51 @@ inst @RELEASE_FILE@ $INITRDDIR
|
|||
inst ${PLYMOUTH_POLICYDIR}/plymouthd.defaults $INITRDDIR
|
||||
inst ${PLYMOUTH_CONFDIR}/plymouthd.conf $INITRDDIR
|
||||
|
||||
# Install xkb info
|
||||
mkdir -p "${INITRDDIR}/${X11_DIRECTORY}/xkb/"
|
||||
mkdir -p "${INITRDDIR}/${X11_DIRECTORY}/xkb/compat/"
|
||||
|
||||
mkdir -p "${INITRDDIR}/${X11_DIRECTORY}/xkb/keycodes/"
|
||||
mkdir -p "${INITRDDIR}/${X11_DIRECTORY}/xkb/rules/"
|
||||
mkdir -p "${INITRDDIR}/${X11_DIRECTORY}/xkb/symbols/"
|
||||
mkdir -p "${INITRDDIR}/${X11_DIRECTORY}/xkb/types/"
|
||||
mkdir -p "${INITRDDIR}/${X11_DIRECTORY}/locale/"
|
||||
inst ${X11_DIRECTORY}/xkb/compat/accessx $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/compat/basic $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/compat/caps $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/compat/complete $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/compat/iso9995 $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/compat/ledcaps $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/compat/lednum $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/compat/ledscroll $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/compat/level5 $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/compat/misc $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/compat/mousekeys $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/compat/xfree86 $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/keycodes/aliases $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/keycodes/evdev $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/rules/evdev $INITRDDIR
|
||||
find ${X11_DIRECTORY}/xkb/symbols -maxdepth 1 ! -type d | while read file; do
|
||||
inst $file $INITRDDIR
|
||||
done
|
||||
inst ${X11_DIRECTORY}/xkb/types/basic $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/types/complete $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/types/extra $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/types/iso9995 $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/types/level5 $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/types/mousekeys $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/types/numpad $INITRDDIR
|
||||
inst ${X11_DIRECTORY}/xkb/types/pc $INITRDDIR
|
||||
|
||||
# In the off chance the user uses their compose key when
|
||||
# typing their password, install compose sequences
|
||||
inst ${X11_DIRECTORY}/locale/compose.dir $INITRDDIR
|
||||
grep UTF-8/Compose: ${X11_DIRECTORY}/locale/compose.dir | awk -F: '{ print $1 }' | sort -u | xargs dirname | while read DIR; do
|
||||
find ${X11_DIRECTORY}/locale/$DIR -maxdepth 1 ! -type d | while read file; do
|
||||
inst $file $INITRDDIR
|
||||
done
|
||||
done
|
||||
|
||||
if [ -z "$PLYMOUTH_THEME_NAME" ]; then
|
||||
echo "No default plymouth plugin is set" >&2
|
||||
exit 1
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
libply_splash_core_sources = files(
|
||||
'ply-boot-splash.c',
|
||||
'ply-device-manager.c',
|
||||
'ply-input-device.c',
|
||||
'ply-keyboard.c',
|
||||
'ply-pixel-buffer.c',
|
||||
'ply-pixel-display.c',
|
||||
|
|
@ -17,6 +18,9 @@ libply_splash_core_public_deps = [
|
|||
|
||||
libply_splash_core_private_deps = [
|
||||
lm_dep,
|
||||
libevdev_dep,
|
||||
xkbcommon_dep,
|
||||
xkeyboard_config_dep,
|
||||
]
|
||||
|
||||
if libudev_dep.found()
|
||||
|
|
@ -49,6 +53,7 @@ libply_splash_core_headers = files(
|
|||
'ply-boot-splash-plugin.h',
|
||||
'ply-boot-splash.h',
|
||||
'ply-device-manager.h',
|
||||
'ply-input-device.h',
|
||||
'ply-keyboard.h',
|
||||
'ply-pixel-buffer.h',
|
||||
'ply-pixel-display.h',
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
#include "config.h"
|
||||
#include "ply-device-manager.h"
|
||||
#include "ply-renderer.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -34,14 +35,19 @@
|
|||
#include <libudev.h>
|
||||
#endif
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include "ply-logger.h"
|
||||
#include "ply-event-loop.h"
|
||||
#include "ply-hashtable.h"
|
||||
#include "ply-list.h"
|
||||
#include "ply-key-file.h"
|
||||
#include "ply-utils.h"
|
||||
#include "ply-input-device.h"
|
||||
|
||||
#define SUBSYSTEM_DRM "drm"
|
||||
#define SUBSYSTEM_FRAME_BUFFER "graphics"
|
||||
#define SUBSYSTEM_INPUT "input"
|
||||
|
||||
#ifdef HAVE_UDEV
|
||||
static void create_devices_from_udev (ply_device_manager_t *manager);
|
||||
|
|
@ -60,7 +66,9 @@ struct _ply_device_manager
|
|||
ply_event_loop_t *loop;
|
||||
ply_hashtable_t *terminals;
|
||||
ply_hashtable_t *renderers;
|
||||
ply_hashtable_t *input_devices;
|
||||
ply_terminal_t *local_console_terminal;
|
||||
const char *keymap;
|
||||
ply_list_t *keyboards;
|
||||
ply_list_t *text_displays;
|
||||
ply_list_t *pixel_displays;
|
||||
|
|
@ -68,6 +76,9 @@ struct _ply_device_manager
|
|||
struct udev_monitor *udev_monitor;
|
||||
ply_fd_watch_t *fd_watch;
|
||||
|
||||
struct xkb_context *xkb_context;
|
||||
struct xkb_keymap *xkb_keymap;
|
||||
|
||||
ply_keyboard_added_handler_t keyboard_added_handler;
|
||||
ply_keyboard_removed_handler_t keyboard_removed_handler;
|
||||
ply_pixel_display_added_handler_t pixel_display_added_handler;
|
||||
|
|
@ -262,6 +273,73 @@ fb_device_has_drm_device (ply_device_manager_t *manager,
|
|||
return has_drm_device;
|
||||
}
|
||||
|
||||
static void
|
||||
on_each_renderer_add_input_device (const char *key,
|
||||
ply_renderer_t *renderer,
|
||||
ply_input_device_t *input_device)
|
||||
{
|
||||
ply_trace ("Adding input device '%s' to renderer for output device '%s'",
|
||||
ply_input_device_get_name (input_device),
|
||||
ply_renderer_get_device_name (renderer));
|
||||
|
||||
ply_renderer_add_input_device (renderer, input_device);
|
||||
}
|
||||
|
||||
static void
|
||||
add_input_device_to_renderers (ply_device_manager_t *manager,
|
||||
ply_input_device_t *input_device)
|
||||
{
|
||||
const char *device_path = ply_input_device_get_path (input_device);
|
||||
if (ply_hashtable_lookup (manager->input_devices, (void *) device_path) != NULL) {
|
||||
ply_trace ("Input device '%s' already added, skipping...", ply_input_device_get_name (input_device));
|
||||
ply_input_device_free (input_device);
|
||||
return;
|
||||
}
|
||||
ply_hashtable_insert (manager->input_devices, (void *) device_path, input_device);
|
||||
ply_hashtable_foreach (manager->renderers,
|
||||
(ply_hashtable_foreach_func_t *)
|
||||
on_each_renderer_add_input_device,
|
||||
input_device);
|
||||
}
|
||||
|
||||
static void
|
||||
on_each_input_device_add_to_renderer (const char *key,
|
||||
ply_input_device_t *input_device,
|
||||
ply_renderer_t *renderer)
|
||||
{
|
||||
ply_trace ("Adding input device '%s' to renderer for output device '%s'",
|
||||
ply_input_device_get_name (input_device),
|
||||
ply_renderer_get_device_name (renderer));
|
||||
|
||||
ply_renderer_add_input_device (renderer, input_device);
|
||||
}
|
||||
|
||||
static void
|
||||
add_input_devices_to_renderer (ply_device_manager_t *manager,
|
||||
ply_renderer_t *renderer)
|
||||
{
|
||||
ply_hashtable_foreach (manager->input_devices,
|
||||
(ply_hashtable_foreach_func_t *)
|
||||
on_each_input_device_add_to_renderer,
|
||||
renderer);
|
||||
}
|
||||
static void
|
||||
on_each_input_device_remove_from_renderer (const char *key,
|
||||
ply_renderer_t *renderer,
|
||||
ply_input_device_t *input_device)
|
||||
{
|
||||
ply_renderer_remove_input_device (renderer, input_device);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_input_device_from_renderers (ply_device_manager_t *manager,
|
||||
ply_input_device_t *input_device)
|
||||
{
|
||||
const char *device_path = ply_input_device_get_path (input_device);
|
||||
ply_hashtable_remove (manager->input_devices, (void *) device_path);
|
||||
ply_hashtable_foreach (manager->renderers, (ply_hashtable_foreach_func_t *) on_each_input_device_remove_from_renderer, input_device);
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_drm_device (struct udev_device *device)
|
||||
{
|
||||
|
|
@ -300,7 +378,7 @@ static bool
|
|||
create_devices_for_udev_device (ply_device_manager_t *manager,
|
||||
struct udev_device *device)
|
||||
{
|
||||
const char *device_path;
|
||||
const char *device_path, *device_sysname;
|
||||
bool created = false;
|
||||
bool force_fb = false;
|
||||
|
||||
|
|
@ -308,6 +386,7 @@ create_devices_for_udev_device (ply_device_manager_t *manager,
|
|||
force_fb = true;
|
||||
|
||||
device_path = udev_device_get_devnode (device);
|
||||
device_sysname = udev_device_get_sysname (device);
|
||||
|
||||
if (device_path != NULL) {
|
||||
const char *subsystem;
|
||||
|
|
@ -331,6 +410,21 @@ create_devices_for_udev_device (ply_device_manager_t *manager,
|
|||
renderer_type = PLY_RENDERER_TYPE_FRAME_BUFFER;
|
||||
else
|
||||
ply_trace ("ignoring, since there's a DRM device associated with it");
|
||||
} else if (strcmp (subsystem, SUBSYSTEM_INPUT) == 0) {
|
||||
if (ply_string_has_prefix (device_sysname, "event")) {
|
||||
ply_trace ("found input device %s", device_path);
|
||||
ply_input_device_t *input_device = ply_input_device_open (manager->xkb_context, manager->xkb_keymap, device_path);
|
||||
if (input_device != NULL) {
|
||||
ply_input_device_set_disconnect_handler (input_device, (ply_input_device_disconnect_handler_t) remove_input_device_from_renderers, manager);
|
||||
if (ply_input_device_is_keyboard (input_device)) {
|
||||
add_input_device_to_renderers (manager, input_device);
|
||||
} else {
|
||||
ply_input_device_free (input_device);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ply_trace ("Ignoring, since this is a non-evdev device");
|
||||
}
|
||||
}
|
||||
|
||||
if (renderer_type != PLY_RENDERER_TYPE_NONE) {
|
||||
|
|
@ -375,7 +469,7 @@ create_devices_for_subsystem (ply_device_manager_t *manager,
|
|||
|
||||
udev_list_entry_foreach (entry, udev_enumerate_get_list_entry (matches)){
|
||||
struct udev_device *device = NULL;
|
||||
const char *path;
|
||||
const char *path, *node;
|
||||
|
||||
path = udev_list_entry_get_name (entry);
|
||||
|
||||
|
|
@ -393,18 +487,10 @@ create_devices_for_subsystem (ply_device_manager_t *manager,
|
|||
if (udev_device_get_is_initialized (device)) {
|
||||
ply_trace ("device is initialized");
|
||||
|
||||
/* We only care about devices assigned to a (any) devices. Floating
|
||||
* devices should be ignored.
|
||||
*/
|
||||
if (udev_device_has_tag (device, "seat")) {
|
||||
const char *node;
|
||||
node = udev_device_get_devnode (device);
|
||||
if (node != NULL) {
|
||||
ply_trace ("found node %s", node);
|
||||
found_device = create_devices_for_udev_device (manager, device);
|
||||
}
|
||||
} else {
|
||||
ply_trace ("device doesn't have a devices tag");
|
||||
node = udev_device_get_devnode (device);
|
||||
if (node != NULL) {
|
||||
ply_trace ("found node %s", node);
|
||||
found_device = create_devices_for_udev_device (manager, device);
|
||||
}
|
||||
} else {
|
||||
ply_trace ("it's not initialized");
|
||||
|
|
@ -456,7 +542,7 @@ verify_add_or_change (ply_device_manager_t *manager,
|
|||
{
|
||||
const char *subsystem;
|
||||
|
||||
if (strcmp (action, "add") && strcmp (action, "change"))
|
||||
if (strcmp (action, "add") != 0 && strcmp (action, "change") != 0)
|
||||
return false;
|
||||
|
||||
if (manager->local_console_managed && manager->local_console_is_text) {
|
||||
|
|
@ -468,7 +554,7 @@ verify_add_or_change (ply_device_manager_t *manager,
|
|||
return true;
|
||||
|
||||
subsystem = udev_device_get_subsystem (device);
|
||||
if (strcmp (subsystem, SUBSYSTEM_DRM)) {
|
||||
if (strcmp (subsystem, SUBSYSTEM_FRAME_BUFFER) == 0) {
|
||||
ply_trace ("ignoring since we only handle subsystem %s devices after timeout", subsystem);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -578,14 +664,15 @@ watch_for_udev_events (ply_device_manager_t *manager)
|
|||
if (manager->fd_watch != NULL)
|
||||
return;
|
||||
|
||||
ply_trace ("watching for udev graphics device add and remove events");
|
||||
ply_trace ("watching for udev graphics device and input device add and remove events");
|
||||
|
||||
if (manager->udev_monitor == NULL) {
|
||||
manager->udev_monitor = udev_monitor_new_from_netlink (manager->udev_context, "udev");
|
||||
|
||||
udev_monitor_filter_add_match_subsystem_devtype (manager->udev_monitor, SUBSYSTEM_DRM, NULL);
|
||||
udev_monitor_filter_add_match_subsystem_devtype (manager->udev_monitor, SUBSYSTEM_FRAME_BUFFER, NULL);
|
||||
udev_monitor_filter_add_match_tag (manager->udev_monitor, "seat");
|
||||
if (!ply_kernel_command_line_has_argument ("plymouth.use-legacy-input"))
|
||||
udev_monitor_filter_add_match_subsystem_devtype (manager->udev_monitor, SUBSYSTEM_INPUT, NULL);
|
||||
udev_monitor_enable_receiving (manager->udev_monitor);
|
||||
}
|
||||
|
||||
|
|
@ -629,6 +716,21 @@ free_terminals (ply_device_manager_t *manager)
|
|||
manager);
|
||||
}
|
||||
|
||||
static void
|
||||
free_input_device (char *device,
|
||||
ply_input_device_t *input_device,
|
||||
ply_device_manager_t *manager)
|
||||
{
|
||||
ply_hashtable_remove (manager->input_devices, device);
|
||||
ply_input_device_free (input_device);
|
||||
}
|
||||
|
||||
static void
|
||||
free_input_devices (ply_device_manager_t *manager)
|
||||
{
|
||||
ply_hashtable_foreach (manager->input_devices, (ply_hashtable_foreach_func_t *) free_input_device, manager);
|
||||
}
|
||||
|
||||
static ply_terminal_t *
|
||||
get_terminal (ply_device_manager_t *manager,
|
||||
const char *device_name)
|
||||
|
|
@ -655,7 +757,7 @@ get_terminal (ply_device_manager_t *manager,
|
|||
terminal = ply_hashtable_lookup (manager->terminals, full_name);
|
||||
|
||||
if (terminal == NULL) {
|
||||
terminal = ply_terminal_new (full_name);
|
||||
terminal = ply_terminal_new (full_name, manager->keymap);
|
||||
|
||||
ply_hashtable_insert (manager->terminals,
|
||||
(void *) ply_terminal_get_name (terminal),
|
||||
|
|
@ -684,6 +786,74 @@ free_renderers (ply_device_manager_t *manager)
|
|||
manager);
|
||||
}
|
||||
|
||||
static char *
|
||||
strip_quotes (char *str)
|
||||
{
|
||||
char *old_str;
|
||||
if (str && str[0] == '"' && str[strlen (str) - 1] == '"') {
|
||||
old_str = str;
|
||||
str = strndup (str + 1, strlen (str) - 2);
|
||||
free (old_str);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_vconsole_conf (ply_device_manager_t *manager)
|
||||
{
|
||||
ply_key_file_t *vconsole_conf;
|
||||
char *keymap = NULL, *xkb_layout = NULL, *xkb_model = NULL, *xkb_variant = NULL, *xkb_options = NULL;
|
||||
|
||||
keymap = ply_kernel_command_line_get_key_value ("rd.vconsole.keymap=");
|
||||
|
||||
if (!keymap)
|
||||
keymap = ply_kernel_command_line_get_key_value ("vconsole.keymap=");
|
||||
|
||||
vconsole_conf = ply_key_file_new ("/etc/vconsole.conf");
|
||||
if (ply_key_file_load_groupless_file (vconsole_conf)) {
|
||||
/* The values in vconsole.conf might be quoted, strip these */
|
||||
if (!keymap) {
|
||||
keymap = ply_key_file_get_value (vconsole_conf, NULL, "KEYMAP");
|
||||
keymap = strip_quotes (keymap);
|
||||
}
|
||||
xkb_layout = ply_key_file_get_value (vconsole_conf, NULL, "XKB_LAYOUT");
|
||||
xkb_layout = strip_quotes (xkb_layout);
|
||||
|
||||
xkb_model = ply_key_file_get_value (vconsole_conf, NULL, "XKB_MODEL");
|
||||
xkb_model = strip_quotes (xkb_model);
|
||||
|
||||
xkb_variant = ply_key_file_get_value (vconsole_conf, NULL, "XKB_VARIANT");
|
||||
xkb_variant = strip_quotes (xkb_variant);
|
||||
|
||||
xkb_options = ply_key_file_get_value (vconsole_conf, NULL, "XKB_OPTIONS");
|
||||
xkb_options = strip_quotes (xkb_options);
|
||||
}
|
||||
ply_key_file_free (vconsole_conf);
|
||||
|
||||
ply_trace ("XKB_KEYMAP: %s KEYMAP: %s", xkb_layout, keymap);
|
||||
|
||||
struct xkb_rule_names xkb_keymap = {
|
||||
.layout = xkb_layout,
|
||||
.model = xkb_model,
|
||||
.variant = xkb_variant,
|
||||
.options = xkb_options,
|
||||
};
|
||||
manager->xkb_keymap = xkb_keymap_new_from_names (manager->xkb_context, &xkb_keymap, XKB_MAP_COMPILE_NO_FLAGS);
|
||||
|
||||
if (manager->xkb_keymap == NULL) {
|
||||
ply_trace ("Failed to set xkb keymap of LAYOUT: %s MODEL: %s VARIANT: %s OPTIONS: %s", xkb_layout, xkb_model, xkb_variant, xkb_options);
|
||||
|
||||
manager->xkb_keymap = xkb_keymap_new_from_names (manager->xkb_context, NULL, XKB_MAP_COMPILE_NO_FLAGS);
|
||||
assert (manager->xkb_keymap != NULL);
|
||||
}
|
||||
|
||||
free (xkb_layout);
|
||||
free (xkb_model);
|
||||
free (xkb_variant);
|
||||
free (xkb_options);
|
||||
manager->keymap = keymap;
|
||||
}
|
||||
|
||||
ply_device_manager_t *
|
||||
ply_device_manager_new (const char *default_tty,
|
||||
ply_device_manager_flags_t flags)
|
||||
|
|
@ -692,9 +862,13 @@ ply_device_manager_new (const char *default_tty,
|
|||
|
||||
manager = calloc (1, sizeof(ply_device_manager_t));
|
||||
manager->loop = NULL;
|
||||
manager->xkb_context = xkb_context_new (XKB_CONTEXT_NO_FLAGS);
|
||||
parse_vconsole_conf (manager);
|
||||
|
||||
manager->terminals = ply_hashtable_new (ply_hashtable_string_hash, ply_hashtable_string_compare);
|
||||
manager->renderers = ply_hashtable_new (ply_hashtable_string_hash, ply_hashtable_string_compare);
|
||||
manager->local_console_terminal = ply_terminal_new (default_tty);
|
||||
manager->local_console_terminal = ply_terminal_new (default_tty, manager->keymap);
|
||||
manager->input_devices = ply_hashtable_new (ply_hashtable_string_hash, ply_hashtable_string_compare);
|
||||
manager->keyboards = ply_list_new ();
|
||||
manager->text_displays = ply_list_new ();
|
||||
manager->pixel_displays = ply_list_new ();
|
||||
|
|
@ -727,10 +901,17 @@ ply_device_manager_free (ply_device_manager_t *manager)
|
|||
|
||||
free_terminals (manager);
|
||||
ply_hashtable_free (manager->terminals);
|
||||
free ((void *) manager->keymap);
|
||||
|
||||
free_renderers (manager);
|
||||
ply_hashtable_free (manager->renderers);
|
||||
|
||||
free_input_devices (manager);
|
||||
ply_hashtable_free (manager->input_devices);
|
||||
|
||||
if (manager->xkb_context)
|
||||
xkb_context_unref (manager->xkb_context);
|
||||
|
||||
#ifdef HAVE_UDEV
|
||||
ply_event_loop_stop_watching_for_timeout (manager->loop,
|
||||
(ply_event_loop_timeout_handler_t)
|
||||
|
|
@ -918,6 +1099,8 @@ create_devices_for_terminal_and_renderer_type (ply_device_manager_t *manager,
|
|||
renderer = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
add_input_devices_to_renderer (manager, renderer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1023,6 +1206,7 @@ create_devices_from_udev (ply_device_manager_t *manager)
|
|||
|
||||
ply_trace ("Timeout elapsed, looking for devices from udev");
|
||||
|
||||
create_devices_for_subsystem (manager, SUBSYSTEM_INPUT);
|
||||
create_devices_for_subsystem (manager, SUBSYSTEM_DRM);
|
||||
create_devices_for_subsystem (manager, SUBSYSTEM_FRAME_BUFFER);
|
||||
|
||||
|
|
@ -1085,6 +1269,7 @@ ply_device_manager_watch_devices (ply_device_manager_t *manager,
|
|||
|
||||
#ifdef HAVE_UDEV
|
||||
watch_for_udev_events (manager);
|
||||
create_devices_for_subsystem (manager, SUBSYSTEM_INPUT);
|
||||
create_devices_for_subsystem (manager, SUBSYSTEM_DRM);
|
||||
ply_event_loop_watch_for_timeout (manager->loop,
|
||||
device_timeout,
|
||||
|
|
|
|||
509
src/libply-splash-core/ply-input-device.c
Normal file
509
src/libply-splash-core/ply-input-device.c
Normal file
|
|
@ -0,0 +1,509 @@
|
|||
/* ply-input-device.c - evdev input device handling implementation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Written By: Diego Augusto <diego.augusto@protonmail.com>
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <malloc.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libevdev-1.0/libevdev/libevdev.h>
|
||||
#include <linux/input.h>
|
||||
#include <unistd.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||
|
||||
#include "ply-buffer.h"
|
||||
#include "ply-event-loop.h"
|
||||
#include "ply-input-device.h"
|
||||
#include "ply-list.h"
|
||||
#include "ply-logger.h"
|
||||
#include "ply-trigger.h"
|
||||
#include "ply-utils.h"
|
||||
|
||||
/* The docs say this needs to be at least 7, the code enforces this, but also never uses more
|
||||
* than 5. We'll just do 7.
|
||||
*/
|
||||
#define PLY_XKB_KEYSYM_TO_UTF8_BUFFER_SIZE 7
|
||||
|
||||
struct _ply_input_device
|
||||
{
|
||||
int fd;
|
||||
char *path;
|
||||
ply_event_loop_t *loop;
|
||||
ply_trigger_t *input_trigger;
|
||||
ply_trigger_t *leds_changed_trigger;
|
||||
ply_trigger_t *disconnect_trigger;
|
||||
ply_fd_watch_t *fd_watch;
|
||||
|
||||
struct xkb_context *xkb_context;
|
||||
struct xkb_keymap *keymap;
|
||||
struct xkb_state *keyboard_state;
|
||||
struct xkb_compose_table *compose_table;
|
||||
struct xkb_compose_state *compose_state;
|
||||
|
||||
struct libevdev *dev;
|
||||
};
|
||||
|
||||
static bool
|
||||
apply_compose_sequence_to_input_buffer (ply_input_device_t *input_device,
|
||||
xkb_keysym_t input_symbol,
|
||||
ply_buffer_t *input_buffer)
|
||||
{
|
||||
enum xkb_compose_feed_result compose_feed_result;
|
||||
enum xkb_compose_status compose_status;
|
||||
|
||||
if (input_device->compose_state == NULL)
|
||||
return false;
|
||||
|
||||
if (input_symbol == XKB_KEY_NoSymbol)
|
||||
return false;
|
||||
|
||||
compose_feed_result = xkb_compose_state_feed (input_device->compose_state, input_symbol);
|
||||
|
||||
if (compose_feed_result == XKB_COMPOSE_FEED_IGNORED)
|
||||
return false;
|
||||
|
||||
assert (compose_feed_result == XKB_COMPOSE_FEED_ACCEPTED);
|
||||
|
||||
compose_status = xkb_compose_state_get_status (input_device->compose_state);
|
||||
|
||||
if (compose_status == XKB_COMPOSE_NOTHING)
|
||||
return false;
|
||||
|
||||
if (compose_status == XKB_COMPOSE_COMPOSED) {
|
||||
xkb_keysym_t output_symbol;
|
||||
ssize_t character_size;
|
||||
char character_buf[PLY_XKB_KEYSYM_TO_UTF8_BUFFER_SIZE] = "";
|
||||
|
||||
output_symbol = xkb_compose_state_get_one_sym (input_device->compose_state);
|
||||
character_size = xkb_keysym_to_utf8 (output_symbol, character_buf, sizeof(character_buf));
|
||||
|
||||
if (character_size > 0)
|
||||
ply_buffer_append_bytes (input_buffer, character_buf, character_size);
|
||||
} else {
|
||||
/* Either we're mid compose sequence (XKB_COMPOSE_COMPOSING) or the compose sequence has
|
||||
* been aborted (XKB_COMPOSE_CANCELLED). Either way, we shouldn't append anything to the
|
||||
* input buffer
|
||||
*/
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
apply_key_to_input_buffer (ply_input_device_t *input_device,
|
||||
xkb_keysym_t symbol,
|
||||
int keycode,
|
||||
ply_buffer_t *input_buffer)
|
||||
{
|
||||
ssize_t character_size;
|
||||
bool was_compose_sequence;
|
||||
|
||||
was_compose_sequence = apply_compose_sequence_to_input_buffer (input_device, symbol, input_buffer);
|
||||
|
||||
if (was_compose_sequence)
|
||||
return;
|
||||
|
||||
switch (symbol) {
|
||||
case XKB_KEY_Escape:
|
||||
ply_buffer_append_bytes (input_buffer, "\033", 1);
|
||||
break;
|
||||
case XKB_KEY_Return:
|
||||
ply_buffer_append_bytes (input_buffer, "\n", 1);
|
||||
break;
|
||||
case XKB_KEY_BackSpace:
|
||||
ply_buffer_append_bytes (input_buffer, "\177", 1);
|
||||
break;
|
||||
case XKB_KEY_NoSymbol:
|
||||
break;
|
||||
default:
|
||||
character_size = xkb_state_key_get_utf8 (input_device->keyboard_state, keycode, NULL, 0);
|
||||
|
||||
if (character_size > 0) {
|
||||
char character_buf[character_size + 1];
|
||||
|
||||
character_size = xkb_state_key_get_utf8 (input_device->keyboard_state, keycode, character_buf, sizeof(character_buf));
|
||||
|
||||
assert (character_size + 1 == sizeof(character_buf));
|
||||
|
||||
ply_buffer_append_bytes (input_buffer, character_buf, character_size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_input (ply_input_device_t *input_device)
|
||||
{
|
||||
struct input_event ev;
|
||||
int rc;
|
||||
ply_buffer_t *input_buffer = ply_buffer_new ();
|
||||
|
||||
for (;;) {
|
||||
ply_key_direction_t key_state;
|
||||
enum xkb_key_direction xkb_key_direction;
|
||||
xkb_keycode_t keycode;
|
||||
xkb_keysym_t symbol;
|
||||
enum xkb_state_component updated_state;
|
||||
|
||||
rc = libevdev_next_event (input_device->dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
|
||||
if (rc != LIBEVDEV_READ_STATUS_SUCCESS)
|
||||
break;
|
||||
|
||||
if (!libevdev_event_is_type (&ev, EV_KEY))
|
||||
continue;
|
||||
|
||||
/* According to `https://docs.kernel.org/input/event-codes.html#ev-key`:
|
||||
* if ev.value = 2, then the key is being held down. libxkbcommon doesn't appear to define this
|
||||
* if ev.value = 1, then key was pressed down
|
||||
* if ev.value = 0, then key was released up
|
||||
*/
|
||||
switch (ev.value) {
|
||||
case 0:
|
||||
key_state = PLY_KEY_UP;
|
||||
xkb_key_direction = XKB_KEY_UP;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
key_state = PLY_KEY_DOWN;
|
||||
xkb_key_direction = XKB_KEY_DOWN;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
key_state = PLY_KEY_HELD;
|
||||
xkb_key_direction = XKB_KEY_UP;
|
||||
break;
|
||||
}
|
||||
|
||||
/* According to
|
||||
* `https://xkbcommon.org/doc/current/xkbcommon_8h.html#ac29aee92124c08d1953910ab28ee1997`
|
||||
* A xkb keycode = linux evdev code + 8
|
||||
*/
|
||||
keycode = (xkb_keycode_t) (ev.code + 8);
|
||||
|
||||
symbol = xkb_state_key_get_one_sym (input_device->keyboard_state, keycode);
|
||||
|
||||
updated_state = xkb_state_update_key (input_device->keyboard_state, keycode, xkb_key_direction);
|
||||
|
||||
if ((updated_state & XKB_STATE_LEDS) != 0)
|
||||
ply_trigger_pull (input_device->leds_changed_trigger, input_device);
|
||||
|
||||
/* If the key is repeating, or is being pressed down */
|
||||
if (key_state == PLY_KEY_HELD || key_state == PLY_KEY_DOWN)
|
||||
apply_key_to_input_buffer (input_device, symbol, keycode, input_buffer);
|
||||
}
|
||||
if (rc != -EAGAIN) {
|
||||
ply_error ("There was an error reading events for device '%s': %s",
|
||||
input_device->path, strerror (-rc));
|
||||
goto error;
|
||||
}
|
||||
if (ply_buffer_get_size (input_buffer) != 0) {
|
||||
ply_trigger_pull (input_device->input_trigger, ply_buffer_get_bytes (input_buffer));
|
||||
}
|
||||
|
||||
error:
|
||||
ply_buffer_free (input_buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
on_disconnect (ply_input_device_t *input_device)
|
||||
{
|
||||
ply_trace ("Input disconnected: %s (%s)", libevdev_get_name (input_device->dev),
|
||||
input_device->path);
|
||||
ply_trigger_pull (input_device->disconnect_trigger, input_device);
|
||||
|
||||
ply_input_device_free (input_device);
|
||||
}
|
||||
|
||||
void
|
||||
ply_input_device_set_disconnect_handler (ply_input_device_t *input_device,
|
||||
ply_input_device_disconnect_handler_t callback,
|
||||
void *user_data)
|
||||
{
|
||||
ply_trigger_add_handler (input_device->disconnect_trigger, (ply_trigger_handler_t) callback, user_data);
|
||||
}
|
||||
|
||||
ply_input_device_t *
|
||||
ply_input_device_open (struct xkb_context *xkb_context,
|
||||
struct xkb_keymap *xkb_keymap,
|
||||
const char *path)
|
||||
{
|
||||
int error;
|
||||
const char *locale;
|
||||
|
||||
/* Look up the preferred locale, falling back to "C" as default */
|
||||
if (!(locale = getenv ("LC_ALL")))
|
||||
if (!(locale = getenv ("LC_CTYPE")))
|
||||
if (!(locale = getenv ("LANG")))
|
||||
locale = "C";
|
||||
|
||||
ply_input_device_t *input_device = calloc (1, sizeof(ply_input_device_t));
|
||||
|
||||
if (input_device == NULL) {
|
||||
ply_error ("Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
input_device->disconnect_trigger = ply_trigger_new (NULL);
|
||||
input_device->path = strdup (path);
|
||||
input_device->input_trigger = ply_trigger_new (NULL);
|
||||
ply_trigger_set_instance (input_device->input_trigger, input_device);
|
||||
|
||||
input_device->leds_changed_trigger = ply_trigger_new (NULL);
|
||||
input_device->loop = ply_event_loop_get_default ();
|
||||
|
||||
input_device->fd = open (path, O_RDWR | O_NONBLOCK);
|
||||
|
||||
if (input_device->fd < 0) {
|
||||
ply_error ("Failed to open input device \"%s\"", path);
|
||||
goto error;
|
||||
}
|
||||
input_device->dev = libevdev_new ();
|
||||
error = libevdev_set_fd (input_device->dev, input_device->fd);
|
||||
if (error != 0) {
|
||||
ply_error ("Failed to set fd for device \"%s\": %s", path, strerror (-error));
|
||||
goto error;
|
||||
}
|
||||
|
||||
input_device->fd_watch = ply_event_loop_watch_fd (
|
||||
input_device->loop, input_device->fd, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
|
||||
(ply_event_handler_t) on_input, (ply_event_handler_t) on_disconnect,
|
||||
input_device);
|
||||
|
||||
input_device->keymap = xkb_keymap_ref (xkb_keymap);
|
||||
input_device->keyboard_state = xkb_state_new (input_device->keymap);
|
||||
if (input_device->keyboard_state == NULL) {
|
||||
ply_error ("Failed to initialize input device \"%s\" keyboard_state", path);
|
||||
goto error;
|
||||
}
|
||||
input_device->compose_table = xkb_compose_table_new_from_locale (xkb_context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||
if (input_device->compose_table)
|
||||
input_device->compose_state = xkb_compose_state_new (input_device->compose_table, XKB_COMPOSE_STATE_NO_FLAGS);
|
||||
|
||||
return input_device;
|
||||
|
||||
error:
|
||||
ply_input_device_free (input_device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ply_input_device_watch_for_input (ply_input_device_t *input_device,
|
||||
ply_input_device_input_handler_t input_callback,
|
||||
ply_input_device_leds_changed_handler_t leds_changed_callback,
|
||||
void *user_data)
|
||||
{
|
||||
ply_trigger_add_instance_handler (input_device->input_trigger, (ply_trigger_instance_handler_t) input_callback, user_data);
|
||||
ply_trigger_add_handler (input_device->leds_changed_trigger, (ply_trigger_handler_t) leds_changed_callback, user_data);
|
||||
}
|
||||
|
||||
void
|
||||
ply_input_device_stop_watching_for_input (ply_input_device_t *input_device,
|
||||
ply_input_device_input_handler_t input_callback,
|
||||
ply_input_device_leds_changed_handler_t leds_changed_callback,
|
||||
void *user_data)
|
||||
{
|
||||
ply_trigger_remove_instance_handler (input_device->input_trigger, (ply_trigger_instance_handler_t) input_callback, user_data);
|
||||
ply_trigger_remove_handler (input_device->leds_changed_trigger, (ply_trigger_handler_t) leds_changed_callback, user_data);
|
||||
}
|
||||
|
||||
int
|
||||
ply_input_device_is_keyboard (ply_input_device_t *input_device)
|
||||
{
|
||||
return libevdev_has_event_type (input_device->dev, EV_KEY);
|
||||
}
|
||||
|
||||
int
|
||||
ply_input_device_is_keyboard_with_leds (ply_input_device_t *input_device)
|
||||
{
|
||||
return (libevdev_has_event_type (input_device->dev, EV_KEY)) &&
|
||||
(libevdev_has_event_type (input_device->dev, EV_LED));
|
||||
}
|
||||
|
||||
const char *
|
||||
ply_input_device_get_name (ply_input_device_t *input_device)
|
||||
{
|
||||
return libevdev_get_name (input_device->dev);
|
||||
}
|
||||
|
||||
const char *
|
||||
ply_input_device_get_path (ply_input_device_t *input_device)
|
||||
{
|
||||
return input_device->path;
|
||||
}
|
||||
|
||||
/*
|
||||
* from libinput's evdev_device_led_update and Weston's weston_keyboard_set_locks
|
||||
*/
|
||||
void
|
||||
ply_input_device_set_state (ply_input_device_t *input_device,
|
||||
ply_xkb_keyboard_state_t *xkb_state)
|
||||
{
|
||||
static struct
|
||||
{
|
||||
ply_led_t ply_led;
|
||||
int evdev;
|
||||
xkb_mod_mask_t status;
|
||||
} map[] = {
|
||||
{ PLY_LED_NUM_LOCK, LED_NUML, false },
|
||||
{ PLY_LED_CAPS_LOCK, LED_CAPSL, false },
|
||||
{ PLY_LED_SCROLL_LOCK, LED_SCROLLL, false },
|
||||
};
|
||||
struct input_event ev[PLY_NUMBER_OF_ELEMENTS (map) + 1];
|
||||
xkb_mod_mask_t mods_depressed, mods_latched, mods_locked, group;
|
||||
unsigned int i;
|
||||
|
||||
mods_depressed = xkb_state_serialize_mods (input_device->keyboard_state,
|
||||
XKB_STATE_DEPRESSED);
|
||||
mods_latched = xkb_state_serialize_mods (input_device->keyboard_state,
|
||||
XKB_STATE_LATCHED);
|
||||
mods_locked = xkb_state_serialize_mods (input_device->keyboard_state,
|
||||
XKB_STATE_LOCKED);
|
||||
group = xkb_state_serialize_group (input_device->keyboard_state,
|
||||
XKB_STATE_EFFECTIVE);
|
||||
|
||||
if (mods_depressed == xkb_state->mods_depressed &&
|
||||
mods_latched == xkb_state->mods_latched &&
|
||||
mods_locked == xkb_state->mods_locked &&
|
||||
group == xkb_state->group)
|
||||
return;
|
||||
|
||||
mods_depressed = xkb_state->mods_depressed;
|
||||
mods_latched = xkb_state->mods_latched;
|
||||
mods_locked = xkb_state->mods_locked;
|
||||
group = xkb_state->group;
|
||||
|
||||
xkb_state_update_mask (input_device->keyboard_state,
|
||||
mods_depressed,
|
||||
mods_latched,
|
||||
mods_locked,
|
||||
0,
|
||||
0,
|
||||
group);
|
||||
|
||||
map[LED_NUML].status = xkb_state_led_name_is_active (input_device->keyboard_state, XKB_LED_NAME_NUM);
|
||||
map[LED_CAPSL].status = xkb_state_led_name_is_active (input_device->keyboard_state, XKB_LED_NAME_CAPS);
|
||||
map[LED_SCROLLL].status = xkb_state_led_name_is_active (input_device->keyboard_state, XKB_LED_NAME_SCROLL);
|
||||
|
||||
memset (ev, 0, sizeof(ev));
|
||||
for (i = 0; i < PLY_NUMBER_OF_ELEMENTS (map); i++) {
|
||||
ev[i].type = EV_LED;
|
||||
ev[i].code = map[i].evdev;
|
||||
ev[i].value = map[i].status;
|
||||
}
|
||||
ev[i].type = EV_SYN;
|
||||
ev[i].code = SYN_REPORT;
|
||||
|
||||
ply_write (input_device->fd, ev, sizeof(ev));
|
||||
}
|
||||
|
||||
ply_xkb_keyboard_state_t
|
||||
*ply_input_device_get_state (ply_input_device_t *input_device)
|
||||
{
|
||||
ply_xkb_keyboard_state_t *xkb_state = calloc (1, sizeof(ply_xkb_keyboard_state_t));
|
||||
|
||||
xkb_state->mods_depressed = xkb_state_serialize_mods (input_device->keyboard_state,
|
||||
XKB_STATE_DEPRESSED);
|
||||
xkb_state->mods_latched = xkb_state_serialize_mods (input_device->keyboard_state,
|
||||
XKB_STATE_LATCHED);
|
||||
xkb_state->mods_locked = xkb_state_serialize_mods (input_device->keyboard_state,
|
||||
XKB_STATE_LOCKED);
|
||||
xkb_state->group = xkb_state_serialize_group (input_device->keyboard_state,
|
||||
XKB_STATE_EFFECTIVE);
|
||||
|
||||
return xkb_state;
|
||||
}
|
||||
|
||||
bool
|
||||
ply_input_device_get_capslock_state (ply_input_device_t *input_device)
|
||||
{
|
||||
return xkb_state_led_name_is_active (input_device->keyboard_state, XKB_LED_NAME_CAPS);
|
||||
}
|
||||
|
||||
const char *
|
||||
ply_input_device_get_keymap (ply_input_device_t *input_device)
|
||||
{
|
||||
xkb_layout_index_t num_indices = xkb_keymap_num_layouts (input_device->keymap);
|
||||
ply_trace ("xkb layout has %d groups", num_indices);
|
||||
if (num_indices == 0) {
|
||||
return NULL;
|
||||
}
|
||||
/* According to xkbcommon docs:
|
||||
* (https://xkbcommon.org/doc/current/xkbcommon_8h.html#ad37512642806c55955e1cd5a30efcc39)
|
||||
*
|
||||
* Each layout is not required to have a name, and the names are not
|
||||
* guaranteed to be unique (though they are usually provided and
|
||||
* unique). Therefore, it is not safe to use the name as a unique
|
||||
* identifier for a layout. Layout names are case-sensitive.
|
||||
*
|
||||
* Layout names are specified in the layout's definition, for example "English
|
||||
* (US)". These are different from the (conventionally) short names
|
||||
* which are used to locate the layout, for example "us" or "us(intl)".
|
||||
* These names are not present in a compiled keymap.
|
||||
*
|
||||
* This string shouldn't be used as a unique indentifier for a keymap
|
||||
*/
|
||||
return xkb_keymap_layout_get_name (input_device->keymap, num_indices - 1);
|
||||
}
|
||||
|
||||
int
|
||||
ply_input_device_get_fd (ply_input_device_t *input_device)
|
||||
{
|
||||
return input_device->fd;
|
||||
}
|
||||
|
||||
void
|
||||
ply_input_device_free (ply_input_device_t *input_device)
|
||||
{
|
||||
if (input_device == NULL)
|
||||
return;
|
||||
|
||||
if (input_device->xkb_context)
|
||||
xkb_context_unref (input_device->xkb_context);
|
||||
|
||||
if (input_device->keyboard_state)
|
||||
xkb_state_unref (input_device->keyboard_state);
|
||||
|
||||
if (input_device->keymap)
|
||||
xkb_keymap_unref (input_device->keymap);
|
||||
|
||||
if (input_device->compose_state)
|
||||
xkb_compose_state_unref (input_device->compose_state);
|
||||
|
||||
if (input_device->compose_table)
|
||||
xkb_compose_table_unref (input_device->compose_table);
|
||||
|
||||
if (input_device->dev)
|
||||
libevdev_free (input_device->dev);
|
||||
|
||||
ply_trigger_free (input_device->input_trigger);
|
||||
ply_trigger_free (input_device->leds_changed_trigger);
|
||||
ply_trigger_free (input_device->disconnect_trigger);
|
||||
|
||||
free (input_device->path);
|
||||
|
||||
ply_event_loop_stop_watching_fd (input_device->loop, input_device->fd_watch);
|
||||
|
||||
close (input_device->fd);
|
||||
|
||||
free (input_device);
|
||||
}
|
||||
92
src/libply-splash-core/ply-input-device.h
Normal file
92
src/libply-splash-core/ply-input-device.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/* ply-input-device.h - evdev input device handling
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Written By: Diego Augusto <diego.augusto@protonmail.com>
|
||||
*/
|
||||
#ifndef PLY_INPUT_DEVICE_H
|
||||
#define PLY_INPUT_DEVICE_H
|
||||
|
||||
#include "ply-buffer.h"
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-compose.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PLY_LED_NUM_LOCK = (1 << 0),
|
||||
PLY_LED_CAPS_LOCK = (1 << 1),
|
||||
PLY_LED_SCROLL_LOCK = (1 << 2)
|
||||
} ply_led_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PLY_KEY_UP,
|
||||
PLY_KEY_DOWN,
|
||||
PLY_KEY_HELD,
|
||||
} ply_key_direction_t;
|
||||
|
||||
typedef struct _ply_input_device ply_input_device_t;
|
||||
typedef void (*ply_input_device_input_handler_t) (void *user_data,
|
||||
ply_input_device_t *input_device,
|
||||
const char *buf);
|
||||
typedef void (*ply_input_device_leds_changed_handler_t) (void *user_data,
|
||||
ply_input_device_t *input_device);
|
||||
typedef void (*ply_input_device_disconnect_handler_t) (void *user_data,
|
||||
ply_input_device_t *input_device);
|
||||
typedef struct
|
||||
{
|
||||
xkb_mod_mask_t mods_depressed;
|
||||
xkb_mod_mask_t mods_latched;
|
||||
xkb_mod_mask_t mods_locked;
|
||||
xkb_mod_mask_t group;
|
||||
} ply_xkb_keyboard_state_t;
|
||||
|
||||
#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
|
||||
|
||||
ply_input_device_t *ply_input_device_open (struct xkb_context *xkb_context,
|
||||
struct xkb_keymap *xkb_keymap,
|
||||
const char *path);
|
||||
void ply_input_device_free (ply_input_device_t *input_device);
|
||||
void ply_input_device_watch_for_input (ply_input_device_t *input_device,
|
||||
ply_input_device_input_handler_t input_callback,
|
||||
ply_input_device_leds_changed_handler_t led_callback,
|
||||
void *user_data);
|
||||
|
||||
void ply_input_device_stop_watching_for_input (ply_input_device_t *input_device,
|
||||
ply_input_device_input_handler_t input_callback,
|
||||
ply_input_device_leds_changed_handler_t led_callback,
|
||||
void *user_data);
|
||||
|
||||
|
||||
ply_xkb_keyboard_state_t *ply_input_device_get_state (ply_input_device_t *input_device);
|
||||
void ply_input_device_set_state (ply_input_device_t *input_device,
|
||||
ply_xkb_keyboard_state_t *xkb_state);
|
||||
|
||||
void ply_input_device_set_disconnect_handler (ply_input_device_t *input_device,
|
||||
ply_input_device_disconnect_handler_t callback,
|
||||
void *user_data);
|
||||
int ply_input_device_get_fd (ply_input_device_t *input_device);
|
||||
int ply_input_device_is_keyboard (ply_input_device_t *input_device);
|
||||
int ply_input_device_is_keyboard_with_leds (ply_input_device_t *input_device);
|
||||
const char *ply_input_device_get_name (ply_input_device_t *input_device);
|
||||
bool ply_input_device_get_capslock_state (ply_input_device_t *input_device);
|
||||
/* The value shouldn't be used as a unique indentifier for a keymap */
|
||||
const char *ply_input_device_get_keymap (ply_input_device_t *input_device);
|
||||
const char *ply_input_device_get_path (ply_input_device_t *input_device);
|
||||
|
||||
#endif //PLY_HIDE_FUNCTION_DECLARATIONS
|
||||
|
||||
#endif //PLY_INPUT_DEVICE_H
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "ply-input-device.h"
|
||||
#include "ply-terminal.h"
|
||||
#include "ply-event-loop.h"
|
||||
#include "ply-list.h"
|
||||
|
|
@ -76,6 +77,11 @@ typedef struct
|
|||
int *scale);
|
||||
bool (*get_capslock_state)(ply_renderer_backend_t *backend);
|
||||
const char * (*get_keymap)(ply_renderer_backend_t *backend);
|
||||
|
||||
void (*add_input_device)(ply_renderer_backend_t *backend,
|
||||
ply_input_device_t *input_device);
|
||||
void (*remove_input_device)(ply_renderer_backend_t *backend,
|
||||
ply_input_device_t *input_device);
|
||||
} ply_renderer_plugin_interface_t;
|
||||
|
||||
#endif /* PLY_RENDERER_PLUGIN_H */
|
||||
|
|
|
|||
|
|
@ -368,6 +368,34 @@ ply_renderer_flush_head (ply_renderer_t *renderer,
|
|||
renderer->plugin_interface->flush_head (renderer->backend, head);
|
||||
}
|
||||
|
||||
void
|
||||
ply_renderer_add_input_device (ply_renderer_t *renderer,
|
||||
ply_input_device_t *input_device)
|
||||
{
|
||||
assert (renderer != NULL);
|
||||
assert (renderer->plugin_interface != NULL);
|
||||
assert (input_device != NULL);
|
||||
|
||||
if (!renderer->plugin_interface->add_input_device)
|
||||
return;
|
||||
|
||||
renderer->plugin_interface->add_input_device (renderer->backend, input_device);
|
||||
}
|
||||
|
||||
void
|
||||
ply_renderer_remove_input_device (ply_renderer_t *renderer,
|
||||
ply_input_device_t *input_device)
|
||||
{
|
||||
assert (renderer != NULL);
|
||||
assert (renderer->plugin_interface != NULL);
|
||||
assert (input_device != NULL);
|
||||
|
||||
if (!renderer->plugin_interface->remove_input_device)
|
||||
return;
|
||||
|
||||
renderer->plugin_interface->remove_input_device (renderer->backend, input_device);
|
||||
}
|
||||
|
||||
ply_renderer_input_source_t *
|
||||
ply_renderer_get_input_source (ply_renderer_t *renderer)
|
||||
{
|
||||
|
|
@ -452,4 +480,3 @@ ply_renderer_get_keymap (ply_renderer_t *renderer)
|
|||
|
||||
return renderer->plugin_interface->get_keymap (renderer->backend);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "ply-pixel-buffer.h"
|
||||
#include "ply-terminal.h"
|
||||
#include "ply-utils.h"
|
||||
#include "ply-input-device.h"
|
||||
|
||||
typedef struct _ply_renderer ply_renderer_t;
|
||||
typedef struct _ply_renderer_head ply_renderer_head_t;
|
||||
|
|
@ -68,6 +69,12 @@ ply_pixel_buffer_t *ply_renderer_get_buffer_for_head (ply_renderer_t *rende
|
|||
void ply_renderer_flush_head (ply_renderer_t *renderer,
|
||||
ply_renderer_head_t *head);
|
||||
|
||||
void ply_renderer_add_input_device (ply_renderer_t *renderer,
|
||||
ply_input_device_t *input_device);
|
||||
|
||||
void ply_renderer_remove_input_device (ply_renderer_t *renderer,
|
||||
ply_input_device_t *input_device);
|
||||
|
||||
ply_renderer_input_source_t *ply_renderer_get_input_source (ply_renderer_t *renderer);
|
||||
bool ply_renderer_open_input_source (ply_renderer_t *renderer,
|
||||
ply_renderer_input_source_t *input_source);
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ struct _ply_terminal
|
|||
struct termios original_locked_term_attributes;
|
||||
|
||||
char *name;
|
||||
char *keymap;
|
||||
const char *keymap;
|
||||
int fd;
|
||||
int vt_number;
|
||||
int initial_vt_number;
|
||||
|
|
@ -117,37 +117,9 @@ typedef enum
|
|||
|
||||
static ply_terminal_open_result_t ply_terminal_open_device (ply_terminal_t *terminal);
|
||||
|
||||
static char *
|
||||
ply_terminal_parse_keymap_conf (ply_terminal_t *terminal)
|
||||
{
|
||||
ply_key_file_t *vconsole_conf;
|
||||
char *keymap, *old_keymap;
|
||||
|
||||
keymap = ply_kernel_command_line_get_key_value ("rd.vconsole.keymap=");
|
||||
if (keymap)
|
||||
return keymap;
|
||||
|
||||
keymap = ply_kernel_command_line_get_key_value ("vconsole.keymap=");
|
||||
if (keymap)
|
||||
return keymap;
|
||||
|
||||
vconsole_conf = ply_key_file_new ("/etc/vconsole.conf");
|
||||
if (ply_key_file_load_groupless_file (vconsole_conf))
|
||||
keymap = ply_key_file_get_value (vconsole_conf, NULL, "KEYMAP");
|
||||
ply_key_file_free (vconsole_conf);
|
||||
|
||||
/* The keymap name in vconsole.conf might be quoted, strip these */
|
||||
if (keymap && keymap[0] == '"' && keymap[strlen (keymap) - 1] == '"') {
|
||||
old_keymap = keymap;
|
||||
keymap = strndup (keymap + 1, strlen (keymap) - 2);
|
||||
free (old_keymap);
|
||||
}
|
||||
|
||||
return keymap;
|
||||
}
|
||||
|
||||
ply_terminal_t *
|
||||
ply_terminal_new (const char *device_name)
|
||||
ply_terminal_new (const char *device_name,
|
||||
const char *keymap)
|
||||
{
|
||||
ply_terminal_t *terminal;
|
||||
|
||||
|
|
@ -167,7 +139,7 @@ ply_terminal_new (const char *device_name)
|
|||
terminal->fd = -1;
|
||||
terminal->vt_number = -1;
|
||||
terminal->initial_vt_number = -1;
|
||||
terminal->keymap = ply_terminal_parse_keymap_conf (terminal);
|
||||
terminal->keymap = keymap;
|
||||
if (terminal->keymap)
|
||||
ply_trace ("terminal %s keymap: %s", terminal->name, terminal->keymap);
|
||||
|
||||
|
|
@ -879,7 +851,6 @@ ply_terminal_free (ply_terminal_t *terminal)
|
|||
|
||||
free_vt_change_closures (terminal);
|
||||
free_input_closures (terminal);
|
||||
free (terminal->keymap);
|
||||
free (terminal->name);
|
||||
free (terminal);
|
||||
}
|
||||
|
|
@ -1101,3 +1072,12 @@ ply_terminal_stop_watching_for_input (ply_terminal_t *terminal,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ply_terminal_flush_input (ply_terminal_t *terminal)
|
||||
{
|
||||
if (!terminal->is_open)
|
||||
return;
|
||||
|
||||
if (tcflush (terminal->fd, TCIFLUSH) < 0)
|
||||
ply_trace ("could not flush input buffer of terminal %s: %m", terminal->name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ typedef enum
|
|||
} ply_terminal_mode_t;
|
||||
|
||||
#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
|
||||
ply_terminal_t *ply_terminal_new (const char *device_name);
|
||||
ply_terminal_t *ply_terminal_new (const char *device_name,
|
||||
const char *keymap);
|
||||
|
||||
void ply_terminal_free (ply_terminal_t *terminal);
|
||||
|
||||
|
|
@ -116,7 +117,8 @@ void ply_terminal_stop_watching_for_input (ply_terminal_t *terminal
|
|||
ply_terminal_input_handler_t input_handler,
|
||||
void *user_data);
|
||||
|
||||
void ply_terminal_flush_input (ply_terminal_t *terminal);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* PLY_TERMINAL_H */
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ ply_keymap_icon_fill_keymap_info (ply_keymap_icon_t *keymap_icon)
|
|||
{
|
||||
const char *keymap_with_variant;
|
||||
ply_renderer_t *renderer;
|
||||
char *keymap;
|
||||
char *keymap, *compare_keymap;
|
||||
int i;
|
||||
|
||||
keymap_icon->keymap_offset = -1;
|
||||
|
|
@ -95,7 +95,13 @@ ply_keymap_icon_fill_keymap_info (ply_keymap_icon_t *keymap_icon)
|
|||
keymap = ply_keymap_normalize_keymap (keymap_with_variant);
|
||||
|
||||
for (i = 0; ply_keymap_metadata[i].name; i++) {
|
||||
if (strcmp (ply_keymap_metadata[i].name, keymap) == 0) {
|
||||
if (ply_keymap_metadata[i].type == PLY_LAYOUT_TERMINAL) {
|
||||
compare_keymap = strdup (keymap);
|
||||
} else if (ply_keymap_metadata[i].type == PLY_LAYOUT_XKB) {
|
||||
compare_keymap = strdup (keymap_with_variant);
|
||||
}
|
||||
|
||||
if (strcmp (ply_keymap_metadata[i].name, compare_keymap) == 0) {
|
||||
keymap_icon->keymap_offset = ply_keymap_metadata[i].offset;
|
||||
keymap_icon->keymap_width = ply_keymap_metadata[i].width;
|
||||
break;
|
||||
|
|
@ -106,6 +112,7 @@ ply_keymap_icon_fill_keymap_info (ply_keymap_icon_t *keymap_icon)
|
|||
ply_trace ("Error no pre-rendered text for '%s' keymap", keymap);
|
||||
|
||||
free (keymap);
|
||||
free (compare_keymap);
|
||||
}
|
||||
|
||||
ply_keymap_icon_t *
|
||||
|
|
@ -273,4 +280,3 @@ ply_keymap_icon_get_height (ply_keymap_icon_t *keymap_icon)
|
|||
{
|
||||
return keymap_icon->height;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,139 +1,256 @@
|
|||
/* This file is autogenerated by running:
|
||||
* scripts/keymap-render.py > src/libply-splash-graphics/ply-keymap-metadata.h
|
||||
*/
|
||||
struct ply_keymap_metadata
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
int offset;
|
||||
int width;
|
||||
};
|
||||
int type;
|
||||
} ply_keymap_metadata_t;
|
||||
|
||||
static struct ply_keymap_metadata ply_keymap_metadata[] = {
|
||||
{ "dvorak", 10, 113 },
|
||||
{ "al", 123, 44 },
|
||||
{ "amiga", 167, 101 },
|
||||
{ "applkey", 268, 126 },
|
||||
{ "at", 394, 46 },
|
||||
{ "atari", 440, 81 },
|
||||
{ "az", 521, 49 },
|
||||
{ "azerty", 570, 104 },
|
||||
{ "ba", 674, 49 },
|
||||
{ "backspace", 723, 157 },
|
||||
{ "bashkir", 880, 119 },
|
||||
{ "be", 999, 50 },
|
||||
{ "bg", 1049, 51 },
|
||||
{ "br", 1100, 48 },
|
||||
{ "by", 1148, 51 },
|
||||
{ "bywin", 1199, 98 },
|
||||
{ "ca", 1297, 47 },
|
||||
{ "carpalx", 1344, 118 },
|
||||
{ "cf", 1462, 45 },
|
||||
{ "ch", 1507, 49 },
|
||||
{ "cm", 1556, 59 },
|
||||
{ "cn", 1615, 49 },
|
||||
{ "croat", 1664, 89 },
|
||||
{ "ctrl", 1753, 65 },
|
||||
{ "cz", 1818, 47 },
|
||||
{ "de", 1865, 51 },
|
||||
{ "defkeymap", 1916, 170 },
|
||||
{ "dk", 2086, 53 },
|
||||
{ "dz", 2139, 50 },
|
||||
{ "ee", 2189, 50 },
|
||||
{ "emacs", 2239, 106 },
|
||||
{ "emacs2", 2345, 122 },
|
||||
{ "en", 2467, 51 },
|
||||
{ "epo", 2518, 68 },
|
||||
{ "es", 2586, 49 },
|
||||
{ "et", 2635, 46 },
|
||||
{ "euro", 2681, 80 },
|
||||
{ "euro1", 2761, 95 },
|
||||
{ "euro2", 2856, 97 },
|
||||
{ "fi", 2953, 38 },
|
||||
{ "fo", 2991, 47 },
|
||||
{ "fr", 3038, 44 },
|
||||
{ "gb", 3082, 53 },
|
||||
{ "ge", 3135, 51 },
|
||||
{ "gh", 3186, 52 },
|
||||
{ "gr", 3238, 49 },
|
||||
{ "hr", 3287, 48 },
|
||||
{ "hu", 3335, 50 },
|
||||
{ "hu101", 3385, 99 },
|
||||
{ "ie", 3484, 42 },
|
||||
{ "il", 3526, 36 },
|
||||
{ "in", 3562, 43 },
|
||||
{ "iq", 3605, 43 },
|
||||
{ "ir", 3648, 40 },
|
||||
{ "is", 3688, 41 },
|
||||
{ "it", 3729, 38 },
|
||||
{ "it2", 3767, 54 },
|
||||
{ "jp", 3821, 46 },
|
||||
{ "jp106", 3867, 96 },
|
||||
{ "kazakh", 3963, 112 },
|
||||
{ "ke", 4075, 49 },
|
||||
{ "keypad", 4124, 114 },
|
||||
{ "kr", 4238, 47 },
|
||||
{ "ky", 4285, 50 },
|
||||
{ "kyrgyz", 4335, 107 },
|
||||
{ "kz", 4442, 48 },
|
||||
{ "la", 4490, 42 },
|
||||
{ "latam", 4532, 97 },
|
||||
{ "lk", 4629, 45 },
|
||||
{ "lt", 4674, 39 },
|
||||
{ "lv", 4713, 44 },
|
||||
{ "ma", 4757, 59 },
|
||||
{ "pl", 4816, 44 },
|
||||
{ "pt", 4860, 46 },
|
||||
{ "se", 4906, 48 },
|
||||
{ "template", 4954, 142 },
|
||||
{ "uk", 5096, 53 },
|
||||
{ "us", 5149, 50 },
|
||||
{ "md", 5199, 61 },
|
||||
{ "me", 5260, 60 },
|
||||
{ "mk", 5320, 62 },
|
||||
{ "mk0", 5382, 79 },
|
||||
{ "ml", 5461, 54 },
|
||||
{ "mm", 5515, 71 },
|
||||
{ "mt", 5586, 56 },
|
||||
{ "ng", 5642, 51 },
|
||||
{ "nl", 5693, 44 },
|
||||
{ "nl2", 5737, 60 },
|
||||
{ "no", 5797, 51 },
|
||||
{ "pc110", 5848, 95 },
|
||||
{ "ph", 5943, 51 },
|
||||
{ "pl1", 5994, 58 },
|
||||
{ "pl2", 6052, 60 },
|
||||
{ "pl3", 6112, 60 },
|
||||
{ "pl4", 6172, 62 },
|
||||
{ "ro", 6234, 46 },
|
||||
{ "rs", 6280, 44 },
|
||||
{ "ru", 6324, 45 },
|
||||
{ "ru1", 6369, 61 },
|
||||
{ "ru2", 6430, 63 },
|
||||
{ "ru3", 6493, 63 },
|
||||
{ "ru4", 6556, 65 },
|
||||
{ "ruwin", 6621, 95 },
|
||||
{ "sg", 6716, 49 },
|
||||
{ "si", 6765, 40 },
|
||||
{ "sk", 6805, 50 },
|
||||
{ "slovene", 6855, 122 },
|
||||
{ "sr", 6977, 46 },
|
||||
{ "sunkeymap", 7023, 174 },
|
||||
{ "sv", 7197, 49 },
|
||||
{ "sy", 7246, 49 },
|
||||
{ "tj", 7295, 38 },
|
||||
{ "tm", 7333, 57 },
|
||||
{ "tr", 7390, 44 },
|
||||
{ "tralt", 7434, 79 },
|
||||
{ "trf", 7513, 55 },
|
||||
{ "trq", 7568, 59 },
|
||||
{ "ttwin", 7627, 90 },
|
||||
{ "tw", 7717, 56 },
|
||||
{ "ua", 7773, 50 },
|
||||
{ "unicode", 7823, 124 },
|
||||
{ "uz", 7947, 50 },
|
||||
{ "vn", 7997, 51 },
|
||||
{ "wangbe", 8048, 126 },
|
||||
{ "wangbe2", 8174, 143 },
|
||||
{ "windowkeys", 8317, 188 },
|
||||
{ NULL, } /* End of array marker */
|
||||
typedef enum
|
||||
{
|
||||
PLY_LAYOUT_TERMINAL,
|
||||
PLY_LAYOUT_XKB,
|
||||
} ply_layout_types_t;
|
||||
|
||||
static ply_keymap_metadata_t ply_keymap_metadata[] = {
|
||||
{ "3l", 10, 47, PLY_LAYOUT_TERMINAL },
|
||||
{ "dvorak", 57, 113, PLY_LAYOUT_TERMINAL },
|
||||
{ "adnw", 170, 94, PLY_LAYOUT_TERMINAL },
|
||||
{ "al", 264, 45, PLY_LAYOUT_TERMINAL },
|
||||
{ "amiga", 309, 103, PLY_LAYOUT_TERMINAL },
|
||||
{ "apple", 412, 93, PLY_LAYOUT_TERMINAL },
|
||||
{ "applkey", 505, 126, PLY_LAYOUT_TERMINAL },
|
||||
{ "ara", 631, 62, PLY_LAYOUT_TERMINAL },
|
||||
{ "at", 693, 46, PLY_LAYOUT_TERMINAL },
|
||||
{ "atari", 739, 81, PLY_LAYOUT_TERMINAL },
|
||||
{ "az", 820, 49, PLY_LAYOUT_TERMINAL },
|
||||
{ "azerty", 869, 105, PLY_LAYOUT_TERMINAL },
|
||||
{ "ba", 974, 50, PLY_LAYOUT_TERMINAL },
|
||||
{ "backspace", 1024, 157, PLY_LAYOUT_TERMINAL },
|
||||
{ "bashkir", 1181, 119, PLY_LAYOUT_TERMINAL },
|
||||
{ "be", 1300, 50, PLY_LAYOUT_TERMINAL },
|
||||
{ "bg", 1350, 51, PLY_LAYOUT_TERMINAL },
|
||||
{ "bone", 1401, 84, PLY_LAYOUT_TERMINAL },
|
||||
{ "br", 1485, 48, PLY_LAYOUT_TERMINAL },
|
||||
{ "by", 1533, 51, PLY_LAYOUT_TERMINAL },
|
||||
{ "bywin", 1584, 98, PLY_LAYOUT_TERMINAL },
|
||||
{ "ca", 1682, 48, PLY_LAYOUT_TERMINAL },
|
||||
{ "carpalx", 1730, 118, PLY_LAYOUT_TERMINAL },
|
||||
{ "cf", 1848, 46, PLY_LAYOUT_TERMINAL },
|
||||
{ "ch", 1894, 49, PLY_LAYOUT_TERMINAL },
|
||||
{ "cm", 1943, 59, PLY_LAYOUT_TERMINAL },
|
||||
{ "cn", 2002, 49, PLY_LAYOUT_TERMINAL },
|
||||
{ "croat", 2051, 89, PLY_LAYOUT_TERMINAL },
|
||||
{ "ctrl", 2140, 66, PLY_LAYOUT_TERMINAL },
|
||||
{ "cz", 2206, 47, PLY_LAYOUT_TERMINAL },
|
||||
{ "de", 2253, 51, PLY_LAYOUT_TERMINAL },
|
||||
{ "defkeymap", 2304, 170, PLY_LAYOUT_TERMINAL },
|
||||
{ "dk", 2474, 53, PLY_LAYOUT_TERMINAL },
|
||||
{ "dz", 2527, 50, PLY_LAYOUT_TERMINAL },
|
||||
{ "ee", 2577, 50, PLY_LAYOUT_TERMINAL },
|
||||
{ "emacs", 2627, 106, PLY_LAYOUT_TERMINAL },
|
||||
{ "emacs2", 2733, 122, PLY_LAYOUT_TERMINAL },
|
||||
{ "en", 2855, 51, PLY_LAYOUT_TERMINAL },
|
||||
{ "epo", 2906, 69, PLY_LAYOUT_TERMINAL },
|
||||
{ "es", 2975, 49, PLY_LAYOUT_TERMINAL },
|
||||
{ "et", 3024, 46, PLY_LAYOUT_TERMINAL },
|
||||
{ "euro", 3070, 81, PLY_LAYOUT_TERMINAL },
|
||||
{ "euro1", 3151, 92, PLY_LAYOUT_TERMINAL },
|
||||
{ "euro2", 3243, 97, PLY_LAYOUT_TERMINAL },
|
||||
{ "fa", 3340, 46, PLY_LAYOUT_TERMINAL },
|
||||
{ "fi", 3386, 38, PLY_LAYOUT_TERMINAL },
|
||||
{ "fo", 3424, 48, PLY_LAYOUT_TERMINAL },
|
||||
{ "fr", 3472, 44, PLY_LAYOUT_TERMINAL },
|
||||
{ "gb", 3516, 54, PLY_LAYOUT_TERMINAL },
|
||||
{ "ge", 3570, 52, PLY_LAYOUT_TERMINAL },
|
||||
{ "gh", 3622, 53, PLY_LAYOUT_TERMINAL },
|
||||
{ "gr", 3675, 50, PLY_LAYOUT_TERMINAL },
|
||||
{ "hr", 3725, 48, PLY_LAYOUT_TERMINAL },
|
||||
{ "hu", 3773, 50, PLY_LAYOUT_TERMINAL },
|
||||
{ "hu101", 3823, 96, PLY_LAYOUT_TERMINAL },
|
||||
{ "id", 3919, 43, PLY_LAYOUT_TERMINAL },
|
||||
{ "ie", 3962, 42, PLY_LAYOUT_TERMINAL },
|
||||
{ "il", 4004, 37, PLY_LAYOUT_TERMINAL },
|
||||
{ "in", 4041, 43, PLY_LAYOUT_TERMINAL },
|
||||
{ "iq", 4084, 43, PLY_LAYOUT_TERMINAL },
|
||||
{ "ir", 4127, 40, PLY_LAYOUT_TERMINAL },
|
||||
{ "is", 4167, 41, PLY_LAYOUT_TERMINAL },
|
||||
{ "it", 4208, 38, PLY_LAYOUT_TERMINAL },
|
||||
{ "it2", 4246, 54, PLY_LAYOUT_TERMINAL },
|
||||
{ "jp", 4300, 46, PLY_LAYOUT_TERMINAL },
|
||||
{ "jp106", 4346, 96, PLY_LAYOUT_TERMINAL },
|
||||
{ "kazakh", 4442, 113, PLY_LAYOUT_TERMINAL },
|
||||
{ "ke", 4555, 49, PLY_LAYOUT_TERMINAL },
|
||||
{ "keypad", 4604, 114, PLY_LAYOUT_TERMINAL },
|
||||
{ "ko", 4718, 51, PLY_LAYOUT_TERMINAL },
|
||||
{ "koy", 4769, 67, PLY_LAYOUT_TERMINAL },
|
||||
{ "kr", 4836, 47, PLY_LAYOUT_TERMINAL },
|
||||
{ "ky", 4883, 50, PLY_LAYOUT_TERMINAL },
|
||||
{ "kyrgyz", 4933, 108, PLY_LAYOUT_TERMINAL },
|
||||
{ "kz", 5041, 48, PLY_LAYOUT_TERMINAL },
|
||||
{ "la", 5089, 42, PLY_LAYOUT_TERMINAL },
|
||||
{ "latam", 5131, 96, PLY_LAYOUT_TERMINAL },
|
||||
{ "lk", 5227, 44, PLY_LAYOUT_TERMINAL },
|
||||
{ "lt", 5271, 38, PLY_LAYOUT_TERMINAL },
|
||||
{ "lv", 5309, 43, PLY_LAYOUT_TERMINAL },
|
||||
{ "ma", 5352, 60, PLY_LAYOUT_TERMINAL },
|
||||
{ "no", 5412, 52, PLY_LAYOUT_TERMINAL },
|
||||
{ "pl", 5464, 45, PLY_LAYOUT_TERMINAL },
|
||||
{ "pt", 5509, 46, PLY_LAYOUT_TERMINAL },
|
||||
{ "se", 5555, 48, PLY_LAYOUT_TERMINAL },
|
||||
{ "template", 5603, 142, PLY_LAYOUT_TERMINAL },
|
||||
{ "uk", 5745, 53, PLY_LAYOUT_TERMINAL },
|
||||
{ "us", 5798, 50, PLY_LAYOUT_TERMINAL },
|
||||
{ "md", 5848, 61, PLY_LAYOUT_TERMINAL },
|
||||
{ "me", 5909, 60, PLY_LAYOUT_TERMINAL },
|
||||
{ "mk", 5969, 62, PLY_LAYOUT_TERMINAL },
|
||||
{ "mk0", 6031, 79, PLY_LAYOUT_TERMINAL },
|
||||
{ "ml", 6110, 55, PLY_LAYOUT_TERMINAL },
|
||||
{ "mm", 6165, 71, PLY_LAYOUT_TERMINAL },
|
||||
{ "mt", 6236, 56, PLY_LAYOUT_TERMINAL },
|
||||
{ "neo", 6292, 68, PLY_LAYOUT_TERMINAL },
|
||||
{ "neoqwertz", 6360, 162, PLY_LAYOUT_TERMINAL },
|
||||
{ "ng", 6522, 51, PLY_LAYOUT_TERMINAL },
|
||||
{ "nl", 6573, 45, PLY_LAYOUT_TERMINAL },
|
||||
{ "nl2", 6618, 60, PLY_LAYOUT_TERMINAL },
|
||||
{ "pc110", 6678, 95, PLY_LAYOUT_TERMINAL },
|
||||
{ "ph", 6773, 51, PLY_LAYOUT_TERMINAL },
|
||||
{ "pl1", 6824, 55, PLY_LAYOUT_TERMINAL },
|
||||
{ "pl2", 6879, 60, PLY_LAYOUT_TERMINAL },
|
||||
{ "pl3", 6939, 61, PLY_LAYOUT_TERMINAL },
|
||||
{ "pl4", 7000, 62, PLY_LAYOUT_TERMINAL },
|
||||
{ "ro", 7062, 47, PLY_LAYOUT_TERMINAL },
|
||||
{ "rs", 7109, 44, PLY_LAYOUT_TERMINAL },
|
||||
{ "ru", 7153, 45, PLY_LAYOUT_TERMINAL },
|
||||
{ "ru1", 7198, 58, PLY_LAYOUT_TERMINAL },
|
||||
{ "ru2", 7256, 63, PLY_LAYOUT_TERMINAL },
|
||||
{ "ru3", 7319, 64, PLY_LAYOUT_TERMINAL },
|
||||
{ "ru4", 7383, 65, PLY_LAYOUT_TERMINAL },
|
||||
{ "ruwin", 7448, 95, PLY_LAYOUT_TERMINAL },
|
||||
{ "sg", 7543, 49, PLY_LAYOUT_TERMINAL },
|
||||
{ "si", 7592, 40, PLY_LAYOUT_TERMINAL },
|
||||
{ "sk", 7632, 50, PLY_LAYOUT_TERMINAL },
|
||||
{ "slovene", 7682, 122, PLY_LAYOUT_TERMINAL },
|
||||
{ "sr", 7804, 46, PLY_LAYOUT_TERMINAL },
|
||||
{ "sunkeymap", 7850, 174, PLY_LAYOUT_TERMINAL },
|
||||
{ "sv", 8024, 49, PLY_LAYOUT_TERMINAL },
|
||||
{ "sy", 8073, 49, PLY_LAYOUT_TERMINAL },
|
||||
{ "tj", 8122, 38, PLY_LAYOUT_TERMINAL },
|
||||
{ "tm", 8160, 57, PLY_LAYOUT_TERMINAL },
|
||||
{ "tr", 8217, 44, PLY_LAYOUT_TERMINAL },
|
||||
{ "tralt", 8261, 79, PLY_LAYOUT_TERMINAL },
|
||||
{ "trf", 8340, 56, PLY_LAYOUT_TERMINAL },
|
||||
{ "trq", 8396, 59, PLY_LAYOUT_TERMINAL },
|
||||
{ "ttwin", 8455, 90, PLY_LAYOUT_TERMINAL },
|
||||
{ "tw", 8545, 56, PLY_LAYOUT_TERMINAL },
|
||||
{ "ua", 8601, 51, PLY_LAYOUT_TERMINAL },
|
||||
{ "unicode", 8652, 124, PLY_LAYOUT_TERMINAL },
|
||||
{ "us1", 8776, 61, PLY_LAYOUT_TERMINAL },
|
||||
{ "uz", 8837, 50, PLY_LAYOUT_TERMINAL },
|
||||
{ "vn", 8887, 51, PLY_LAYOUT_TERMINAL },
|
||||
{ "wangbe", 8938, 127, PLY_LAYOUT_TERMINAL },
|
||||
{ "wangbe2", 9065, 144, PLY_LAYOUT_TERMINAL },
|
||||
{ "windowkeys", 9209, 188, PLY_LAYOUT_TERMINAL },
|
||||
{ "English (US)", 9397, 182, PLY_LAYOUT_XKB },
|
||||
{ "Dari", 9579, 75, PLY_LAYOUT_XKB },
|
||||
{ "Arabic", 9654, 107, PLY_LAYOUT_XKB },
|
||||
{ "Albanian", 9761, 139, PLY_LAYOUT_XKB },
|
||||
{ "Armenian", 9900, 152, PLY_LAYOUT_XKB },
|
||||
{ "German (Austria)", 10052, 252, PLY_LAYOUT_XKB },
|
||||
{ "English (Australian)", 10304, 284, PLY_LAYOUT_XKB },
|
||||
{ "Azerbaijani", 10588, 172, PLY_LAYOUT_XKB },
|
||||
{ "Belarusian", 10760, 162, PLY_LAYOUT_XKB },
|
||||
{ "Belgian", 10922, 121, PLY_LAYOUT_XKB },
|
||||
{ "Bangla", 11043, 113, PLY_LAYOUT_XKB },
|
||||
{ "Indian", 11156, 101, PLY_LAYOUT_XKB },
|
||||
{ "Bosnian", 11257, 126, PLY_LAYOUT_XKB },
|
||||
{ "Portuguese (Brazil)", 11383, 279, PLY_LAYOUT_XKB },
|
||||
{ "Bulgarian", 11662, 150, PLY_LAYOUT_XKB },
|
||||
{ "Berber (Algeria, Latin)", 11812, 317, PLY_LAYOUT_XKB },
|
||||
{ "Arabic (Morocco)", 12129, 249, PLY_LAYOUT_XKB },
|
||||
{ "English (Cameroon)", 12378, 285, PLY_LAYOUT_XKB },
|
||||
{ "Burmese", 12663, 139, PLY_LAYOUT_XKB },
|
||||
{ "French (Canada)", 12802, 237, PLY_LAYOUT_XKB },
|
||||
{ "French (Democratic Republic of the Congo)", 13039, 594, PLY_LAYOUT_XKB },
|
||||
{ "Chinese", 13633, 125, PLY_LAYOUT_XKB },
|
||||
{ "Croatian", 13758, 134, PLY_LAYOUT_XKB },
|
||||
{ "Czech", 13892, 99, PLY_LAYOUT_XKB },
|
||||
{ "Danish", 13991, 111, PLY_LAYOUT_XKB },
|
||||
{ "Dutch", 14102, 98, PLY_LAYOUT_XKB },
|
||||
{ "Dzongkha", 14200, 155, PLY_LAYOUT_XKB },
|
||||
{ "Estonian", 14355, 135, PLY_LAYOUT_XKB },
|
||||
{ "Persian", 14490, 118, PLY_LAYOUT_XKB },
|
||||
{ "Iraqi", 14608, 79, PLY_LAYOUT_XKB },
|
||||
{ "Faroese", 14687, 125, PLY_LAYOUT_XKB },
|
||||
{ "Finnish", 14812, 115, PLY_LAYOUT_XKB },
|
||||
{ "French", 14927, 110, PLY_LAYOUT_XKB },
|
||||
{ "English (Ghana)", 15037, 232, PLY_LAYOUT_XKB },
|
||||
{ "N'Ko (AZERTY)", 15269, 225, PLY_LAYOUT_XKB },
|
||||
{ "Georgian", 15494, 144, PLY_LAYOUT_XKB },
|
||||
{ "German", 15638, 128, PLY_LAYOUT_XKB },
|
||||
{ "Greek", 15766, 102, PLY_LAYOUT_XKB },
|
||||
{ "Hungarian", 15868, 160, PLY_LAYOUT_XKB },
|
||||
{ "Icelandic", 16028, 138, PLY_LAYOUT_XKB },
|
||||
{ "Hebrew", 16166, 126, PLY_LAYOUT_XKB },
|
||||
{ "Italian", 16292, 103, PLY_LAYOUT_XKB },
|
||||
{ "Japanese", 16395, 144, PLY_LAYOUT_XKB },
|
||||
{ "Kyrgyz", 16539, 112, PLY_LAYOUT_XKB },
|
||||
{ "Khmer (Cambodia)", 16651, 272, PLY_LAYOUT_XKB },
|
||||
{ "Kazakh", 16923, 117, PLY_LAYOUT_XKB },
|
||||
{ "Lao", 17040, 67, PLY_LAYOUT_XKB },
|
||||
{ "Spanish (Latin American)", 17107, 355, PLY_LAYOUT_XKB },
|
||||
{ "Lithuanian", 17462, 160, PLY_LAYOUT_XKB },
|
||||
{ "Latvian", 17622, 116, PLY_LAYOUT_XKB },
|
||||
{ "Maori", 17738, 96, PLY_LAYOUT_XKB },
|
||||
{ "Montenegrin", 17834, 192, PLY_LAYOUT_XKB },
|
||||
{ "Macedonian", 18026, 181, PLY_LAYOUT_XKB },
|
||||
{ "Maltese", 18207, 125, PLY_LAYOUT_XKB },
|
||||
{ "Mongolian", 18332, 162, PLY_LAYOUT_XKB },
|
||||
{ "Norwegian", 18494, 168, PLY_LAYOUT_XKB },
|
||||
{ "Polish", 18662, 100, PLY_LAYOUT_XKB },
|
||||
{ "Portuguese", 18762, 173, PLY_LAYOUT_XKB },
|
||||
{ "Romanian", 18935, 154, PLY_LAYOUT_XKB },
|
||||
{ "Russian", 19089, 122, PLY_LAYOUT_XKB },
|
||||
{ "Serbian", 19211, 122, PLY_LAYOUT_XKB },
|
||||
{ "Slovenian", 19333, 151, PLY_LAYOUT_XKB },
|
||||
{ "Slovak", 19484, 111, PLY_LAYOUT_XKB },
|
||||
{ "Spanish", 19595, 125, PLY_LAYOUT_XKB },
|
||||
{ "Swedish", 19720, 132, PLY_LAYOUT_XKB },
|
||||
{ "German (Switzerland)", 19852, 316, PLY_LAYOUT_XKB },
|
||||
{ "Arabic (Syria)", 20168, 200, PLY_LAYOUT_XKB },
|
||||
{ "Tajik", 20368, 87, PLY_LAYOUT_XKB },
|
||||
{ "Sinhala (phonetic)", 20455, 262, PLY_LAYOUT_XKB },
|
||||
{ "Thai", 20717, 78, PLY_LAYOUT_XKB },
|
||||
{ "Turkish", 20795, 121, PLY_LAYOUT_XKB },
|
||||
{ "Taiwanese", 20916, 164, PLY_LAYOUT_XKB },
|
||||
{ "Ukrainian", 21080, 149, PLY_LAYOUT_XKB },
|
||||
{ "English (UK)", 21229, 185, PLY_LAYOUT_XKB },
|
||||
{ "Uzbek", 21414, 105, PLY_LAYOUT_XKB },
|
||||
{ "Vietnamese", 21519, 179, PLY_LAYOUT_XKB },
|
||||
{ "Korean", 21698, 115, PLY_LAYOUT_XKB },
|
||||
{ "Irish", 21813, 77, PLY_LAYOUT_XKB },
|
||||
{ "Urdu (Pakistan)", 21890, 227, PLY_LAYOUT_XKB },
|
||||
{ "Dhivehi", 22117, 120, PLY_LAYOUT_XKB },
|
||||
{ "English (South Africa)", 22237, 310, PLY_LAYOUT_XKB },
|
||||
{ "Esperanto", 22547, 156, PLY_LAYOUT_XKB },
|
||||
{ "Nepali", 22703, 106, PLY_LAYOUT_XKB },
|
||||
{ "English (Nigeria)", 22809, 245, PLY_LAYOUT_XKB },
|
||||
{ "Amharic", 23054, 134, PLY_LAYOUT_XKB },
|
||||
{ "Wolof", 23188, 106, PLY_LAYOUT_XKB },
|
||||
{ "Braille", 23294, 107, PLY_LAYOUT_XKB },
|
||||
{ "Turkmen", 23401, 142, PLY_LAYOUT_XKB },
|
||||
{ "Bambara", 23543, 141, PLY_LAYOUT_XKB },
|
||||
{ "Swahili (Tanzania)", 23684, 267, PLY_LAYOUT_XKB },
|
||||
{ "French (Togo)", 23951, 206, PLY_LAYOUT_XKB },
|
||||
{ "Swahili (Kenya)", 24157, 228, PLY_LAYOUT_XKB },
|
||||
{ "Tswana", 24385, 124, PLY_LAYOUT_XKB },
|
||||
{ "Filipino", 24509, 119, PLY_LAYOUT_XKB },
|
||||
{ "Moldavian", 24628, 158, PLY_LAYOUT_XKB },
|
||||
{ "Indonesian (Latin)", 24786, 259, PLY_LAYOUT_XKB },
|
||||
{ "Malay (Jawi, Arabic Keyboard)", 25045, 423, PLY_LAYOUT_XKB },
|
||||
{ "A user-defined custom Layout", 25468, 423, PLY_LAYOUT_XKB },
|
||||
{ NULL, } /* End of array marker */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -181,10 +181,12 @@ ply_buffer_append_bytes (ply_buffer_t *buffer,
|
|||
{
|
||||
assert (buffer != NULL);
|
||||
assert (bytes_in != NULL);
|
||||
assert (length != 0);
|
||||
|
||||
const uint8_t *bytes = bytes_in;
|
||||
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
if (length > PLY_BUFFER_MAX_BUFFER_CAPACITY) {
|
||||
bytes += length - (PLY_BUFFER_MAX_BUFFER_CAPACITY - 1);
|
||||
length = (PLY_BUFFER_MAX_BUFFER_CAPACITY - 1);
|
||||
|
|
@ -257,4 +259,3 @@ ply_buffer_clear (ply_buffer_t *buffer)
|
|||
memset (buffer->data, '\0', buffer->capacity);
|
||||
buffer->size = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ ply_list_node_t *ply_list_get_nth_node (ply_list_t *list,
|
|||
ply_list_node_t *ply_list_get_next_node (ply_list_t *list,
|
||||
ply_list_node_t *node);
|
||||
void *ply_list_node_get_data (ply_list_node_t *node);
|
||||
|
||||
#define ply_list_foreach(list, node) \
|
||||
for (node = ply_list_get_first_node (list); node != NULL; node = ply_list_get_next_node (list, node))
|
||||
#endif
|
||||
|
||||
#endif /* PLY_LIST_H */
|
||||
|
|
|
|||
|
|
@ -30,16 +30,29 @@
|
|||
#include "ply-list.h"
|
||||
#include "ply-utils.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PLY_TRIGGER_HANDLER_TYPE_HANDLER,
|
||||
PLY_TRIGGER_HANDLER_TYPE_INSTANCE_HANDLER
|
||||
} ply_trigger_handler_type_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ply_trigger_handler_t handler;
|
||||
void *user_data;
|
||||
ply_trigger_handler_type_t handler_type;
|
||||
union
|
||||
{
|
||||
ply_trigger_handler_t handler;
|
||||
ply_trigger_instance_handler_t instance_handler;
|
||||
};
|
||||
void *user_data;
|
||||
} ply_trigger_closure_t;
|
||||
|
||||
struct _ply_trigger
|
||||
{
|
||||
ply_list_t *closures;
|
||||
|
||||
void *instance;
|
||||
|
||||
ply_trigger_t **free_address;
|
||||
int ignore_count;
|
||||
};
|
||||
|
|
@ -90,6 +103,62 @@ ply_trigger_free (ply_trigger_t *trigger)
|
|||
free (trigger);
|
||||
}
|
||||
|
||||
void
|
||||
ply_trigger_set_instance (ply_trigger_t *trigger,
|
||||
void *instance)
|
||||
{
|
||||
trigger->instance = instance;
|
||||
}
|
||||
|
||||
void *
|
||||
ply_trigger_get_instance (ply_trigger_t *trigger)
|
||||
{
|
||||
return trigger->instance;
|
||||
}
|
||||
|
||||
void
|
||||
ply_trigger_add_instance_handler (ply_trigger_t *trigger,
|
||||
ply_trigger_instance_handler_t handler,
|
||||
void *user_data)
|
||||
{
|
||||
ply_trigger_closure_t *closure;
|
||||
|
||||
closure = calloc (1, sizeof(ply_trigger_closure_t));
|
||||
closure->handler_type = PLY_TRIGGER_HANDLER_TYPE_INSTANCE_HANDLER;
|
||||
closure->instance_handler = handler;
|
||||
closure->user_data = user_data;
|
||||
|
||||
ply_list_append_data (trigger->closures, closure);
|
||||
}
|
||||
|
||||
void
|
||||
ply_trigger_remove_instance_handler (ply_trigger_t *trigger,
|
||||
ply_trigger_instance_handler_t handler,
|
||||
void *user_data)
|
||||
{
|
||||
ply_list_node_t *node;
|
||||
|
||||
node = ply_list_get_first_node (trigger->closures);
|
||||
while (node != NULL) {
|
||||
ply_list_node_t *next_node;
|
||||
ply_trigger_closure_t *closure;
|
||||
|
||||
closure = (ply_trigger_closure_t *) ply_list_node_get_data (node);
|
||||
|
||||
next_node = ply_list_get_next_node (trigger->closures, node);
|
||||
|
||||
if (closure->handler_type == PLY_TRIGGER_HANDLER_TYPE_INSTANCE_HANDLER &&
|
||||
closure->instance_handler == handler &&
|
||||
closure->user_data == user_data) {
|
||||
free (closure);
|
||||
ply_list_remove_node (trigger->closures, node);
|
||||
break;
|
||||
}
|
||||
|
||||
node = next_node;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ply_trigger_add_handler (ply_trigger_t *trigger,
|
||||
ply_trigger_handler_t handler,
|
||||
|
|
@ -98,6 +167,7 @@ ply_trigger_add_handler (ply_trigger_t *trigger,
|
|||
ply_trigger_closure_t *closure;
|
||||
|
||||
closure = calloc (1, sizeof(ply_trigger_closure_t));
|
||||
closure->handler_type = PLY_TRIGGER_HANDLER_TYPE_HANDLER;
|
||||
closure->handler = handler;
|
||||
closure->user_data = user_data;
|
||||
|
||||
|
|
@ -120,7 +190,9 @@ ply_trigger_remove_handler (ply_trigger_t *trigger,
|
|||
|
||||
next_node = ply_list_get_next_node (trigger->closures, node);
|
||||
|
||||
if (closure->handler == handler && closure->user_data == user_data) {
|
||||
if (closure->handler_type == PLY_TRIGGER_HANDLER_TYPE_HANDLER &&
|
||||
closure->handler == handler &&
|
||||
closure->user_data == user_data) {
|
||||
free (closure);
|
||||
ply_list_remove_node (trigger->closures, node);
|
||||
break;
|
||||
|
|
@ -158,8 +230,16 @@ ply_trigger_pull (ply_trigger_t *trigger,
|
|||
closure = (ply_trigger_closure_t *) ply_list_node_get_data (node);
|
||||
|
||||
next_node = ply_list_get_next_node (trigger->closures, node);
|
||||
|
||||
closure->handler (closure->user_data, data, trigger);
|
||||
switch (closure->handler_type) {
|
||||
case PLY_TRIGGER_HANDLER_TYPE_HANDLER:
|
||||
closure->handler (closure->user_data, data, trigger);
|
||||
break;
|
||||
case PLY_TRIGGER_HANDLER_TYPE_INSTANCE_HANDLER:
|
||||
closure->instance_handler (closure->user_data, trigger->instance, data, trigger);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
node = next_node;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ typedef struct _ply_trigger ply_trigger_t;
|
|||
typedef void (*ply_trigger_handler_t) (void *user_data,
|
||||
const void *trigger_data,
|
||||
ply_trigger_t *trigger);
|
||||
|
||||
typedef void (*ply_trigger_instance_handler_t) (void *user_data,
|
||||
void *instance,
|
||||
const void *trigger_data,
|
||||
ply_trigger_t *trigger);
|
||||
#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
|
||||
ply_trigger_t *ply_trigger_new (ply_trigger_t **free_address);
|
||||
|
||||
|
|
@ -42,6 +47,18 @@ void ply_trigger_add_handler (ply_trigger_t *trigger,
|
|||
void ply_trigger_remove_handler (ply_trigger_t *trigger,
|
||||
ply_trigger_handler_t handler,
|
||||
void *user_data);
|
||||
|
||||
void ply_trigger_set_instance (ply_trigger_t *trigger,
|
||||
void *instance);
|
||||
void *ply_trigger_get_instance (ply_trigger_t *trigger);
|
||||
|
||||
void ply_trigger_add_instance_handler (ply_trigger_t *trigger,
|
||||
ply_trigger_instance_handler_t handler,
|
||||
void *user_data);
|
||||
void ply_trigger_remove_instance_handler (ply_trigger_t *trigger,
|
||||
ply_trigger_instance_handler_t handler,
|
||||
void *user_data);
|
||||
|
||||
void ply_trigger_free (ply_trigger_t *trigger);
|
||||
|
||||
void ply_trigger_ignore_next_pull (ply_trigger_t *trigger);
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
#include "ply-array.h"
|
||||
#include "ply-buffer.h"
|
||||
#include "ply-event-loop.h"
|
||||
#include "ply-input-device.h"
|
||||
#include "ply-list.h"
|
||||
#include "ply-logger.h"
|
||||
#include "ply-hashtable.h"
|
||||
|
|
@ -94,6 +95,7 @@ struct _ply_renderer_input_source
|
|||
{
|
||||
ply_renderer_backend_t *backend;
|
||||
ply_fd_watch_t *terminal_input_watch;
|
||||
ply_list_t *input_devices;
|
||||
|
||||
ply_buffer_t *key_buffer;
|
||||
|
||||
|
|
@ -158,6 +160,7 @@ struct _ply_renderer_backend
|
|||
|
||||
uint32_t is_active : 1;
|
||||
uint32_t requires_explicit_flushing : 1;
|
||||
uint32_t input_source_is_open : 1;
|
||||
|
||||
int panel_width;
|
||||
int panel_height;
|
||||
|
|
@ -166,6 +169,8 @@ struct _ply_renderer_backend
|
|||
};
|
||||
|
||||
ply_renderer_plugin_interface_t *ply_renderer_backend_get_interface (void);
|
||||
|
||||
static bool using_input_device (ply_renderer_input_source_t *backend);
|
||||
static bool open_input_source (ply_renderer_backend_t *backend,
|
||||
ply_renderer_input_source_t *input_source);
|
||||
static void flush_head (ply_renderer_backend_t *backend,
|
||||
|
|
@ -884,6 +889,7 @@ create_backend (const char *device_name,
|
|||
backend->loop = ply_event_loop_get_default ();
|
||||
backend->heads = ply_list_new ();
|
||||
backend->input_source.key_buffer = ply_buffer_new ();
|
||||
backend->input_source.input_devices = ply_list_new ();
|
||||
backend->terminal = terminal;
|
||||
backend->requires_explicit_flushing = true;
|
||||
backend->output_buffers = ply_hashtable_new (ply_hashtable_direct_hash,
|
||||
|
|
@ -908,6 +914,7 @@ destroy_backend (ply_renderer_backend_t *backend)
|
|||
free (backend->device_name);
|
||||
ply_hashtable_free (backend->output_buffers);
|
||||
ply_hashtable_free (backend->heads_by_controller_id);
|
||||
ply_list_free (backend->input_source.input_devices);
|
||||
|
||||
free (backend->outputs);
|
||||
free (backend);
|
||||
|
|
@ -1236,14 +1243,12 @@ find_controller_for_output (ply_renderer_backend_t *backend,
|
|||
|
||||
if (!(possible_controllers & (1 << i)))
|
||||
continue; /* controller not usable for this connector */
|
||||
|
||||
for (j = 0; j < outputs_len; j++) {
|
||||
if (outputs[j].controller_id == controller_id)
|
||||
break;
|
||||
}
|
||||
if (j < outputs_len)
|
||||
continue; /* controller already in use */
|
||||
|
||||
return controller_id;
|
||||
}
|
||||
|
||||
|
|
@ -1744,9 +1749,18 @@ get_input_source (ply_renderer_backend_t *backend)
|
|||
}
|
||||
|
||||
static void
|
||||
on_key_event (ply_renderer_input_source_t *input_source,
|
||||
int terminal_fd)
|
||||
on_terminal_key_event (ply_renderer_input_source_t *input_source)
|
||||
{
|
||||
ply_renderer_backend_t *backend = input_source->backend;
|
||||
int terminal_fd;
|
||||
|
||||
if (using_input_device (input_source)) {
|
||||
ply_terminal_flush_input (backend->terminal);
|
||||
return;
|
||||
}
|
||||
|
||||
terminal_fd = ply_terminal_get_fd (backend->terminal);
|
||||
|
||||
ply_buffer_append_from_fd (input_source->key_buffer,
|
||||
terminal_fd);
|
||||
|
||||
|
|
@ -1754,6 +1768,34 @@ on_key_event (ply_renderer_input_source_t *input_source,
|
|||
input_source->handler (input_source->user_data, input_source->key_buffer, input_source);
|
||||
}
|
||||
|
||||
static void
|
||||
on_input_device_key (ply_renderer_input_source_t *input_source,
|
||||
ply_input_device_t *input_device,
|
||||
const char *text)
|
||||
{
|
||||
int len = strlen (text);
|
||||
if (len > 0)
|
||||
ply_buffer_append_bytes (input_source->key_buffer, text, len);
|
||||
|
||||
if (input_source->handler != NULL)
|
||||
input_source->handler (input_source->user_data, input_source->key_buffer, input_source);
|
||||
}
|
||||
|
||||
static void
|
||||
on_input_leds_changed (ply_renderer_input_source_t *input_source,
|
||||
ply_input_device_t *input_device)
|
||||
{
|
||||
ply_xkb_keyboard_state_t *state;
|
||||
ply_list_node_t *node;
|
||||
|
||||
state = ply_input_device_get_state (input_device);
|
||||
|
||||
ply_list_foreach (input_source->input_devices, node) {
|
||||
ply_input_device_t *set_input_device = ply_list_node_get_data (node);
|
||||
ply_input_device_set_state (set_input_device, state);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_input_source_disconnected (ply_renderer_input_source_t *input_source)
|
||||
{
|
||||
|
|
@ -1762,6 +1804,37 @@ on_input_source_disconnected (ply_renderer_input_source_t *input_source)
|
|||
open_input_source (input_source->backend, input_source);
|
||||
}
|
||||
|
||||
static bool
|
||||
using_input_device (ply_renderer_input_source_t *input_source)
|
||||
{
|
||||
return ply_list_get_length (input_source->input_devices) > 0;
|
||||
}
|
||||
|
||||
static void
|
||||
watch_input_device (ply_renderer_backend_t *backend,
|
||||
ply_input_device_t *input_device)
|
||||
{
|
||||
ply_trace ("Listening for keys from device '%s'", ply_input_device_get_name (input_device));
|
||||
|
||||
ply_input_device_watch_for_input (input_device,
|
||||
(ply_input_device_input_handler_t) on_input_device_key,
|
||||
(ply_input_device_leds_changed_handler_t) on_input_leds_changed,
|
||||
&backend->input_source);
|
||||
}
|
||||
|
||||
static void
|
||||
watch_input_devices (ply_renderer_backend_t *backend)
|
||||
{
|
||||
ply_list_node_t *node;
|
||||
ply_renderer_input_source_t *input_source = &backend->input_source;
|
||||
|
||||
ply_list_foreach (input_source->input_devices, node) {
|
||||
ply_input_device_t *input_device = ply_list_node_get_data (node);
|
||||
|
||||
watch_input_device (backend, input_device);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
open_input_source (ply_renderer_backend_t *backend,
|
||||
ply_renderer_input_source_t *input_source)
|
||||
|
|
@ -1771,16 +1844,24 @@ open_input_source (ply_renderer_backend_t *backend,
|
|||
assert (backend != NULL);
|
||||
assert (has_input_source (backend, input_source));
|
||||
|
||||
if (!backend->input_source_is_open)
|
||||
watch_input_devices (backend);
|
||||
|
||||
if (backend->terminal == NULL)
|
||||
return false;
|
||||
|
||||
terminal_fd = ply_terminal_get_fd (backend->terminal);
|
||||
if (backend->terminal != NULL) {
|
||||
terminal_fd = ply_terminal_get_fd (backend->terminal);
|
||||
|
||||
input_source->terminal_input_watch = ply_event_loop_watch_fd (backend->loop, terminal_fd, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
|
||||
(ply_event_handler_t) on_terminal_key_event,
|
||||
(ply_event_handler_t)
|
||||
on_input_source_disconnected, input_source);
|
||||
}
|
||||
|
||||
input_source->backend = backend;
|
||||
input_source->terminal_input_watch = ply_event_loop_watch_fd (backend->loop, terminal_fd, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
|
||||
(ply_event_handler_t) on_key_event,
|
||||
(ply_event_handler_t)
|
||||
on_input_source_disconnected, input_source);
|
||||
backend->input_source_is_open = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1804,12 +1885,28 @@ close_input_source (ply_renderer_backend_t *backend,
|
|||
assert (backend != NULL);
|
||||
assert (has_input_source (backend, input_source));
|
||||
|
||||
if (backend->terminal == NULL)
|
||||
if (!backend->input_source_is_open)
|
||||
return;
|
||||
|
||||
ply_event_loop_stop_watching_fd (backend->loop, input_source->terminal_input_watch);
|
||||
input_source->terminal_input_watch = NULL;
|
||||
if (using_input_device (input_source)) {
|
||||
ply_list_node_t *node;
|
||||
ply_list_foreach (input_source->input_devices, node) {
|
||||
ply_input_device_t *input_device = ply_list_node_get_data (node);
|
||||
ply_input_device_stop_watching_for_input (input_device,
|
||||
(ply_input_device_input_handler_t) on_input_device_key,
|
||||
(ply_input_device_leds_changed_handler_t) on_input_leds_changed,
|
||||
&backend->input_source);
|
||||
}
|
||||
}
|
||||
|
||||
if (input_source->terminal_input_watch != NULL) {
|
||||
ply_event_loop_stop_watching_fd (backend->loop, input_source->terminal_input_watch);
|
||||
input_source->terminal_input_watch = NULL;
|
||||
}
|
||||
|
||||
input_source->backend = NULL;
|
||||
|
||||
backend->input_source_is_open = false;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -1829,9 +1926,30 @@ get_panel_properties (ply_renderer_backend_t *backend,
|
|||
return true;
|
||||
}
|
||||
|
||||
static ply_input_device_t *
|
||||
get_any_input_device_with_leds (ply_renderer_backend_t *backend)
|
||||
{
|
||||
ply_list_node_t *node;
|
||||
|
||||
ply_list_foreach (backend->input_source.input_devices, node) {
|
||||
ply_input_device_t *input_device;
|
||||
|
||||
input_device = ply_list_node_get_data (node);
|
||||
|
||||
if (ply_input_device_is_keyboard_with_leds (input_device))
|
||||
return input_device;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
get_capslock_state (ply_renderer_backend_t *backend)
|
||||
{
|
||||
if (using_input_device (&backend->input_source)) {
|
||||
ply_input_device_t *dev = get_any_input_device_with_leds (backend);
|
||||
return ply_input_device_get_capslock_state (dev);
|
||||
}
|
||||
if (!backend->terminal)
|
||||
return false;
|
||||
|
||||
|
|
@ -1841,12 +1959,64 @@ get_capslock_state (ply_renderer_backend_t *backend)
|
|||
static const char *
|
||||
get_keymap (ply_renderer_backend_t *backend)
|
||||
{
|
||||
if (using_input_device (&backend->input_source)) {
|
||||
ply_input_device_t *dev = get_any_input_device_with_leds (backend);
|
||||
const char *keymap = ply_input_device_get_keymap (dev);
|
||||
if (keymap != NULL) {
|
||||
return keymap;
|
||||
}
|
||||
}
|
||||
if (!backend->terminal)
|
||||
return NULL;
|
||||
|
||||
return ply_terminal_get_keymap (backend->terminal);
|
||||
}
|
||||
|
||||
static void
|
||||
sync_input_devices (ply_renderer_backend_t *backend)
|
||||
{
|
||||
ply_list_node_t *node;
|
||||
ply_xkb_keyboard_state_t *xkb_state;
|
||||
ply_input_device_t *source_input_device;
|
||||
|
||||
source_input_device = get_any_input_device_with_leds (backend);
|
||||
|
||||
if (source_input_device == NULL)
|
||||
return;
|
||||
|
||||
xkb_state = ply_input_device_get_state (source_input_device);
|
||||
|
||||
ply_list_foreach (backend->input_source.input_devices, node) {
|
||||
ply_input_device_t *target_input_device = ply_list_node_get_data (node);
|
||||
|
||||
if (source_input_device == target_input_device)
|
||||
continue;
|
||||
|
||||
ply_input_device_set_state (target_input_device, xkb_state);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_input_device (ply_renderer_backend_t *backend,
|
||||
ply_input_device_t *input_device)
|
||||
{
|
||||
ply_list_append_data (backend->input_source.input_devices, input_device);
|
||||
|
||||
if (backend->input_source_is_open)
|
||||
watch_input_device (backend, input_device);
|
||||
|
||||
sync_input_devices (backend);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_input_device (ply_renderer_backend_t *backend,
|
||||
ply_input_device_t *input_device)
|
||||
{
|
||||
ply_list_remove_data (backend->input_source.input_devices, input_device);
|
||||
|
||||
sync_input_devices (backend);
|
||||
}
|
||||
|
||||
ply_renderer_plugin_interface_t *
|
||||
ply_renderer_backend_get_interface (void)
|
||||
{
|
||||
|
|
@ -1873,8 +2043,9 @@ ply_renderer_backend_get_interface (void)
|
|||
.get_panel_properties = get_panel_properties,
|
||||
.get_capslock_state = get_capslock_state,
|
||||
.get_keymap = get_keymap,
|
||||
.add_input_device = add_input_device,
|
||||
.remove_input_device = remove_input_device,
|
||||
};
|
||||
|
||||
return &plugin_interface;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
|
||||
#include "ply-buffer.h"
|
||||
#include "ply-event-loop.h"
|
||||
#include "ply-input-device.h"
|
||||
#include "ply-list.h"
|
||||
#include "ply-logger.h"
|
||||
#include "ply-rectangle.h"
|
||||
|
|
@ -71,6 +72,7 @@ struct _ply_renderer_input_source
|
|||
{
|
||||
ply_renderer_backend_t *backend;
|
||||
ply_fd_watch_t *terminal_input_watch;
|
||||
ply_list_t *input_devices;
|
||||
|
||||
ply_buffer_t *key_buffer;
|
||||
|
||||
|
|
@ -108,6 +110,7 @@ struct _ply_renderer_backend
|
|||
unsigned int row_stride;
|
||||
|
||||
uint32_t is_active : 1;
|
||||
uint32_t input_source_is_open : 1;
|
||||
|
||||
void (*flush_area) (ply_renderer_backend_t *backend,
|
||||
ply_renderer_head_t *head,
|
||||
|
|
@ -117,6 +120,7 @@ struct _ply_renderer_backend
|
|||
ply_renderer_plugin_interface_t *ply_renderer_backend_get_interface (void);
|
||||
static void ply_renderer_head_redraw (ply_renderer_backend_t *backend,
|
||||
ply_renderer_head_t *head);
|
||||
static bool using_input_device (ply_renderer_input_source_t *backend);
|
||||
static bool open_input_source (ply_renderer_backend_t *backend,
|
||||
ply_renderer_input_source_t *input_source);
|
||||
|
||||
|
|
@ -260,6 +264,7 @@ create_backend (const char *device_name,
|
|||
backend->head.map_address = MAP_FAILED;
|
||||
backend->heads = ply_list_new ();
|
||||
backend->input_source.key_buffer = ply_buffer_new ();
|
||||
backend->input_source.input_devices = ply_list_new ();
|
||||
backend->terminal = terminal;
|
||||
|
||||
return backend;
|
||||
|
|
@ -298,6 +303,7 @@ destroy_backend (ply_renderer_backend_t *backend)
|
|||
ply_trace ("destroying renderer backend for device %s",
|
||||
backend->device_name);
|
||||
free (backend->device_name);
|
||||
ply_list_free (backend->input_source.input_devices);
|
||||
uninitialize_head (backend, &backend->head);
|
||||
|
||||
ply_list_free (backend->heads);
|
||||
|
|
@ -651,9 +657,18 @@ get_input_source (ply_renderer_backend_t *backend)
|
|||
}
|
||||
|
||||
static void
|
||||
on_key_event (ply_renderer_input_source_t *input_source,
|
||||
int terminal_fd)
|
||||
on_terminal_key_event (ply_renderer_input_source_t *input_source)
|
||||
{
|
||||
ply_renderer_backend_t *backend = input_source->backend;
|
||||
int terminal_fd;
|
||||
|
||||
if (using_input_device (input_source)) {
|
||||
ply_terminal_flush_input (backend->terminal);
|
||||
return;
|
||||
}
|
||||
|
||||
terminal_fd = ply_terminal_get_fd (backend->terminal);
|
||||
|
||||
ply_buffer_append_from_fd (input_source->key_buffer,
|
||||
terminal_fd);
|
||||
|
||||
|
|
@ -661,6 +676,32 @@ on_key_event (ply_renderer_input_source_t *input_source,
|
|||
input_source->handler (input_source->user_data, input_source->key_buffer, input_source);
|
||||
}
|
||||
|
||||
static void
|
||||
on_input_device_key (ply_renderer_input_source_t *input_source,
|
||||
ply_input_device_t *input_device,
|
||||
const char *text)
|
||||
{
|
||||
ply_buffer_append_bytes (input_source->key_buffer, text, strlen (text));
|
||||
|
||||
if (input_source->handler != NULL)
|
||||
input_source->handler (input_source->user_data, input_source->key_buffer, input_source);
|
||||
}
|
||||
|
||||
static void
|
||||
on_input_leds_changed (ply_renderer_input_source_t *input_source,
|
||||
ply_input_device_t *input_device)
|
||||
{
|
||||
ply_xkb_keyboard_state_t *state;
|
||||
ply_list_node_t *node;
|
||||
|
||||
state = ply_input_device_get_state (input_device);
|
||||
|
||||
ply_list_foreach (input_source->input_devices, node) {
|
||||
ply_input_device_t *set_input_device = ply_list_node_get_data (node);
|
||||
ply_input_device_set_state (set_input_device, state);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_input_source_disconnected (ply_renderer_input_source_t *input_source)
|
||||
{
|
||||
|
|
@ -668,6 +709,37 @@ on_input_source_disconnected (ply_renderer_input_source_t *input_source)
|
|||
open_input_source (input_source->backend, input_source);
|
||||
}
|
||||
|
||||
static bool
|
||||
using_input_device (ply_renderer_input_source_t *input_source)
|
||||
{
|
||||
return ply_list_get_length (input_source->input_devices) > 0;
|
||||
}
|
||||
|
||||
static void
|
||||
watch_input_device (ply_renderer_backend_t *backend,
|
||||
ply_input_device_t *input_device)
|
||||
{
|
||||
ply_trace ("Listening for keys from device '%s'", ply_input_device_get_name (input_device));
|
||||
|
||||
ply_input_device_watch_for_input (input_device,
|
||||
(ply_input_device_input_handler_t) on_input_device_key,
|
||||
(ply_input_device_leds_changed_handler_t) on_input_leds_changed,
|
||||
&backend->input_source);
|
||||
}
|
||||
|
||||
static void
|
||||
watch_input_devices (ply_renderer_backend_t *backend)
|
||||
{
|
||||
ply_list_node_t *node;
|
||||
ply_renderer_input_source_t *input_source = &backend->input_source;
|
||||
|
||||
ply_list_foreach (input_source->input_devices, node) {
|
||||
ply_input_device_t *input_device = ply_list_node_get_data (node);
|
||||
|
||||
watch_input_device (backend, input_device);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
open_input_source (ply_renderer_backend_t *backend,
|
||||
ply_renderer_input_source_t *input_source)
|
||||
|
|
@ -677,16 +749,24 @@ open_input_source (ply_renderer_backend_t *backend,
|
|||
assert (backend != NULL);
|
||||
assert (has_input_source (backend, input_source));
|
||||
|
||||
if (!backend->input_source_is_open)
|
||||
watch_input_devices (backend);
|
||||
|
||||
if (backend->terminal == NULL)
|
||||
return false;
|
||||
|
||||
terminal_fd = ply_terminal_get_fd (backend->terminal);
|
||||
if (backend->terminal != NULL) {
|
||||
terminal_fd = ply_terminal_get_fd (backend->terminal);
|
||||
|
||||
input_source->terminal_input_watch = ply_event_loop_watch_fd (backend->loop, terminal_fd, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
|
||||
(ply_event_handler_t) on_terminal_key_event,
|
||||
(ply_event_handler_t)
|
||||
on_input_source_disconnected, input_source);
|
||||
}
|
||||
|
||||
input_source->backend = backend;
|
||||
input_source->terminal_input_watch = ply_event_loop_watch_fd (backend->loop, terminal_fd, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
|
||||
(ply_event_handler_t) on_key_event,
|
||||
(ply_event_handler_t) on_input_source_disconnected,
|
||||
input_source);
|
||||
backend->input_source_is_open = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -710,17 +790,54 @@ close_input_source (ply_renderer_backend_t *backend,
|
|||
assert (backend != NULL);
|
||||
assert (has_input_source (backend, input_source));
|
||||
|
||||
if (backend->terminal == NULL)
|
||||
if (!backend->input_source_is_open)
|
||||
return;
|
||||
|
||||
ply_event_loop_stop_watching_fd (backend->loop, input_source->terminal_input_watch);
|
||||
input_source->terminal_input_watch = NULL;
|
||||
if (using_input_device (input_source)) {
|
||||
ply_list_node_t *node;
|
||||
ply_list_foreach (input_source->input_devices, node) {
|
||||
ply_input_device_t *input_device = ply_list_node_get_data (node);
|
||||
ply_input_device_stop_watching_for_input (input_device,
|
||||
(ply_input_device_input_handler_t) on_input_device_key,
|
||||
(ply_input_device_leds_changed_handler_t) on_input_leds_changed,
|
||||
&backend->input_source);
|
||||
}
|
||||
}
|
||||
|
||||
if (input_source->terminal_input_watch != NULL) {
|
||||
ply_event_loop_stop_watching_fd (backend->loop, input_source->terminal_input_watch);
|
||||
input_source->terminal_input_watch = NULL;
|
||||
}
|
||||
|
||||
input_source->backend = NULL;
|
||||
|
||||
backend->input_source_is_open = false;
|
||||
}
|
||||
|
||||
static ply_input_device_t *
|
||||
get_any_input_device_with_leds (ply_renderer_backend_t *backend)
|
||||
{
|
||||
ply_list_node_t *node;
|
||||
|
||||
ply_list_foreach (backend->input_source.input_devices, node) {
|
||||
ply_input_device_t *input_device;
|
||||
|
||||
input_device = ply_list_node_get_data (node);
|
||||
|
||||
if (ply_input_device_is_keyboard_with_leds (input_device))
|
||||
return input_device;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
get_capslock_state (ply_renderer_backend_t *backend)
|
||||
{
|
||||
if (using_input_device (&backend->input_source)) {
|
||||
ply_input_device_t *dev = get_any_input_device_with_leds (backend);
|
||||
return ply_input_device_get_capslock_state (dev);
|
||||
}
|
||||
if (!backend->terminal)
|
||||
return false;
|
||||
|
||||
|
|
@ -730,12 +847,64 @@ get_capslock_state (ply_renderer_backend_t *backend)
|
|||
static const char *
|
||||
get_keymap (ply_renderer_backend_t *backend)
|
||||
{
|
||||
if (using_input_device (&backend->input_source)) {
|
||||
ply_input_device_t *dev = get_any_input_device_with_leds (backend);
|
||||
const char *keymap = ply_input_device_get_keymap (dev);
|
||||
if (keymap != NULL) {
|
||||
return keymap;
|
||||
}
|
||||
}
|
||||
if (!backend->terminal)
|
||||
return NULL;
|
||||
|
||||
return ply_terminal_get_keymap (backend->terminal);
|
||||
}
|
||||
|
||||
static void
|
||||
sync_input_devices (ply_renderer_backend_t *backend)
|
||||
{
|
||||
ply_list_node_t *node;
|
||||
ply_xkb_keyboard_state_t *xkb_state;
|
||||
ply_input_device_t *source_input_device;
|
||||
|
||||
source_input_device = get_any_input_device_with_leds (backend);
|
||||
|
||||
if (source_input_device == NULL)
|
||||
return;
|
||||
|
||||
xkb_state = ply_input_device_get_state (source_input_device);
|
||||
|
||||
ply_list_foreach (backend->input_source.input_devices, node) {
|
||||
ply_input_device_t *target_input_device = ply_list_node_get_data (node);
|
||||
|
||||
if (source_input_device == target_input_device)
|
||||
continue;
|
||||
|
||||
ply_input_device_set_state (target_input_device, xkb_state);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_input_device (ply_renderer_backend_t *backend,
|
||||
ply_input_device_t *input_device)
|
||||
{
|
||||
ply_list_append_data (backend->input_source.input_devices, input_device);
|
||||
|
||||
if (backend->input_source_is_open)
|
||||
watch_input_device (backend, input_device);
|
||||
|
||||
sync_input_devices (backend);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_input_device (ply_renderer_backend_t *backend,
|
||||
ply_input_device_t *input_device)
|
||||
{
|
||||
ply_list_remove_data (backend->input_source.input_devices, input_device);
|
||||
|
||||
sync_input_devices (backend);
|
||||
}
|
||||
|
||||
ply_renderer_plugin_interface_t *
|
||||
ply_renderer_backend_get_interface (void)
|
||||
{
|
||||
|
|
@ -760,8 +929,9 @@ ply_renderer_backend_get_interface (void)
|
|||
.get_device_name = get_device_name,
|
||||
.get_capslock_state = get_capslock_state,
|
||||
.get_keymap = get_keymap,
|
||||
.add_input_device = add_input_device,
|
||||
.remove_input_device = remove_input_device,
|
||||
};
|
||||
|
||||
return &plugin_interface;
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 70 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 70 KiB |
Loading…
Add table
Reference in a new issue