Projects
openEuler:Mainline
libinput
Sign Up
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 2
View file
_service:tar_scm:libinput.spec
Changed
@@ -1,11 +1,10 @@ Name: libinput -Version: 1.19.2 -Release: 2 +Version: 1.22.1 +Release: 1 Summary: Input device management and event handling library License: MIT -URL: https://www.freedesktop.org/wiki/Software/libinput/ -Source0: https://www.freedesktop.org/software/libinput/libinput-%{version}.tar.xz -patch0001: 0001-evdev-strip-the-device-name-of-format-directives.patch +URL: https://gitlab.freedesktop.org/libinput/libinput/-/releases +Source0: https://gitlab.freedesktop.org/libinput/libinput/-/archive/%{version}/libinput-%{version}.tar.gz BuildRequires: gcc gcc-c++ python3-devel meson pkgconfig(libudev) pkgconfig(mtdev) pkgconfig(libevdev) pkgconfig(libwacom) @@ -84,6 +83,9 @@ %{_mandir}/man1/* %changelog +* Fri Feb 10 2023 Liu Yuntao <liuyuntao10@huawei.com> - 1.22.1-1 +- update to 1.22.1, and update upstream URL + * Tue Jun 7 2022 zhouwenpei <zhouwenpei1@h-partners.com> - 1.19.2-2 - fix CVE-2022-1215
View file
_service:tar_scm:0001-evdev-strip-the-device-name-of-format-directives.patch
Deleted
@@ -1,355 +0,0 @@ -From 0fd73ca67649b359abc68ee7f6c6778c97681f76 Mon Sep 17 00:00:00 2001 -From: Peter Hutterer <peter.hutterer@who-t.net> -Date: Wed, 30 Mar 2022 09:25:22 +1000 -Subject: PATCH evdev: strip the device name of format directives -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This fixes a format string vulnerabilty. - -evdev_log_message() composes a format string consisting of a fixed -prefix (including the rendered device name) and the passed-in format -buffer. This format string is then passed with the arguments to the -actual log handler, which usually and eventually ends up being printf. - -If the device name contains a printf-style format directive, these ended -up in the format string and thus get interpreted correctly, e.g. for a -device "Foo%sBar" the log message vs printf invocation ends up being: - evdev_log_message(device, "some message %s", "some argument"); - printf("event9 - Foo%sBar: some message %s", "some argument"); - -This can enable an attacker to execute malicious code with the -privileges of the process using libinput. - -To exploit this, an attacker needs to be able to create a kernel device -with a malicious name, e.g. through /dev/uinput or a Bluetooth device. - -To fix this, convert any potential format directives in the device name -by duplicating percentages. - -Pre-rendering the device to avoid the issue altogether would be nicer -but the current log level hooks do not easily allow for this. The device -name is the only user-controlled part of the format string. - -A second potential issue is the sysname of the device which is also -sanitized. - -This issue was found by Albin Eldstål-Ahrens and Benjamin Svensson from -Assured AB. - -Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> ---- - meson.build | 1 + - src/evdev.c | 31 +++++++++++------ - src/evdev.h | 6 ++-- - src/util-strings.h | 30 ++++++++++++++++ - test/litest-device-format-string.c | 56 ++++++++++++++++++++++++++++++ - test/litest.h | 1 + - test/test-utils.c | 26 ++++++++++++++ - 7 files changed, 139 insertions(+), 12 deletions(-) - create mode 100644 test/litest-device-format-string.c - -diff --git meson.build meson.build -index 97649e57..1407aac5 100644 ---- meson.build -+++ meson.build -@@ -734,6 +734,7 @@ if get_option('tests') - 'test/litest-device-dell-canvas-totem-touch.c', - 'test/litest-device-elantech-touchpad.c', - 'test/litest-device-elan-tablet.c', -+ 'test/litest-device-format-string.c', - 'test/litest-device-generic-pressurepad.c', - 'test/litest-device-generic-singletouch.c', - 'test/litest-device-gpio-keys.c', -diff --git src/evdev.c src/evdev.c -index d0090c86..3c31b59a 100644 ---- src/evdev.c -+++ src/evdev.c -@@ -2384,19 +2384,19 @@ evdev_device_create(struct libinput_seat *seat, - struct libinput *libinput = seat->libinput; - struct evdev_device *device = NULL; - int rc; -- int fd; -+ int fd = -1; - int unhandled_device = 0; - const char *devnode = udev_device_get_devnode(udev_device); -- const char *sysname = udev_device_get_sysname(udev_device); -+ char *sysname = str_sanitize(udev_device_get_sysname(udev_device)); - - if (!devnode) { - log_info(libinput, "%s: no device node associated\n", sysname); -- return NULL; -+ goto err; - } - - if (udev_device_should_be_ignored(udev_device)) { - log_debug(libinput, "%s: device is ignored\n", sysname); -- return NULL; -+ goto err; - } - - /* Use non-blocking mode so that we can loop on read on -@@ -2410,13 +2410,15 @@ evdev_device_create(struct libinput_seat *seat, - sysname, - devnode, - strerror(-fd)); -- return NULL; -+ goto err; - } - - if (!evdev_device_have_same_syspath(udev_device, fd)) - goto err; - - device = zalloc(sizeof *device); -+ device->sysname = sysname; -+ sysname = NULL; - - libinput_device_init(&device->base, seat); - libinput_seat_ref(seat); -@@ -2439,6 +2441,9 @@ evdev_device_create(struct libinput_seat *seat, - device->dispatch = NULL; - device->fd = fd; - device->devname = libevdev_get_name(device->evdev); -+ /* the log_prefix_name is used as part of a printf format string and -+ * must not contain % directives, see evdev_log_msg */ -+ device->log_prefix_name = str_sanitize(device->devname); - device->scroll.threshold = 5.0; /* Default may be overridden */ - device->scroll.direction_lock_threshold = 5.0; /* Default may be overridden */ - device->scroll.direction = 0; -@@ -2479,12 +2484,16 @@ evdev_device_create(struct libinput_seat *seat, - return device; - - err: -- close_restricted(libinput, fd); -- if (device) { -- unhandled_device = device->seat_caps == 0; -- evdev_device_destroy(device); -+ if (fd >= 0) { -+ close_restricted(libinput, fd); -+ if (device) { -+ unhandled_device = device->seat_caps == 0; -+ evdev_device_destroy(device); -+ } - } - -+ free(sysname); -+ - return unhandled_device ? EVDEV_UNHANDLED_DEVICE : NULL; - } - -@@ -2497,7 +2506,7 @@ evdev_device_get_output(struct evdev_device *device) - const char * - evdev_device_get_sysname(struct evdev_device *device) - { -- return udev_device_get_sysname(device->udev_device); -+ return device->sysname; - } - - const char * -@@ -3094,6 +3103,8 @@ evdev_device_destroy(struct evdev_device *device) - if (device->base.group) - libinput_device_group_unref(device->base.group); - -+ free(device->log_prefix_name); -+ free(device->sysname); - free(device->output_name); - filter_destroy(device->pointer.filter); - libinput_timer_destroy(&device->scroll.timer); -diff --git src/evdev.h src/evdev.h -index c7d130f8..980c5943 100644 ---- src/evdev.h -+++ src/evdev.h -@@ -169,6 +169,8 @@ struct evdev_device { - struct udev_device *udev_device; - char *output_name; - const char *devname; -+ char *log_prefix_name; -+ char *sysname; - bool was_removed; - int fd; - enum evdev_device_seat_capability seat_caps; -@@ -786,7 +788,7 @@ evdev_log_msg(struct evdev_device *device, - sizeof(buf), - "%-7s - %s%s%s", - evdev_device_get_sysname(device), -- (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? device->devname : "", -+ (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? device->log_prefix_name : "", - (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? ": " : "", - format); - -@@ -824,7 +826,7 @@ evdev_log_msg_ratelimit(struct evdev_device *device, - sizeof(buf), - "%-7s - %s%s%s", - evdev_device_get_sysname(device), -- (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? device->devname : "", -+ (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? device->log_prefix_name : "", - (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? ": " : "", - format); - -diff --git src/util-strings.h src/util-strings.h -index 2a15fab3..d5a84146 100644 ---- src/util-strings.h -+++ src/util-strings.h -@@ -43,6 +43,8 @@ - #include <xlocale.h> - #endif - -+#include "util-macros.h" -+
View file
_service
Changed
@@ -2,7 +2,7 @@ <service name="tar_scm"> <param name="scm">git</param> <param name="url">git@gitee.com:src-openeuler/libinput.git</param> - <param name="revision">f62e4208b5ed7425141ff7a9dc290ec5151ced2f</param> + <param name="revision">master</param> <param name="exclude">*</param> <param name="extract">*</param> </service>
View file
_service:tar_scm:libinput-1.14.1-vs-1.15.6.yaml
Deleted
@@ -1,45 +0,0 @@ -name: libinput -old_version: 1.14.1 -new_version: 1.15.6 -interface_differences: -- type: 'feature' - item: 添加HP Elite x2 1013 G3 - diff: 将HP Elite x2 1013 G3键盘标记为外部键盘 - influence: 功能增强 -- type: 'feature' - item: markdown - diff: 删除markdown源码解析器,废弃此功能 - influence: 功能优化 -- type: 'feature' - item: 增加Lenovo ThinkPad X200 Tablet - diff: 为quirk模式添加Lenovo ThinkPad X200 Tablet - influence: 功能增强 -- type: 'feature' - item: 使用qemu - diff: 添加使用qemu运行完整的测试套件的支持,允许失败,至少可以利用它 - influence: 功能增强 -- type: 'feature' - item: 添加滚动按钮 - diff: 添加滚动按钮锁定功能 - influence: 功能增强 -- type: 'feature' - item: 在quirks模式添加RollerMouse Free 3 - diff: 添加RollerMouse Free 3进行双击修复 - influence: 功能增强 -- type: 'feature' - item: 从libinput - diff: 删除特定的libinput度量工具 - influence: 功能优化 -- type: 'feature' - item: tools - diff: 只要笔尖在逻辑上向下,就会显示一个额外的正方形。 - influence: 功能增强 -- type: 'ABI' - item: tablet - diff: 添加一个tablet_get_current_tool,用于获取当前工具 - influence: 功能增强 -- type: 'ABI' - item: touchpad - diff: 添加一个tp_tap_move_to_dead,用于控制移动后不允许多手指点击 - influence: 功能增强 -remark: '新增函数和特性,对老特性无影响,libinput为触摸屏基础库,被图形桌面引入,无相关产品使用,影响小;' \ No newline at end of file
View file
_service:tar_scm:libinput-1.19.2.tar.xz/.gitlab-ci/meson-junit-report.py
Deleted
@@ -1,117 +0,0 @@ -#!/usr/bin/env python3 -# -# meson-junit-report.py: Turns a Meson test log into a JUnit report -# -# Copyright 2019 GNOME Foundation -# -# SPDX-License-Identifier: LGPL-2.1-or-later - -import argparse -import datetime -import json -import sys -import xml.etree.ElementTree as ET - -aparser = argparse.ArgumentParser( - description="Turns a Meson test log into a JUnit report" -) -aparser.add_argument( - "--project-name", metavar="NAME", help="The project name", default="unknown" -) -aparser.add_argument( - "--job-id", metavar="ID", help="The job ID for the report", default="Unknown" -) -aparser.add_argument( - "--branch", - metavar="NAME", - help="Branch of the project being tested", - default="main", -) -aparser.add_argument( - "--output", - metavar="FILE", - help="The output file, stdout by default", - type=argparse.FileType("w", encoding="UTF-8"), - default=sys.stdout, -) -aparser.add_argument( - "infile", - metavar="FILE", - help="The input testlog.json, stdin by default", - type=argparse.FileType("r", encoding="UTF-8"), - default=sys.stdin, -) - -args = aparser.parse_args() - -outfile = args.output - -testsuites = ET.Element("testsuites") -testsuites.set("id", "{}/{}".format(args.job_id, args.branch)) -testsuites.set("package", args.project_name) -testsuites.set("timestamp", datetime.datetime.utcnow().isoformat(timespec="minutes")) - -suites = {} -for line in args.infile: - data = json.loads(line) - (full_suite, unit_name) = data"name".split(" / ") - (project_name, suite_name) = full_suite.split(":") - - duration = data"duration" - return_code = data"returncode" - log = data"stdout" - - unit = { - "suite": suite_name, - "name": unit_name, - "duration": duration, - "returncode": return_code, - "stdout": log, - } - - units = suites.setdefault(suite_name, ) - units.append(unit) - -for name, units in suites.items(): - print("Processing suite {} (units: {})".format(name, len(units))) - - def if_failed(unit): - if unit"returncode" != 0: - return True - return False - - def if_succeded(unit): - if unit"returncode" == 0: - return True - return False - - successes = list(filter(if_succeded, units)) - failures = list(filter(if_failed, units)) - print(" - {}: {} pass, {} fail".format(name, len(successes), len(failures))) - - testsuite = ET.SubElement(testsuites, "testsuite") - testsuite.set("name", "{}/{}".format(args.project_name, name)) - testsuite.set("tests", str(len(units))) - testsuite.set("errors", str(len(failures))) - testsuite.set("failures", str(len(failures))) - - for unit in successes: - testcase = ET.SubElement(testsuite, "testcase") - testcase.set("classname", "{}/{}".format(args.project_name, unit"suite")) - testcase.set("name", unit"name") - testcase.set("time", str(unit"duration")) - - for unit in failures: - testcase = ET.SubElement(testsuite, "testcase") - testcase.set("classname", "{}/{}".format(args.project_name, unit"suite")) - testcase.set("name", unit"name") - testcase.set("time", str(unit"duration")) - - failure = ET.SubElement(testcase, "failure") - failure.set("classname", "{}/{}".format(args.project_name, unit"suite")) - failure.set("name", unit"name") - failure.set("type", "error") - failure.text = unit"stdout" - -output = ET.tostring(testsuites, encoding="unicode") -outfile.write(output)
View file
_service:tar_scm:libinput-1.19.2.tar.xz/quirks/10-generic-lid.quirks
Deleted
@@ -1,11 +0,0 @@ -# Do not edit this file, it will be overwritten on update - -Lid Switch Ct9 -MatchName=*Lid Switch* -MatchDMIModalias=dmi:*:ct9:* -AttrLidSwitchReliability=reliable - -Lid Switch Ct10 -MatchName=*Lid Switch* -MatchDMIModalias=dmi:*:ct10:* -AttrLidSwitchReliability=reliable
View file
_service:tar_scm:libinput-1.19.2.tar.xz/quirks/30-vendor-starlabs.quirks
Deleted
@@ -1,41 +0,0 @@ -StarBook Mk V -MatchName=STAR0001:00 093A:0255 Touchpad -MatchUdevType=touchpad -MatchDMIModalias=dmi:*svnStarLabs:pnStarBook* -AttrEventCodeDisable=BTN_RIGHT - -StarLabTop Mk IV - coreboot firmware -MatchName=STAR0001:00 093A:1336 Touchpad -MatchUdevType=touchpad -MatchDMIModalias=dmi:*svnStarLabs:pnLabTop* -AttrEventCodeDisable=BTN_RIGHT - -StarLabTop Mk IV - AMI firmware -MatchName=PCT1336:00 093A:1336 Touchpad -MatchUdevType=touchpad -MatchDMIModalias=dmi:*svnStarLabs:pnLabTop* -AttrEventCodeDisable=BTN_RIGHT - -StarLite Mk III - coreboot firmware -MatchName=STAR0001:00 093A:0255 Touchpad -MatchUdevType=touchpad -MatchDMIModalias=dmi:*svnStarLabs:pnLite* -AttrEventCodeDisable=BTN_RIGHT - -StarLite Mk III - AMI firmware -MatchName=HTIX5288:00 093A:0255 Touchpad -MatchUdevType=touchpad -MatchDMIModalias=dmi:*svnStarLabs:pnLite* -AttrEventCodeDisable=BTN_RIGHT - -StarLite Mk II - coreboot firmware -MatchName=STAR0001:00 0911:5288 Touchpad -MatchUdevType=touchpad -MatchDMIModalias=dmi:*svnStarLabs:pnLite* -AttrEventCodeDisable=BTN_RIGHT - -StarLite Mk II - AMI firmware -MatchName=ALPS0001:00 0911:5288 Touchpad -MatchUdevType=touchpad -MatchDMIModalias=dmi:*svnStarLabs:pnLite* -AttrEventCodeDisable=BTN_RIGHT
View file
_service:tar_scm:libinput-1.19.2.tar.xz/quirks/50-system-prestigio.quirks
Deleted
@@ -1,7 +0,0 @@ -# Clickpad that announces BTN_RIGHT -# https://gitlab.freedesktop.org/libinput/libinput/-/issues/674 -Prestigio Smartbook 141 C2 Touchpad -MatchName=SYNA3602:00 0911:5288 Touchpad -MatchUdevType=touchpad -MatchDMIModalias=dmi:*svnPrestigio:*pnPSB141C02* -AttrEventCodeDisable=BTN_RIGHT
View file
_service:tar_scm:libinput-1.19.2.tar.xz/quirks/50-system-purism.quirks
Deleted
@@ -1,7 +0,0 @@ -# Clickpad that announces BTN_RIGHT -# https://gitlab.freedesktop.org/libinput/libinput/-/issues/629 -Librem 14v1 Touchpad -MatchName=HTIX5288:00 0911:5288 Touchpad -MatchUdevType=touchpad -MatchDMIModalias=dmi:*svnPurism:*pnLlibrem*14:* -AttrEventCodeDisable=BTN_RIGHT
View file
_service:tar_scm:libinput-1.22.1.tar.gz/.gitignore
Added
@@ -0,0 +1,12 @@ +*.swp +*~ +*.sig +*.tar.* +*.announce +*.patch +*.rej +*.trs +*.gcda +*.gcno +tags +*.gnuplot
View file
_service:tar_scm:libinput-1.19.2.tar.xz/.gitlab-ci.yml -> _service:tar_scm:libinput-1.22.1.tar.gz/.gitlab-ci.yml
Changed
@@ -34,36 +34,25 @@ # <distribution>:<version>@activity: # e.g. fedora:31@build-default -.templates_sha: &template_sha 007f3e2fe2235328e77d3cd4ce007ab41cd9ce6c +.templates_sha: &template_sha 25459a8d343961918a7398e4b3c147e450926569 include: - # Alpine container builder template - project: 'freedesktop/ci-templates' ref: *template_sha - file: '/templates/alpine.yml' - # Arch container builder template - - project: 'freedesktop/ci-templates' - ref: *template_sha - file: '/templates/arch.yml' - # Debian container builder template - - project: 'freedesktop/ci-templates' - ref: *template_sha - file: '/templates/debian.yml' - # Fedora container builder template - - project: 'freedesktop/ci-templates' - ref: *template_sha - file: '/templates/fedora.yml' - # Freebsd container builder template - - project: 'freedesktop/ci-templates' - ref: *template_sha - file: '/templates/freebsd.yml' - # Ubuntu container builder template - - project: 'freedesktop/ci-templates' - ref: *template_sha - file: '/templates/ubuntu.yml' - - project: 'freedesktop/ci-templates' - ref: *template_sha - file: '/templates/ci-fairy.yml' + file: + - '/templates/ci-fairy.yml' + # Alpine container builder template + - '/templates/alpine.yml' + # Arch container builder template + - '/templates/arch.yml' + # Debian container builder template + - '/templates/debian.yml' + # Fedora container builder template + - '/templates/fedora.yml' + # Freebsd container builder template + - '/templates/freebsd.yml' + # Ubuntu container builder template + - '/templates/ubuntu.yml' stages: - sanity check # CI/commit checks @@ -87,10 +76,10 @@ # See the documentation here: # # https://wayland.freedesktop.org/libinput/doc/latest/building_libinput.html # ############################################################################### - FEDORA_PACKAGES: 'git-core gcc gcc-c++ pkgconf-pkg-config meson check-devel libudev-devel libevdev-devel doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx_rtd_theme python3-pytest-xdist libwacom-devel cairo-devel gtk4-devel glib2-devel mtdev-devel diffutils valgrind' + FEDORA_PACKAGES: 'git-core gcc gcc-c++ pkgconf-pkg-config meson check-devel libudev-devel libevdev-devel doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx_rtd_theme python3-pytest-xdist libwacom-devel cairo-devel gtk4-devel glib2-devel mtdev-devel diffutils wayland-protocols-devel black clang-analyzer jq rpmdevtools valgrind systemd-udev qemu-img qemu-system-x86-core qemu-system-aarch64-core jq python3-click python3-rich' DEBIAN_PACKAGES: 'git gcc g++ pkg-config meson check libudev-dev libevdev-dev doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx-rtd-theme python3-pytest-xdist libwacom-dev libcairo2-dev libgtk-3-dev libglib2.0-dev libmtdev-dev curl' UBUNTU_PACKAGES: 'git gcc g++ pkg-config meson check libudev-dev libevdev-dev doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx-rtd-theme python3-pytest-xdist libwacom-dev libcairo2-dev libgtk-3-dev libglib2.0-dev libmtdev-dev' - ARCH_PACKAGES: 'git gcc pkgconfig meson check libsystemd libevdev doxygen graphviz python-sphinx python-recommonmark python-sphinx_rtd_theme python-pytest-xdist libwacom gtk4 mtdev diffutils' + ARCH_PACKAGES: 'git gcc pkgconfig meson check libsystemd libevdev doxygen graphviz python-sphinx python-recommonmark python-sphinx_rtd_theme python-pytest-xdist libwacom gtk4 mtdev diffutils wayland-protocols' ALPINE_PACKAGES: 'git gcc build-base pkgconfig meson check-dev eudev-dev libevdev-dev libwacom-dev cairo-dev gtk4.0-dev mtdev-dev bash' FREEBSD_PACKAGES: 'git pkgconf meson libepoll-shim libudev-devd libevdev libwacom gtk3 libmtdev bash wayland' ############################ end of package lists ############################# @@ -99,14 +88,12 @@ # changing these will force rebuilding the associated image # Note: these tags have no meaning and are not tied to a particular # libinput version - FEDORA_TAG: '2021-07-30.0' - DEBIAN_TAG: '2021-07-30.0' - UBUNTU_TAG: '2021-07-30.0' - ARCH_TAG: '2021-07-30.0' - ALPINE_TAG: '2021-07-30.0' - FREEBSD_TAG: '2021-07-30.0' - FEDORA_QEMU_TAG: 'fedora-qemu-vm-2021-07-30.0' - FREEBSD_QEMU_TAG: 'freebsd-qemu-vm-2021-07-30.0' + FEDORA_TAG: '2022-11-16.2' + DEBIAN_TAG: '2022-11-16.2' + UBUNTU_TAG: '2022-11-16.2' + ARCH_TAG: '2022-11-16.2' + ALPINE_TAG: '2022-11-16.2' + FREEBSD_TAG: '2022-11-16.2' FDO_UPSTREAM_REPO: libinput/libinput @@ -137,7 +124,7 @@ paths: - $MESON_BUILDDIR/meson-logs reports: - junit: $MESON_BUILDDIR/junit-*.xml + junit: $MESON_BUILDDIR/*junit*.xml ################################################################# @@ -146,6 +133,20 @@ # # ################################################################# +fail-if-fork-is-not-public: + stage: sanity check + script: + - | + if $CI_PROJECT_VISIBILITY != "public" ; then + echo "*************************************************************************************" + echo "Project visibility must be set to 'public'" + echo "Change this in $CI_PROJECT_URL/edit under 'Visibility, project features, permissions'" + echo "*************************************************************************************" + exit 1 + fi + except: + - main@libinput/libinput + # Re-generate the CI script and make sure it's the one currently checked in # If this job fails, re-generate the gitlab-ci.yml script, see # $SRCDIR/.gitlab-ci/generate-gitlab-ci.py @@ -195,52 +196,25 @@ # Note: images are rebuilt weekly with a scheduled pipeline with FDO_FORCE_REBUILD set # # -fedora:34@qemu-prep: - extends: - - .fdo.qemu-build@fedora - - .policy - stage: prep - tags: - - kvm - variables: - GIT_STRATEGY: none - FDO_DISTRIBUTION_VERSION: "34" - FDO_DISTRIBUTION_TAG: $FEDORA_QEMU_TAG - FDO_DISTRIBUTION_PACKAGES: $FEDORA_PACKAGES - -freebsd:13.0@qemu-prep: - extends: - - .fdo.qemu-build@freebsd - - .policy - stage: prep - tags: - - kvm - variables: - GIT_STRATEGY: none - FDO_DISTRIBUTION_VERSION: "13.0" - FDO_DISTRIBUTION_TAG: $FREEBSD_QEMU_TAG - FDO_DISTRIBUTION_PACKAGES: $FREEBSD_PACKAGES - - -fedora:33@container-prep: +fedora:35@container-prep: extends: - .fdo.container-build@fedora - .policy stage: prep variables: GIT_STRATEGY: none - FDO_DISTRIBUTION_VERSION: '33' + FDO_DISTRIBUTION_VERSION: '35' FDO_DISTRIBUTION_PACKAGES: $FEDORA_PACKAGES FDO_DISTRIBUTION_TAG: $FEDORA_TAG -fedora:34@container-prep: +fedora:36@container-prep: extends: - .fdo.container-build@fedora - .policy stage: prep variables: GIT_STRATEGY: none - FDO_DISTRIBUTION_VERSION: '34' + FDO_DISTRIBUTION_VERSION: '36' FDO_DISTRIBUTION_PACKAGES: $FEDORA_PACKAGES FDO_DISTRIBUTION_TAG: $FEDORA_TAG @@ -255,25 +229,14 @@ FDO_DISTRIBUTION_PACKAGES: $DEBIAN_PACKAGES FDO_DISTRIBUTION_TAG: $DEBIAN_TAG -ubuntu:20.10@container-prep: +ubuntu:22.04@container-prep: extends: - .fdo.container-build@ubuntu - .policy stage: prep variables: GIT_STRATEGY: none - FDO_DISTRIBUTION_VERSION: '20.10' - FDO_DISTRIBUTION_PACKAGES: $UBUNTU_PACKAGES - FDO_DISTRIBUTION_TAG: $UBUNTU_TAG - -ubuntu:21.04@container-prep: - extends: - - .fdo.container-build@ubuntu - - .policy - stage: prep - variables: - GIT_STRATEGY: none - FDO_DISTRIBUTION_VERSION: '21.04' + FDO_DISTRIBUTION_VERSION: '22.04' FDO_DISTRIBUTION_PACKAGES: $UBUNTU_PACKAGES FDO_DISTRIBUTION_TAG: $UBUNTU_TAG
View file
_service:tar_scm:libinput-1.19.2.tar.xz/.gitlab-ci/ci.template -> _service:tar_scm:libinput-1.22.1.tar.gz/.gitlab-ci/ci.template
Changed
@@ -36,18 +36,17 @@ # <distribution>:<version>@activity: # e.g. fedora:31@build-default -.templates_sha: &template_sha 007f3e2fe2235328e77d3cd4ce007ab41cd9ce6c +.templates_sha: &template_sha 25459a8d343961918a7398e4b3c147e450926569 include: - {% for distro in distributions|sort(attribute="name") %} - # {{ distro.name.capitalize() }} container builder template - project: 'freedesktop/ci-templates' ref: *template_sha - file: '/templates/{{distro.name}}.yml' + file: + - '/templates/ci-fairy.yml' + {% for distro in distributions|sort(attribute="name") %} + # {{ distro.name.capitalize() }} container builder template + - '/templates/{{distro.name}}.yml' {% endfor %} - - project: 'freedesktop/ci-templates' - ref: *template_sha - file: '/templates/ci-fairy.yml' stages: - sanity check # CI/commit checks @@ -83,11 +82,6 @@ {% for distro in distributions %} {{"%-13s"| format(distro.name.upper() + '_TAG:')}}'{{distro.tag}}' {% endfor %} -{% for distro in distributions %} -{% if distro.want_qemu %} - {{"%-20s"| format(distro.name.upper() + '_QEMU_TAG:')}} '{{distro.name}}-qemu-vm-{{distro.tag}}' -{% endif %} -{% endfor %} FDO_UPSTREAM_REPO: libinput/libinput @@ -118,7 +112,7 @@ paths: - $MESON_BUILDDIR/meson-logs reports: - junit: $MESON_BUILDDIR/junit-*.xml + junit: $MESON_BUILDDIR/*junit*.xml ################################################################# @@ -127,6 +121,20 @@ # # ################################################################# +fail-if-fork-is-not-public: + stage: sanity check + script: + - | + if $CI_PROJECT_VISIBILITY != "public" ; then + echo "*************************************************************************************" + echo "Project visibility must be set to 'public'" + echo "Change this in $CI_PROJECT_URL/edit under 'Visibility, project features, permissions'" + echo "*************************************************************************************" + exit 1 + fi + except: + - main@libinput/libinput + # Re-generate the CI script and make sure it's the one currently checked in # If this job fails, re-generate the gitlab-ci.yml script, see # $SRCDIR/.gitlab-ci/generate-gitlab-ci.py @@ -176,31 +184,20 @@ # Note: images are rebuilt weekly with a scheduled pipeline with FDO_FORCE_REBUILD set # # -{# qemu builds are only done for the latest version of any distribution #} -{% for distro in distributions if distro.want_qemu %} -{% set version = "{}".format(distro.versions|last()) %} -{{distro.name}}:{{version}}@qemu-prep: - extends: - - .fdo.qemu-build@{{distro.name}} - - .policy - stage: prep - tags: - - kvm - variables: - GIT_STRATEGY: none - FDO_DISTRIBUTION_VERSION: "{{version}}" - FDO_DISTRIBUTION_TAG: ${{distro.name.upper()}}_QEMU_TAG - FDO_DISTRIBUTION_PACKAGES: ${{distro.name.upper()}}_PACKAGES - -{% endfor %} - {% for distro in distributions %} -{% if not distro.skip_container %} {% for version in distro.versions %} {{distro.name}}:{{version}}@container-prep: extends: +{% if distro.qemu_based %} + - .fdo.qemu-build@{{distro.name}} +{% else %} - .fdo.container-build@{{distro.name}} +{% endif %} - .policy +{% if distro.qemu_based %} + tags: + - kvm +{% endif %} stage: prep variables: GIT_STRATEGY: none @@ -209,7 +206,6 @@ FDO_DISTRIBUTION_TAG: ${{distro.name.upper()}}_TAG {% endfor %} -{% endif %} {% endfor %} @@ -244,7 +240,6 @@ - schedules {% for distro in distributions %} -{% if not distro.skip_container %} {% for version in distro.versions %} {{distro.name}}:{{version}}@container-clean: extends: @@ -257,7 +252,6 @@ FDO_DISTRIBUTION_TAG: ${{distro.name.upper()}}_TAG {% endfor %} -{% endif %} {% endfor %} ################################################################# @@ -274,6 +268,31 @@ script: - .gitlab-ci/meson-build.sh + +# Run meson and meson test in the container image through qemu +.build-in-b2c@template: + extends: + - .policy + - .default_artifacts + tags: + - kvm + variables: + MESON_BUILDDIR: build_dir + B2C_KERNEL: {{ b2c.kernel }} + B2C_VERSION: {{ b2c.version }} + B2C_IMAGE: $FDO_DISTRIBUTION_IMAGE + B2C_COMMAND: .gitlab-ci/start-in-systemd.sh + script: + # first build in the host container + - .gitlab-ci/meson-build.sh --skip-test + + # pull b2c + - curl -L -o /app/boot2container https://gitlab.freedesktop.org/mupuf/boot2container/-/raw/{{b2c.version}}/vm2c.py + - chmod +x /app/boot2container + + # runs the test suite only + - /app/boot2container + # # Fedora # @@ -329,7 +348,7 @@ - $MESON_BUILDDIR/meson-logs - console.out reports: - junit: $MESON_BUILDDIR/junit-*.xml + junit: $MESON_BUILDDIR/*junit*.xml # Run in a test suite. Special variables: @@ -338,7 +357,7 @@ # Set one or the other, not both. .test-suite-vm: extends: - - .build-in-qemu@template + - .build-in-b2c@template stage: test-suite variables: # remove the global --no-suite=hardware @@ -347,23 +366,21 @@ - if ! -z $SUITE_NAMES ; then SUITES=$(echo $SUITE_NAMES | sed 's/\(^ *\)/libinput-test-suite-\1/g'); fi - echo "Testing $SUITES" - export MESON_TEST_ARGS="$MESON_TEST_ARGS $SUITES" - retry: - max: 2 - when: script_failure + - export LITEST_JOBS="2" {# qemu tests are only done for the latest version of any distribution #} -{% for distro in distributions if distro.want_qemu %} +{% for distro in distributions if distro.use_for_qemu_tests %} {% set version = "{}".format(distro.versions|last()) %} -{% if distro.use_for_custom_build_tests %} .{{distro.name}}:{{version}}@test-suite-vm: extends: + - .fdo.distribution-image@{{distro.name}} - .test-suite-vm
View file
_service:tar_scm:libinput-1.19.2.tar.xz/.gitlab-ci/config.yml -> _service:tar_scm:libinput-1.22.1.tar.gz/.gitlab-ci/config.yml
Changed
@@ -3,15 +3,14 @@ # # We're happy to rebuild all containers when one changes. -.default_tag: &default_tag '2021-07-30.0' +.default_tag: &default_tag '2022-11-16.2' distributions: - name: fedora tag: *default_tag versions: - - '33' - - '34' # last is picked for qemu - want_qemu: true + - '35' + - '36' use_for_custom_build_tests: true use_for_qemu_tests: true packages: @@ -35,7 +34,20 @@ - glib2-devel - mtdev-devel - diffutils + - wayland-protocols-devel + - black # for the Python black job, optional + - clang-analyzer # for the scan-build job, optional + - jq # for the test suite check job, optional + - rpmdevtools # for the rpm build job, optional - valgrind # for the valgrind run, optional + # below packages are for the qemu runs, so optional + - systemd-udev # for the qemu run + - qemu-img + - qemu-system-x86-core + - qemu-system-aarch64-core + - jq + - python3-click + - python3-rich - name: debian tag: *default_tag versions: @@ -64,8 +76,7 @@ - name: ubuntu tag: *default_tag versions: - - '20.10' - - '21.04' + - '22.04' packages: - git - gcc @@ -108,6 +119,7 @@ - gtk4 - mtdev - diffutils + - wayland-protocols - name: alpine tag: *default_tag versions: @@ -134,10 +146,9 @@ - "MESON_TEST_ARGS: '' # litest-selftest fails on musl" - name: freebsd tag: *default_tag - want_qemu: true - skip_container: true + qemu_based: true versions: - - '13.0' + - '13.1' packages: - git - pkgconf @@ -195,3 +206,7 @@ - name: pointer suites: - pointer + +b2c: + version: v0.9.8 + kernel: https://gitlab.freedesktop.org/api/v4/projects/libevdev%2Fhid-tools/packages/generic/kernel-x86_64/v5.19/bzImage
View file
_service:tar_scm:libinput-1.19.2.tar.xz/.gitlab-ci/libinput.spec.in -> _service:tar_scm:libinput-1.22.1.tar.gz/.gitlab-ci/libinput.spec.in
Changed
@@ -132,7 +132,10 @@ %{_mandir}/man1/libinput-analyze-touch-down-state.1* %files test +%{_libexecdir}/libinput/libinput-test %{_libexecdir}/libinput/libinput-test-suite +%{_libexecdir}/libinput/libinput-test-utils +%{_mandir}/man1/libinput-test.1* %{_mandir}/man1/libinput-test-suite.1* %changelog
View file
_service:tar_scm:libinput-1.19.2.tar.xz/.gitlab-ci/meson-build.sh -> _service:tar_scm:libinput-1.22.1.tar.gz/.gitlab-ci/meson-build.sh
Changed
@@ -5,6 +5,34 @@ . .meson_environment fi +# If test args are set, we assume we want to run the tests +MESON_RUN_TEST="$MESON_TEST_ARGS" + +while $# -gt 0 ; do + case $1 in + --skip-setup) + shift + MESON_SKIP_SETUP="1" + ;; + --skip-build) + shift + MESON_SKIP_BUILD="1" + ;; + --skip-test) + shift + MESON_RUN_TEST="" + ;; + --run-test) + shift + MESON_RUN_TEST="1" + ;; + *) + echo "Unknow commandline argument $1" + exit 1 + ;; + esac +done + if -z "$MESON_BUILDDIR" ; then echo "\$MESON_BUILDDIR undefined." exit 1 @@ -23,7 +51,7 @@ if -n "$FDO_CI_CONCURRENT" ; then NINJA_ARGS="-j$FDO_CI_CONCURRENT $NINJA_ARGS" - MESON_TESTTHREADS="$FDO_CI_CONCURRENT" + export MESON_TESTTHREADS="$FDO_CI_CONCURRENT" fi echo "*************************************************" @@ -35,27 +63,16 @@ set -e -rm -rf "$MESON_BUILDDIR" -meson "$MESON_BUILDDIR" $MESON_ARGS +if -z "$MESON_SKIP_SETUP" ; then + rm -rf "$MESON_BUILDDIR" + meson setup "$MESON_BUILDDIR" $MESON_ARGS +fi meson configure "$MESON_BUILDDIR" -ninja -C "$MESON_BUILDDIR" $NINJA_ARGS -if -z "$MESON_TEST_ARGS" ; then - exit 0 +if -z "$MESON_SKIP_BUILD" ; then + ninja -C "$MESON_BUILDDIR" $NINJA_ARGS fi -# we still want to generate the reports, even if meson test fails -set +e -meson test -C "$MESON_BUILDDIR" $MESON_TEST_ARGS --print-errorlogs -exit_code=$? -set -e - -# We need the glob for the testlog so that it picks up those suffixed by a -# suite (e.g. testlog-valgrind.json) -./.gitlab-ci/meson-junit-report.py \ - --project-name=libinput \ - --job-id="$CI_JOB_ID" \ - --output="$MESON_BUILDDIR/junit-$CI_JOB_NAME-report.xml" \ - "$MESON_BUILDDIR"/meson-logs/testlog*.json; \ - -exit $exit_code +if -n "$MESON_RUN_TEST" ; then + meson test -C "$MESON_BUILDDIR" $MESON_TEST_ARGS --print-errorlogs +fi
View file
_service:tar_scm:libinput-1.22.1.tar.gz/.gitlab-ci/meson-prep.sh
Added
@@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +set -x +if -f .meson_environment ; then + . .meson_environment +fi + +if -z "$MESON_BUILDDIR" ; then + echo "\$MESON_BUILDDIR undefined." + exit 1 +fi + +# emulate a few gitlab variables to make it easier to +# run and debug locally. +if -z "$CI_JOB_ID" || -z "$CI_JOB_NAME" ; then + echo "Missing \$CI_JOB_ID or \$CI_JOB_NAME". + CI_JOB_ID=$(date +%s) + CI_JOB_NAME='libinput-job-local' + echo "Simulating gitlab environment: " + echo " CI_JOB_ID=$CI_JOB_ID" + echo " CI_JOB_NAME=$CI_JOB_NAME" +fi + +if -n "$FDO_CI_CONCURRENT" ; then + NINJA_ARGS="-j$FDO_CI_CONCURRENT $NINJA_ARGS" + MESON_TESTTHREADS="$FDO_CI_CONCURRENT" +fi + +echo "*************************************************" +echo "builddir: $MESON_BUILDDIR" +echo "meson args: $MESON_ARGS" +echo "ninja args: $NINJA_ARGS" +echo "meson test args: $MESON_TEST_ARGS" +echo "*************************************************" + +set -e
View file
_service:tar_scm:libinput-1.22.1.tar.gz/.gitlab-ci/meson-test.sh
Added
@@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +DIR="${BASH_SOURCE%/*}" +if ! -d "$DIR" ; then DIR="$PWD"; fi +. $DIR/meson-prep.sh + +if -z "$MESON_TEST_ARGS" ; then + echo "\$MESON_TEST_ARGS undefined." + exit 1 +fi + +meson test -C "$MESON_BUILDDIR" $MESON_TEST_ARGS --print-errorlogs
View file
_service:tar_scm:libinput-1.22.1.tar.gz/.gitlab-ci/start-in-systemd.sh
Added
@@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +set -x + +systemd_target=basic.target +post_command="/usr/bin/systemctl exit \$EXIT_STATUS" + +while $# -gt 0 ; do + case $1 in + --debug-mode) + shift + systemd_target=multi-user.target + post_command="echo you can now log in as root (no password) and then turn off by running \'/usr/bin/systemctl exit \$EXIT_STATUS\'" + ;; + *) + echo "Unknow commandline argument $1" + exit 1 + ;; + esac +done + +WORKDIR=${FDO_DISTRIBUTION_WORKINGDIR:-$PWD} +B2C_WORKDIR=${FDO_B2C_WORKDIR:-/app} + +# remove root password for debugging +sed -i 's/root:!locked::/root:::/' /etc/shadow + +# create a libinput test suite service +cat <<EOF > /etc/systemd/system/libinput-testsuite.service + +Unit +Description=Libinput test suite +After=$systemd_target + +Service +Type=simple +StandardOutput=journal+console +EnvironmentFile=$B2C_WORKDIR/.b2c_env +WorkingDirectory=$WORKDIR +ExecStart=$WORKDIR/.gitlab-ci/meson-build.sh --skip-setup --skip-build + +# exit the container on termination +ExecStopPost=$post_command + +Install +WantedBy=default.target +EOF + +cat /etc/systemd/system/libinput-testsuite.service + +# enable the service +systemctl enable libinput-testsuite.service + +# disable some services we don't need in the CI +systemctl mask network-online.target +systemctl mask network-pre.target +systemctl mask timers.target +systemctl mask dnf-makecache.timer +systemctl mask systemd-logind.service +systemctl mask rpmdb-migrate.service +systemctl mask systemd-network-generator.service +systemctl mask cryptsetup-pre.target +systemctl mask cryptsetup.target + +#change default target +systemctl set-default $systemd_target + +# start the system +exec /usr/sbin/init
View file
_service:tar_scm:libinput-1.19.2.tar.xz/CODING_STYLE.md -> _service:tar_scm:libinput-1.22.1.tar.gz/CODING_STYLE.md
Changed
@@ -52,51 +52,102 @@ - if it generates a static checker warning, it needs to be fixed or commented -- declare variables at the top, try to keep them as local as possible. - Exception: if the same variable is re-used in multiple blocks, declare it - at the top. - Exception: basic loop variables, e.g. for (int i = 0; ...) +- declare variables when they are used first and try to keep them as local as possible. + Exception: basic loop variables, e.g. for (int i = 0; ...) should always be + declared inside the loop even where multiple loops exist ```c int a; -int c; if (foo) { - int b; + int b = 10; - c = get_value(); - usevalue(c); + a = get_value(); + usevalue(a, b); } if (bar) { - c = get_value(); - useit(c); + a = get_value(); + useit(a); } + +int c = a * 100; +useit(c); ``` -- do not mix function invocations and variable definitions. +- avoid uninitialized variables where possible, declare them late instead. + Note that most of libinput predates this style, try to stick with the code + around you if in doubt. wrong: ```c -{ - int a = foo(); + int *a; int b = 7; -} + + ... some code ... + + a = zalloc(32); ``` right: + ```c -{ - int a; int b = 7; + ... some code ... - a = foo(); + int *a = zalloc(32); +``` + +- avoid calling non-obvious functions inside declaration blocks for multiple + variables. + + bad: + +```c +{ + int a = 7; + int b = some_complicated_function(); + int *c = zalloc(32); } ``` - There are exceptions here, e.g. `tp_libinput_context()`, - `litest_current_device()` + better: +```c +{ + int a = 7; + int *c = zalloc(32); + + int b = some_complicated_function(); +} +``` + + There is a bit of gut-feeling involved with this, but the goal is to make + the variable values immediately recognizable. + +- Where statements are near-identical and repeated, try to keep them + identical: + + bad: +```c +int a = get_some_value(x++); +do_something(a); +a = get_some_value(x++); +do_something(a); +a = get_some_value(x++); +do_something(a); +``` + better: + +```c +int a; +a = = get_some_value(x++); +do_something(a); +a = get_some_value(x++); +do_something(a); +a = get_some_value(x++); +do_something(a); +``` - if/else: { on the same line, no curly braces if both blocks are a single statement. If either if or else block are multiple statements, both must
View file
_service:tar_scm:libinput-1.19.2.tar.xz/completion/zsh/_libinput -> _service:tar_scm:libinput-1.22.1.tar.gz/completion/zsh/_libinput
Changed
@@ -79,6 +79,9 @@ + '(dwt)' \ '--enable-dwtEnable disable-while-typing' \ '--disable-dwtDisable disable-while-typing' + + '(dwtp)' \ + '--enable-dwtpEnable disable-while-trackpointing' \ + '--disable-dwtpDisable disable-while-trackpointing' } (( $+functions_libinput_debug-gui )) || _libinput_debug-gui()
View file
_service:tar_scm:libinput-1.19.2.tar.xz/doc/touchpad-gestures-state-machine.svg -> _service:tar_scm:libinput-1.22.1.tar.gz/doc/touchpad-gestures-state-machine.svg
Changed
@@ -1,3 +1,4 @@ <?xml version="1.0" encoding="UTF-8"?> +<!-- Do not edit this file with editors other than diagrams.net --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="3549px" height="2249px" viewBox="-0.5 -0.5 3549 2249" content="<mxfile host="app.diagrams.net" modified="2021-06-08T15:46:29.683Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36" etag="dGoOzLxFj0Psxj0F8VP9" version="14.7.3" type="device"><diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">7V1bd6M4Ev41Oaf3ITlIIC6PubjT6Ukn2SQ9vbMvc7BNHO/YJmPjTmd+/QJGNqgEyAYk2Ul2z7SNAWNVfaW615F5Pv11Ofdfnr+Fw2ByhI3hryPz4ghjkxAS/5McecuOYM9dHRnNx8PVMbQ58DD+J8gOGtnR5XgYLAonRmE4icYvxYODcDYLBlHhmD+fh6/F057CSfFbX/xRAA48DPwJPPpjPIyes6MeNjYffAnGo2f61djIPpn69OzswOLZH4avuUNm78g8n4dhtHo1/XUeTJLlowvz4+rtx+T6L/vy678Xf/vfz357vPn9eHWzz9tcsv4N82AW7Xzry6eHf5+9fr2buZN/rozl1c00HGWXGD/9yTJbsJvbm172e6M3uorxnWKCxW/OXp/HUfDw4g+ST15jpomPPUfTSfwOxS+fxpPJeTgJ5+l15hNJ/hcfX0Tz8K8g94md/iVXhLMod3z1Fx8X/M3Z2vwM5lHwK0fybA0ug3AaRPO3+JTsU8fKfnPG0ZS6rznuoMeec4zhZsf8jCFH6ztv1jx+kS37FiQwAQng8s+GpwkW4neDib9YjAfFVQ9+jaP/xK+NE5K9+yP3yUXyyw365i17s936LsLlfBDUM1IwLMARUiG3zISzyvTYPJj40fhnEcS8pc++4S4cxz+jlMgmYqi3+j3ZVXnQMDdyjeKNkMXcKPLnoyACN0o5Yf2zd2cOCzDH56uby979nxe9x975Y+8C8EospV6Sl1H6Tx1eFyuBbZxg5m8vsWy6HDBbFWzWOpgRFKhv8fYHAB3D5CF7G86j53AUzvxJb3P0bB4uZ8NgmIF1c851GL5ktPtfEEVv2Y7rL6OwuUyIyTN/W11kmTY98Ed6ALn0/eba9F3h4rtgPo5XMph3I2UybWQFunrY1EqjhmKGlQ4WlisdiAO4bRaqZDaUY7UN49UyGymwWg2fKWIpIrrDNeSptWZK9RNPMk8BlroMFtFynkgxI5j5/UnCKJ8Bl82fw2l/uTgIFdFmSEDgtuLKVBFtNSqiHITWI08r1ZKV+ZiV+buqltiRC3S4dzRgKgsXRb9nV3NW/IZVFTTZDyxBrkSmVmzpeF5RFWG5SZQtwY1YqdYeW37t/YH/jr7c3t++/XfoL8lfvdHjsUmUKDCU+VCB9TacKIf5EEcm8lepdQ23mdlD99iNMPl+89vN7Y8bSMzDdSURm2N+SvUlIZ4zyfanydLO+ouXdDGMh5i9EsQ/J87UmNliMTwHdKJ+hEUUJJe95KR1cignvesJ+SugnuGczwEbkMhDErhDi0dkF/fNlMiyiLkWoHXE7M6XAJ0/B6T21ctCU3QnRnrtxC4jFXbdiV2TuZFk7wKGQv1bGI3DWXxsGEN/EL07S9DmCAWpliAVAe9VJojajFhvmWCzTp1dZYItOR6BoYLB9W8LsuBu/kKlKjoWdlvoFRKzSJFzPHNHFlzzbnYjR7KDEkO1iOf0FhWCW3BgR5x0aAziIIZB2OBr1wwCXdhfNpZOuIwAs7w3W4cwELZdAtQaubYObtPFvcumsqXfR0awE4uGprCjtSBxdxUkBCsWJNBF/uX2+uLPx6tvvdvvj6VipPXUC4WiwkICokJqioWFwMLrn06h0mjCrqAc0cypbJn6ENrYidBIU0JbWCtC0+dm5Cyk/o6hA4Xik1W0RJ3KnTmQqKhWBCoJqlnLoDKFXU6uVqCiz80qL2e9yysYlaOqS7xs/mQSTMLR3J8yplDhswY2kT7oxIRVbgThaXcFT7NN/+42YKtKyFALQKqF16svevtTXFamC5tBRo091Z4ZdO1//e4v/7ny3YERnUX3X91fF8eQJRWnNO+h15iq1nkm5i62rWoT4T4N9ParzS/eSX/Qj/J7oT9AN3un0V+FagBifBwugmqA1Cgv4Wz6uotXpZavKWr5ysriJ0zigMu6wzp2XZp8k/rP3k380p7ES3TWn8evRsmrT+enN+e9638BpnufVgHQt0RLRDuzCiwoi/3kqv3wjrWM9fadV3wII0Z/JwZzi65LP2EYc/9UL6W7AuWU2mxqS7TEJGONY+PEc0imHDdkM+ww4oYIJtyfzuf+W+60l+SERfkXscnKHtMuoPp0RFOYys7HHo0MlVwRv1g9MnM9ff7w6WkRNEXS8Ph8+T/v6beL5eT304ufL78F5uc1H+SQtIhvGh/5NAz6MUAGAdz7El649vvBpAgHfzIezeLXg5hF020u2VfGA39ymn0wHQ+HK+QFi/E/SblcxtwZfeKbk7MjcrFmd7AxrZthZBcfrUuM8siokBmVfLtu6UFrpptxcXaXY+aKVohZCep8Sfx4Nkoy2I3ly4FaJER1BaLl7Yu2savZLyOjw+K4MvkSq3UzpRn1SxIhUmviw2Y4AnE+y5JoMnBVGpoprb8LoWWMUUlZ7wrw2sZYiR2BmDQmhGyrEw0PGU7xm2jCVJnOBi5ABFXobG2VeGKliR17wZuSGpgA3vRcbVkTyWBNU4nYVMVmtixXCqvPWo6nKZvRJ+uWy5QIQGXCTNS7IkeZpc+d73m4nPZTAzJ8iv/zlJqTiwMvbWT7DCkvbXTUujdPXIdsoRlUdzDRz/QkomFoRy/Tk8DQB85hFHDMOkWU2qGDSbgcHgJgEWJqPzd7l4xsUr4m7+47ZtuGGadmh79yeuXaExhsMpP9MNkUrQ+8le6QcuGm2Al74DukJ7hD2q07jppB1wPQRWvEvmvAIssWrGvtDLH0ifajm5kMmFGfQ20MxGw9H3I3lwJia3jadUNxfzvM3voU0xgbSXP+/QtVVyCjMlSNPbuw8hnn7OqM6j42TXk7RzdCtahpOA9g6t2HXoWxZaqW0khNQEKPBHWbo/fwV6l1b3GzpshQ77m7vbp57N3/+e328eq2vMit/dEIT094MOChbGj3bdJppogJJlTIHILAZRTnHaPJ4XjFuYukrNCn8rFzYHo4v7+9vpYIIncQ8EHUd0lSTCcTRIbyNhdU93mfKBLt/enp5UZzYMHcw4+rOzhQq7tWMX7gPnFRZA/coP/UJYpsJpZKkKcaREr8022DQTR04+kVaHVg6Obu6ub8i0y9LLBL9DLH6xudbiksGFxLNRhcNb6oA8vhdURLDR3RARFNk2tsRnmxqWVU02igLa+HC70ei9dxDGVlfqraOgkKBWGHVinOjZPY4MoMnqaVQHbxiu78VO4etlDbZ0kgK5uTlQSOJVkSQPX3ZTwbPOssCcp29q0lwbFxYiCr6LG2WhEMNBJSvGn3YsKBYYhsFhx0ZEdvie520BlzyBLo5tZVyhzfh/Se/daesKdNL7+1x3G1cX0EO7c7VOgC8BiIEMMCEJEb26HK8PvECBbFiF7Nh+hz17oOdp4mptAzwGLENSVihL/cSiI2bfO6sJtMrwxnD7rJ0v1Aw06dCjcWl21fgQRB01lTHk/JxtI2aERnDFCJrAtoYL5yukHoBxqVOw0LGteSCBpuQ0ko6/aol+ju2OOuhWj9XPuJkI1IiKBXYA+bgkrraSxKev5ai052kUN6aLnSlqCsO2g9dTZ7t541+zwPFunrFn1FARqSwOGJWM92TL/L9Cs2ccTjNP7oyiXEJRHs1KIGnC0Dxt5PWQlFpeLtTu/xNaKkrxJOmlAezjPLFeUcpuyT2TaZn6CsBFl6aBRI1BveTQPkratq2Im4yM5qtdqqq6lcJc1HQyoENXLYblXEhLDubDgkfwAFzPRXvY1KMDlaTmHg40FWjpLJlmbatnXi5f7c4i3b663M3ymg+0ixDav1tLlK3tG4bqjyubexYieHbcUii+32bGNY/yDVjkVKvOv7DEfhMVnKSiYqn5vtLXt6c1FWx7dr0Fchwrx6N1FnIV++ToU/8LUVvigA9s1nS2+s/RxIfdCJsMz2zfzBa2r7hiiGGiexupK3dYFaydAl6fPiVaqSGLGqJA9MUuvRMSCLKveBdF9hlQuwfidr3TvQzL0LfeofRntz0kuy2UscQ4Sw7kZLpWMI+oeziodFshizpBbkYIx+AlzwEo1+btsrRYMBGuVqMwhpEaucwCd/1bBKqQyFcknjkJ1TtRX2BWErfjRouUvzXvcJI61Bgm5L9aqLJmFOtgsAIqgQ5hS5grQbGOXKELWh8510ou4EL4/LuKtWUhAqSR2GZk1N/7Pdi2XUtTcDElh9T1cMg4d7lMSsiSTHotU6jrKMPv5zw1yExAg16vqzaupZaDnJQJjUzTr+5nrEIlrd2/FGbjLbclUX4I5azlYurjSLVcfCfDa7RHlhvgmtItUux1gWGGZROHhYA+lgikoH4ZmoG+ngmmbL0gHq7d1D3IQQ72jisYbYZv2DxFYMbQvGU9fUGMRoTXhi8OzHRw5d7Do2q5qrJg1UzC96Z7ffb8578dHPVzeXvfv4xfXt5dU5IMzidTyd+LMgXWJ/HmUSNZF4k6RT0V24GKdZYpz2RNfMCes2RbUNjfphFIXTDomEQVNODKlkmxwymVV0yr7vPumPNBvFv3XzhRbb3p0X/+PxBRtM9yfxms38KDhLNsEFYI8WRKvaseZqzLZK6NRu17wR5vwT9bLbOCPMHxKYx4eGQT+m6CDh4aQKYA5Fg4oagFYFfrW4FN+M8QkpinyeM8bhYLuz2D7BKhDcOqo4GS/8n6ss46XyufM7bhFN2tTU6IgnbGsIKH28m62lTDQDJ8VcPTiVZVbzH4fvqtSHkNsXEssipF66C4EmJ39itf6WZ0uC0/KA4CSKjU/OoOLz09jyvI6PnX+/v+/dPMavLnsPj9/vy+dBqGhQpCN9icPQl2dEEgEjsj36QlXnajRLh7oZ0fN4cbQZuZmhMHmK2TClc+pNHM/SU5PjC38arD6IYJv0eI2iIgWLlJmFqZciT8bskHj/ZB7LFOV8d7R1WOyu8+9lpNvzk5ighIUb5Wx4Op+Hr8n6TvzFYjwo2+U6tdDrDW/R+pPcavOQRI817WoPJLXHULGkKTm4kwvu5DB36jg5lKgdbKZhaJe0HtrtNoxrYnZWRkUYt63cKqiGH9ww1xUyKgP1Lq0myFaeVmVoMc2VvylAS9hPrtLHgJJcPMAb3cw/US9D2IbR+EU45c+n0bYtWjOKUO1hi+C54yGkEUT5aat72PKpw4IBDjfwl61p4upOmy8Gm68lYfflpMmWeMF03nUruL8yAQa5DUfQSNhmIYE6Sm9R2L88mc1U4H3eYAy5s2M+jJkSrWVfjBkoTyWIU6gTH5wxY9cbM4SY2ovVsrESvZsLQKf3OVRik7GWAWid8qTMEUk9Wu+yus8WzYIQtmbk2JcO1GBK7UvpUw8r2ayVqYeu5RSnHmrv2eFMptbMs7N9aFwO8tofatyoYQDt47kfSix36TqmIn/ZLC30VdoDulv7X7hrjM6KagX3V4pmExVWfA+c7jDM3lWxi7rBTMAbwBsBKNUbQHfw/RCkMrwBJTudsHugqXSF4W+ba+3XBb+3DpGabFsgwyiI6forZPghoAZ3cH6IFSYr/RAOZuS7ThGbSliBwX2auSWU7g6MW8ITbTrUnVsCuv0gxoTzo7o0dWr7SYhWEcvJjnIZlXhd5bx9chRzI1Nse2hLHnP4YS/1h1ass/JmQdLUh60bXIBGjCau2fYJOzRg6ytkKAomLPxL61lqO7borC+UQ7BaXaDVcm+Fb9RCW+D/JNiPU3UJizKXTyOhgpoKlUZuOkjFzmx6wU5lHNyJ0aQUX4iwja9NAmv5pLZTRYrbqSrr6leR9CQy6lxWW7/KxwRx2+93F6ePWlUOCYduO0Cbx/QFtDltLTqzkfiEU5JQ0zlqRPv0eSXqhyTUQH/Qyq2gH2qEPQsSUONwqibloob+sgNDjWg8FTVFzW7GnmMxlVSWJ6PJMIzt1HSsVQpTdaok6AFt8tpCdFX+ysepNhMz1QffK7rwi7TrVxJ8Rw5rnuBsz+wU8hh6X/aJaXbu1CXbuWiKcl9HwUnksc5AZDCiqMSTvXV80mLbDiJU43Zkr5DidoRmHJ0vu3jxZwUE2H8vw+SDwWqPOU3IMer7n+JbxP+Pv9/gvvrXEV6xlpH0Zzh+8qfjydvq8mk4Cxfpzlc4ZdUeKTnBePm1/qjvD/4apRA7Lj7BJ5z0d8q+Die98uhrknw5fezNtFySMlW80z5/C4fBJDnQS4/Ow/jM9Tu6giRdw/jIRfI6uTlJVonElKk7F63PpRja6TZ4c5sVodafpN5hsvYP07NWRFuftfETx4dWAif5DKVvV97i5H3mL04OFj3GyYeZzzj5cOM1Tj4w0mMUD6uvJMkqk4v0k9yzr1QQ3urkvcmcJQKrt750vXAbIUESSG3WzkTWie3aOFYmDc9N6lnoTd9y9zMMdGIQ18UmwZ6FEiuZnuYvNueNct/CEi99u6Zg/mCRr7LzAAPa2fjmzyvkrWc7f6DxA40faJSLxkLUrQSYHP1w/4JxAh0R6CwJ2uJo9a6hJnbMXNFdcI7mlh5IDtbOZPQa1oLRtB9PHuVgEpby+oc9teZNpW5vmja8HxG+XeamqiB0Rc2ZereNQaqtXey5pPKKjuxd6B9c1cAZn2h/7QPZEswS/11uSzAcp0AC3M4GYcraH+gDS0jYEB3uKcPLzhvuKXf+rdoqDM0SNnhzw8pH0KragjkDuE7/c/UACKkylKUQZJbD7EbrjjTKQlkmlG4rihmJj+fcgPvUO6WdA6Yf8/ojyKWdmoEtmsYcTU6awWVp0YMyIwWG/e97D73HUphF6T91wMlmPRgnmPnjgKhpi+v2wcXGy0xOgN/iIKuNuQ/8gjq1rfQ0s//p0uuNLPqUH8jKIWs94EwbZEEN8bp3ya131GEGXfsUwS5bW+RyFAnb4xCFlhQdyBA6rghB0HXy8MhLWg1E57dDqlUzpnjvfgZagtmjbRjM/KWDqkXv93TSRmcCsLO1ZbujWBLlFn9xYePy83A2TAWMD6MFwi6g7laQAf16RSX4c7gryClfexynTtHgZzBTNRhNlnTAiMPBPPHQGQdjyME6DODpjABsIw7eptdVdj+XAJwmlGsRUrG9UWIMJuFyqFCgsOvJEyidbXj89qtQV/gSToZQGBcMsy3bJJPAHVo8nd7FfdMWznyvIEK58s7KEENQhrDtDtpbcdg/bLXi2XCnachl5iYECFBMAodHAM92TF8uAXhqiFwCQCF+N54Nnltd8raKstpYcu4MUKlLbkO95eF1/AI7mjYSMy1Vj7ay5Fj5ksNkqjT8m8ZcO5AxbZU3tbH6ykUMZwTBw2AeclKiGi15S6GcNpbc7W7Jj7JE0JyPZJMCavb+Dw==</diagram></mxfile>"><defs/><g><ellipse cx="798" cy="107" rx="60" ry="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 107px; margin-left: 739px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">NONE</div></div></div></foreignObject><text x="798" y="111" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">NONE</text></switch></g><path d="M 798 147 L 798 180.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 798 185.88 L 794.5 178.88 L 798 180.63 L 801.5 178.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 738 432.56 Q 773 442.56 808 432.56 Q 843 422.56 878 432.56 L 878 471.44 Q 843 461.44 808 471.44 Q 773 481.44 738 471.44 L 738 432.56 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 452px; margin-left: 739px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">FINGER_DETECTED</div></div></div></foreignObject><text x="808" y="456" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">FINGER_DETECTED</text></switch></g><path d="M 798 377 L 798 402 L 798.85 429.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 799.01 434.88 L 795.29 427.99 L 798.85 429.63 L 802.29 427.78 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 406px; margin-left: 799px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">yes</div></div></div></foreignObject><text x="799" y="409" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 838 337 L 958 337 L 958 710.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 958 715.88 L 954.5 708.88 L 958 710.63 L 961.5 708.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 467px; margin-left: 958px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">no</div></div></div></foreignObject><text x="958" y="470" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 798 297 L 838 337 L 798 377 L 758 337 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 337px; margin-left: 759px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Gestures enabled?</div></div></div></foreignObject><text x="798" y="341" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Gestures enab...</text></switch></g><path d="M 798 267 L 798 290.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 798 295.88 L 794.5 288.88 L 798 290.63 L 801.5 288.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 796.94 475 L 797.84 510.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 797.97 515.88 L 794.3 508.97 L 797.84 510.63 L 801.29 508.8 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 738 647 L 634.37 647" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 629.12 647 L 636.12 643.5 L 634.37 647 L 636.12 650.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="798" cy="647" rx="60" ry="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 647px; margin-left: 739px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">UNKNOWN</div></div></div></foreignObject><text x="798" y="651" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">UNKNOWN</text></switch></g><path d="M 738 517 L 838 517 L 858 542 L 838 567 L 738 567 L 758 542 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 542px; margin-left: 739px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "> Start hold timer</div></div></div></foreignObject><text x="798" y="546" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> Start hold timer</text></switch></g><path d="M 798 567 L 798 600.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 798 605.88 L 794.5 598.88 L 798 600.63 L 801.5 598.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 798 717 L 838 757 L 798 797 L 758 757 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 757px; margin-left: 759px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Motion detected?</div></div></div></foreignObject><text x="798" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Motion detect...</text></switch></g><path d="M 798 687 L 798 710.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 798 715.88 L 794.5 708.88 L 798 710.63 L 801.5 708.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 838 757 L 911.63 757" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 916.88 757 L 909.88 760.5 L 911.63 757 L 909.88 753.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 757px; margin-left: 878px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">yes</div></div></div></foreignObject><text x="878" y="760" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 758 757 L 714.37 757" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 709.12 757 L 716.12 753.5 L 714.37 757 L 716.12 760.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 757px; margin-left: 733px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">no</div></div></div></foreignObject><text x="733" y="760" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 588 732 L 688 732 L 708 757 L 688 782 L 588 782 L 608 757 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 757px; margin-left: 589px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Hold timeout</div></div></div></foreignObject><text x="648" y="761" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Hold timeout</text></switch></g><path d="M 608 757 L 554.37 757" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 549.12 757 L 556.12 753.5 L 554.37 757 L 556.12 760.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 408 737.56 Q 443 747.56 478 737.56 Q 513 727.56 548 737.56 L 548 776.44 Q 513 766.44 478 776.44 Q 443 786.44 408 776.44 L 408 737.56 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 757px; margin-left: 409px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">HOLD_TIMEOUT</div></div></div></foreignObject><text x="478" y="761" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD_TIMEOUT</text></switch></g><path d="M 148 797 L 148 850.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 148 855.88 L 144.5 848.88 L 148 850.63 L 151.5 848.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 148 717 L 148 683.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 148 678.12 L 151.5 685.12 L 148 683.37 L 144.5 685.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="148" cy="757" rx="60" ry="40" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 757px; margin-left: 89px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">HOLD</div></div></div></foreignObject><text x="148" y="761" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD</text></switch></g><path d="M 258 757 L 214.37 757" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 209.12 757 L 216.12 753.5 L 214.37 757 L 216.12 760.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 248 787 L 268 727 L 368 727 L 348 787 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 757px; margin-left: 249px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">HOLD_BEGIN</div></div></div></foreignObject><text x="308" y="761" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD_BEGIN</text></switch></g><path d="M 408 757 L 364.37 757" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 359.12 757 L 366.12 753.5 L 364.37 757 L 366.12 760.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 188 897 L 291.63 897" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 296.88 897 L 289.88 900.5 L 291.63 897 L 289.88 893.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 897px; margin-left: 243px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">yes</div></div></div></foreignObject><text x="243" y="900" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 108 897 L 68 897 L 68 757 L 81.63 757" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 86.88 757 L 79.88 760.5 L 81.63 757 L 79.88 753.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 837px; margin-left: 68px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">no</div></div></div></foreignObject><text x="68" y="840" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 148 857 L 188 897 L 148 937 L 108 897 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 897px; margin-left: 109px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Motion detected?</div></div></div></foreignObject><text x="148" y="901" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Motion detect...</text></switch></g><path d="M 608 897 L 958 897 L 958 803.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 958 798.12 L 961.5 805.12 L 958 803.37 L 954.5 805.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 498 927 L 518 867 L 618 867 L 598 927 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 897px; margin-left: 499px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">HOLD_END<br />(CANCEL)</div></div></div></foreignObject><text x="558" y="901" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD_END...</text></switch></g><path d="M 148 597 L 148 554.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 148 549.12 L 151.5 556.12 L 148 554.37 L 144.5 556.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 572px; margin-left: 148px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">all</div></div></div></foreignObject><text x="148" y="575" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">all</text></switch></g><path d="M 108 637 L 38 637 L 38 1827 L 2983 1827 L 2983 953.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 2983 948.12 L 2986.5 955.12 L 2983 953.37 L 2979.5 955.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 680px; margin-left: 42px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">some (debounce)</div></div></div></foreignObject><text x="42" y="683" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">some (debounce)</text></switch></g><path d="M 148 597 L 188 637 L 148 677 L 108 637 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 637px; margin-left: 109px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Finger up?</div></div></div></foreignObject><text x="148" y="641" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Finger up?</text></switch></g><path d="M 148 487 L 148 107 L 511.63 107" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 516.88 107 L 509.88 110.5 L 511.63 107 L 509.88 103.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 88 547 L 108 487 L 208 487 L 188 547 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 517px; margin-left: 89px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">HOLD_END</div></div></div></foreignObject><text x="148" y="521" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD_END</text></switch></g><path d="M 998 757 L 1068 757 L 1068 1557 L 1122.1 1557" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1127.35 1557 L 1120.35 1560.5 L 1122.1 1557 L 1120.35 1553.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 998 757 L 1068 757 L 1068 1157 L 1121.63 1157" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1126.88 1157 L 1119.88 1160.5 L 1121.63 1157 L 1119.88 1153.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 998 757 L 1068 757 L 1068 526 L 1121.93 526" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1127.18 526 L 1120.18 529.5 L 1121.93 526 L 1120.18 522.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 998 757 L 1121.63 757" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1126.88 757 L 1119.88 760.5 L 1121.63 757 L 1119.88 753.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 958 717 L 998 757 L 958 797 L 918 757 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 757px; margin-left: 919px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Number of fingers?</div></div></div></foreignObject><text x="958" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Number of fin...</text></switch></g><path d="M 1233 1157 L 1291.63 1157" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1296.88 1157 L 1289.88 1160.5 L 1291.63 1157 L 1289.88 1153.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 1158 1137 C 1134 1137 1128 1157 1147.2 1161 C 1128 1169.8 1149.6 1189 1165.2 1181 C 1176 1197 1212 1197 1224 1181 C 1248 1181 1248 1165 1233 1157 C 1248 1141 1224 1125 1203 1133 C 1188 1121 1164 1121 1158 1137 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1157px; margin-left: 1129px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">2 fingers</div></div></div></foreignObject><text x="1188" y="1161" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">2 fingers</text></switch></g><path d="M 1233 757 L 1321.63 757" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1326.88 757 L 1319.88 760.5 L 1321.63 757 L 1319.88 753.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 1158 737 C 1134 737 1128 757 1147.2 761 C 1128 769.8 1149.6 789 1165.2 781 C 1176 797 1212 797 1224 781 C 1248 781 1248 765 1233 757 C 1248 741 1224 725 1203 733 C 1188 721 1164 721 1158 737 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 757px; margin-left: 1129px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">3 or 4 fingers</div></div></div></foreignObject><text x="1188" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">3 or 4 fingers</text></switch></g><path d="M 1233 1552 L 1291.63 1552" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1296.88 1552 L 1289.88 1555.5 L 1291.63 1552 L 1289.88 1548.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 1158 1532 C 1134 1532 1128 1552 1147.2 1556 C 1128 1564.8 1149.6 1584 1165.2 1576 C 1176 1592 1212 1592 1224 1576 C 1248 1576 1248 1560 1233 1552 C 1248 1536 1224 1520 1203 1528 C 1188 1516 1164 1516 1158 1532 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1552px; margin-left: 1129px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">1 finger</div></div></div></foreignObject><text x="1188" y="1556" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">1 finger</text></switch></g><path d="M 1188 482 L 1188 107 L 1084.37 107" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1079.12 107 L 1086.12 103.5 L 1084.37 107 L 1086.12 110.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 466px; margin-left: 1187px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">(to NONE)</div></div></div></foreignObject><text x="1187" y="469" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">(to NONE)</text></switch></g><path d="M 1158 502 C 1134 502 1128 522 1147.2 526 C 1128 534.8 1149.6 554 1165.2 546 C 1176 562 1212 562 1224 546 C 1248 546 1248 530 1233 522 C 1248 506 1224 490 1203 498 C 1188 486 1164 486 1158 502 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 522px; margin-left: 1129px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">5 or more<br />fingers</div></div></div></foreignObject><text x="1188" y="526" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">5 or more...</text></switch></g><path d="M 1438 1552 L 1481.63 1552" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1486.88 1552 L 1479.88 1555.5 L 1481.63 1552 L 1479.88 1548.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 1298 1532.56 Q 1333 1542.56 1368 1532.56 Q 1403 1522.56 1438 1532.56 L 1438 1571.44 Q 1403 1561.44 1368 1571.44 Q 1333 1581.44 1298 1571.44 L 1298 1532.56 Z" fill="#fff2cc" stroke="#d6b656" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 1552px; margin-left: 1299px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">POINTER_MOTION</div></div></div></foreignObject><text x="1368" y="1556" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">POINTER_MOTION</text></switch></g><path d="M 1438 1157 L 1481.63 1157" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1486.88 1157 L 1479.88 1160.5 L 1481.63 1157 L 1479.88 1153.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 1298 1137.56 Q 1333 1147.56 1368 1137.56 Q 1403 1127.56 1438 1137.56 L 1438 1176.44 Q 1403 1166.44 1368 1176.44 Q 1333 1186.44 1298 1176.44 L 1298 1137.56 Z" fill="#f8cecc" stroke="#b85450" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 1157px; margin-left: 1299px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">SCROLL</div></div></div></foreignObject><text x="1368" y="1161" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">SCROLL</text></switch></g><path d="M 1808 591 L 1828 591 L 1818 591 L 1841.63 591" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1846.88 591 L 1839.88 594.5 L 1841.63 591 L 1839.88 587.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 1668 571.56 Q 1703 581.56 1738 571.56 Q 1773 561.56 1808 571.56 L 1808 610.44 Q 1773 600.44 1738 610.44 Q 1703 620.44 1668 610.44 L 1668 571.56 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 591px; margin-left: 1669px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">SWIPE</div></div></div></foreignObject><text x="1738" y="595" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">SWIPE</text></switch></g><path d="M 1808 921 L 1828 921 L 1818 921 L 1841.63 921" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1846.88 921 L 1839.88 924.5 L 1841.63 921 L 1839.88 917.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 1668 901.56 Q 1703 911.56 1738 901.56 Q 1773 891.56 1808 901.56 L 1808 940.44 Q 1773 930.44 1738 940.44 Q 1703 950.44 1668 940.44 L 1668 901.56 Z" fill="#ffe6cc" stroke="#d79b00" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 921px; margin-left: 1669px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">PINCH</div></div></div></foreignObject><text x="1738" y="925" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">PINCH</text></switch></g><path d="M 1528 717 L 1528 591 L 1661.63 591" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1666.88 591 L 1659.88 594.5 L 1661.63 591 L 1659.88 587.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 592px; margin-left: 1582px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">swipe</div></div></div></foreignObject><text x="1582" y="596" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">swipe</text></switch></g><path d="M 1528 797 L 1528 921 L 1661.63 921" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1666.88 921 L 1659.88 924.5 L 1661.63 921 L 1659.88 917.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 922px; margin-left: 1573px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">pinch</div></div></div></foreignObject><text x="1573" y="926" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">pinch</text></switch></g><path d="M 1528 717 L 1568 757 L 1528 797 L 1488 757 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 757px; margin-left: 1489px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Gesture<br />type?</div></div></div></foreignObject><text x="1528" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Gesture...</text></switch></g><path d="M 2108 591 L 2151.63 591" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 2156.88 591 L 2149.88 594.5 L 2151.63 591 L 2149.88 587.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="2048" cy="591" rx="60" ry="40" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 591px; margin-left: 1989px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">SWIPE</div></div></div></foreignObject><text x="2048" y="595" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">SWIPE</text></switch></g><path d="M 2108 921 L 2151.63 921" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 2156.88 921 L 2149.88 924.5 L 2151.63 921 L 2149.88 917.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="2048" cy="921" rx="60" ry="40" fill="#ffe6cc" stroke="#d79b00" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 921px; margin-left: 1989px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">PINCH</div></div></div></foreignObject><text x="2048" y="925" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">PINCH</text></switch></g><path d="M 1948 591 L 1978 591 L 1968 591 L 1981.63 591" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1986.88 591 L 1979.88 594.5 L 1981.63 591 L 1979.88 587.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 1838 621 L 1858 561 L 1958 561 L 1938 621 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 591px; margin-left: 1839px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">SWIPE_BEGIN</div></div></div></foreignObject><text x="1898" y="595" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">SWIPE_BEGIN</text></switch></g><path d="M 1948 921 L 1978 921 L 1968 921 L 1981.63 921" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1986.88 921 L 1979.88 924.5 L 1981.63 921 L 1979.88 917.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 1838 951 L 1858 891 L 1958 891 L 1938 951 Z" fill="#ffe6cc" stroke="#d79b00" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 921px; margin-left: 1839px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">PINCH_BEGIN</div></div></div></foreignObject><text x="1898" y="925" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">PINCH_BEGIN</text></switch></g><path d="M 378 1027 L 558 1027 L 558 933.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 558 928.12 L 561.5 935.12 L 558 933.37 L 554.5 935.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1027px; margin-left: 518px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">yes</div></div></div></foreignObject><text x="518" y="1030" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 298 1027 L 214.37 1027" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 209.12 1027 L 216.12 1023.5 L 214.37 1027 L 216.12 1030.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1027px; margin-left: 253px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">no</div></div></div></foreignObject><text x="253" y="1030" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 338 987 L 378 1027 L 338 1067 L 298 1027 Z" fill="#e1d5e7" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 1027px; margin-left: 299px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Motion<br />> hold threshold?</div></div></div></foreignObject><text x="338" y="1031" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Motion...</text></switch></g><path d="M 378 897 L 501.63 897" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 506.88 897 L 499.88 900.5 L 501.63 897 L 499.88 893.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 897px; margin-left: 443px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">no</div></div></div></foreignObject><text x="443" y="900" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 338 937 L 338 980.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 338 985.88 L 334.5 978.88 L 338 980.63 L 341.5 978.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 962px; margin-left: 338px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">yes</div></div></div></foreignObject><text x="338" y="965" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 338 857 L 378 897 L 338 937 L 298 897 Z" fill="#e1d5e7" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 897px; margin-left: 299px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">1 finger?</div></div></div></foreignObject><text x="338" y="901" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">1 finger?</text></switch></g><path d="M 1778 1627 L 1778 1712 L 1664.37 1712" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1659.12 1712 L 1666.12 1708.5 L 1664.37 1712 L 1666.12 1715.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 1718 1577 L 1818 1577 L 1838 1602 L 1818 1627 L 1718 1627 L 1738 1602 Z" fill="#e1d5e7" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1602px; margin-left: 1719px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Hold timeout</div></div></div></foreignObject><text x="1778" y="1606" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Hold timeout</text></switch></g><path d="M 1438 1712 L 1334.37 1712" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1329.12 1712 L 1336.12 1708.5 L 1334.37 1712 L 1336.12 1715.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1712px; margin-left: 1383px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">yes</div></div></div></foreignObject><text x="1383" y="1715" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 1478 1672 L 1478 1632 L 1548 1632 L 1548 1598.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1548 1593.12 L 1551.5 1600.12 L 1548 1598.37 L 1544.5 1600.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1632px; margin-left: 1513px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">no</div></div></div></foreignObject><text x="1513" y="1635" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 1478 1672 L 1518 1712 L 1478 1752 L 1438 1712 Z" fill="#e1d5e7" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 1712px; margin-left: 1439px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Motion<br />< hold threshold?</div></div></div></foreignObject><text x="1478" y="1716" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Motion...</text></switch></g><path d="M 148 987 L 148 943.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 148 938.12 L 151.5 945.12 L 148 943.37 L 144.5 945.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="148" cy="1027" rx="60" ry="40" fill="#e1d5e7" stroke="#9673a6" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1027px; margin-left: 89px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">HOLD_AND_MOTION</div></div></div></foreignObject><text x="148" y="1031" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD_AND_MOTION</text></switch></g><path d="M 148 1287 L 148 1073.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 148 1068.12 L 151.5 1075.12 L 148 1073.37 L 144.5 1075.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 88 1347 L 108 1287 L 208 1287 L 188 1347 Z" fill="#e1d5e7" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1317px; margin-left: 89px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">HOLD_BEGIN</div></div></div></foreignObject><text x="148" y="1321" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD_BEGIN</text></switch></g><path d="M 1208 1712 L 148 1712 L 148 1353.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 148 1348.12 L 151.5 1355.12 L 148 1353.37 L 144.5 1355.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 1208 1692.56 Q 1243 1702.56 1278 1692.56 Q 1313 1682.56 1348 1692.56 L 1348 1731.44 Q 1313 1721.44 1278 1731.44 Q 1243 1741.44 1208 1731.44 L 1208 1692.56 Z" fill="#e1d5e7" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 1712px; margin-left: 1209px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">HOLD_TIMEOUT</div></div></div></foreignObject><text x="1278" y="1716" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD_TIMEOUT</text></switch></g><path d="M 1578 1712 L 1524.37 1712" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1519.12 1712 L 1526.12 1708.5 L 1524.37 1712 L 1526.12 1715.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1712px; margin-left: 1548px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">yes</div></div></div></foreignObject><text x="1548" y="1715" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 1618 1672 L 1618 1632 L 1548 1632 L 1548 1598.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1548 1593.12 L 1551.5 1600.12 L 1548 1598.37 L 1544.5 1600.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1632px; margin-left: 1583px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">no</div></div></div></foreignObject><text x="1583" y="1635" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 1618 1672 L 1658 1712 L 1618 1752 L 1578 1712 Z" fill="#e1d5e7" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 1712px; margin-left: 1579px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Gestures enabled?</div></div></div></foreignObject><text x="1618" y="1716" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Gestures enab...</text></switch></g><path d="M 1608 1157 L 1661.63 1157" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1666.88 1157 L 1659.88 1160.5 L 1661.63 1157 L 1659.88 1153.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="1548" cy="1157" rx="60" ry="40" fill="#f8cecc" stroke="#b85450" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1157px; margin-left: 1489px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">SCROLL</div></div></div></foreignObject><text x="1548" y="1161" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">SCROLL</text></switch></g><path d="M 1606.09 1562 L 1668 1562 L 1668 1602 L 1731.63 1602" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1736.88 1602 L 1729.88 1605.5 L 1731.63 1602 L 1729.88 1598.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 1548 1512 L 1548 1492 L 1548 1502 L 1548 1488.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1548 1483.12 L 1551.5 1490.12 L 1548 1488.37 L 1544.5 1490.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="1548" cy="1552" rx="60" ry="40" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1552px; margin-left: 1489px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">POINTER_MOTION</div></div></div></foreignObject><text x="1548" y="1556" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">POINTER_MOTION</text></switch></g><path d="M 1408 757 L 1481.63 757" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1486.88 757 L 1479.88 760.5 L 1481.63 757 L 1479.88 753.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 757px; margin-left: 1448px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">yes</div></div></div></foreignObject><text x="1448" y="760" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 1368 717 L 1368 107 L 1084.37 107" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1079.12 107 L 1086.12 103.5 L 1084.37 107 L 1086.12 110.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 680px; margin-left: 1368px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">no (to NONE)</div></div></div></foreignObject><text x="1368" y="683" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">no (to NONE)</text></switch></g><path d="M 1368 717 L 1408 757 L 1368 797 L 1328 757 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 757px; margin-left: 1329px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Gestures enabled?</div></div></div></foreignObject><text x="1368" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Gestures enab...</text></switch></g><path d="M 588 607 L 588 369.5 L 588.41 134.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 588.42 129.12 L 591.91 136.12 L 588.41 134.37 L 584.91 136.11 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 567px; margin-left: 588px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">yes</div></div></div></foreignObject><text x="588" y="570" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 588 607 L 628 647 L 588 687 L 548 647 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 647px; margin-left: 549px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Finger up?</div></div></div></foreignObject><text x="588" y="651" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Finger up?</text></switch></g><path d="M 798 187 L 838 227 L 798 267 L 758 227 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 227px; margin-left: 759px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Finger count changed?</div></div></div></foreignObject><text x="798" y="231" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Finger count...</text></switch></g><path d="M 2668 567 L 2668 567 L 3298 567 L 3298 567" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 2668 567 L 2668 947 L 3298 947 L 3298 567" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2668 567 L 3298 567" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g fill="#000000" font-family="Helvetica" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px"><text x="2982.5" y="561.5">DEBOUNCE FINGER LOGIC</text></g><path d="M 2890.5 757 L 2944.13 757" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2949.38 757 L 2942.38 760.5 L 2944.13 757 L 2942.38 753.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2720.5 732 L 2870.5 732 L 2890.5 757 L 2870.5 782 L 2720.5 782 L 2740.5 757 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 168px; height: 1px; padding-top: 757px; margin-left: 2722px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Start debounce timer</div></div></div></foreignObject><text x="2806" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Start debounce timer</text></switch></g><path d="M 3100.5 757 L 3154.13 757" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 3159.38 757 L 3152.38 760.5 L 3154.13 757 L 3152.38 753.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2930.5 732 L 3080.5 732 L 3100.5 757 L 3080.5 782 L 2930.5 782 L 2950.5 757 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 168px; height: 1px; padding-top: 757px; margin-left: 2932px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Debounce timeout</div></div></div></foreignObject><text x="3016" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Debounce timeout</text></switch></g><path d="M 3200.5 717 L 3200.5 673.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 3200.5 668.12 L 3204 675.12 L 3200.5 673.37 L 3197 675.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 692px; margin-left: 3201px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">yes</div></div></div></foreignObject><text x="3201" y="695" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 3200.5 797 L 3200.5 850.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 3200.5 855.88 L 3197 848.88 L 3200.5 850.63 L 3204 848.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 827px; margin-left: 3201px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">no</div></div></div></foreignObject><text x="3201" y="830" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 3200.5 717 L 3240.5 757 L 3200.5 797 L 3160.5 757 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 757px; margin-left: 3162px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Number of fingers changed?</div></div></div></foreignObject><text x="3201" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Number of fin...</text></switch></g><path d="M 3125.5 667 L 3145.5 607 L 3275.5 607 L 3255.5 667 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 148px; height: 1px; padding-top: 637px; margin-left: 3127px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">CANCEL CURRENT GESTURE</div></div></div></foreignObject><text x="3201" y="641" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">CANCEL CURRENT GESTURE</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 887px; margin-left: 3142px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Ignore this finger change and stay in the same state</div></div></div></foreignObject><text x="3201" y="891" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Ignore this finger c...</text></switch></g><path d="M 2690.5 757 L 2734.13 757" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2739.38 757 L 2732.38 760.5 L 2734.13 757 L 2732.38 753.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 3198 607 L 3198 107 L 1084.37 107" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1079.12 107 L 1086.12 103.5 L 1084.37 107 L 1086.12 110.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 583px; margin-left: 3201px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">(to NONE)</div></div></div></foreignObject><text x="3201" y="587" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">(to NONE)</text></switch></g><path d="M 2198 551 L 2198 493.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2198 488.12 L 2201.5 495.12 L 2198 493.37 L 2194.5 495.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 519px; margin-left: 2198px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">all</div></div></div></foreignObject><text x="2198" y="522" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">all</text></switch></g><path d="M 2238 591 L 2453 591 L 2453 757 L 2661.63 757" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2666.88 757 L 2659.88 760.5 L 2661.63 757 L 2659.88 753.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 591px; margin-left: 2301px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">some</div></div></div></foreignObject><text x="2301" y="594" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">some</text></switch></g><path d="M 2198 631 L 2198 687 L 2098 687 L 2098 690.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2098 695.88 L 2094.5 688.88 L 2098 690.63 L 2101.5 688.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 647px; margin-left: 2199px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">no</div></div></div></foreignObject><text x="2199" y="651" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 2198 551 L 2238 591 L 2198 631 L 2158 591 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 591px; margin-left: 2159px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Finger up?</div></div></div></foreignObject><text x="2198" y="595" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Finger up?</text></switch></g><path d="M 2198 427 L 2198 107 L 1084.37 107" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1079.12 107 L 1086.12 103.5 L 1084.37 107 L 1086.12 110.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 396px; margin-left: 2199px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">(to NONE)</div></div></div></foreignObject><text x="2199" y="399" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">(to NONE)</text></switch></g><path d="M 2138 487 L 2158 427 L 2258 427 L 2238 487 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 457px; margin-left: 2139px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">SWIPE_END</div></div></div></foreignObject><text x="2198" y="461" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">SWIPE_END</text></switch></g><path d="M 2238 921 L 2453 921 L 2453 757 L 2661.63 757" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2666.88 757 L 2659.88 760.5 L 2661.63 757 L 2659.88 753.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 920px; margin-left: 2284px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">some</div></div></div></foreignObject><text x="2284" y="924" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">some</text></switch></g><path d="M 2198 961 L 2198 1010.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2198 1015.88 L 2194.5 1008.88 L 2198 1010.63 L 2201.5 1008.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 989px; margin-left: 2198px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">all</div></div></div></foreignObject><text x="2198" y="992" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">all</text></switch></g><path d="M 2198 881 L 2198 827 L 2104.37 827" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2099.12 827 L 2106.12 823.5 L 2104.37 827 L 2106.12 830.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 870px; margin-left: 2201px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">no</div></div></div></foreignObject><text x="2201" y="873" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 2198 881 L 2238 921 L 2198 961 L 2158 921 Z" fill="#ffe6cc" stroke="#d79b00" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 921px; margin-left: 2159px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Finger up?</div></div></div></foreignObject><text x="2198" y="925" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Finger up?</text></switch></g><path d="M 2248 1047 L 3378 1047 L 3378 107 L 1084.37 107" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1079.12 107 L 1086.12 103.5 L 1084.37 107 L 1086.12 110.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1049px; margin-left: 2309px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">(to NONE)</div></div></div></foreignObject><text x="2309" y="1053" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">(to NONE)</text></switch></g><path d="M 2138 1077 L 2158 1017 L 2258 1017 L 2238 1077 Z" fill="#ffe6cc" stroke="#d79b00" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1047px; margin-left: 2139px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">PINCH_END</div></div></div></foreignObject><text x="2198" y="1051" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">PINCH_END</text></switch></g><path d="M 798 7 L 798 60.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 798 65.88 L 794.5 58.88 L 798 60.63 L 801.5 58.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1548 1402 L 1548 1367 L 3538 1367 L 3538 107 L 1084.37 107" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1079.12 107 L 1086.12 103.5 L 1084.37 107 L 1086.12 110.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1367px; margin-left: 1584px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">yes (to NONE)</div></div></div></foreignObject><text x="1584" y="1371" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">yes (to NONE)</text></switch></g><path d="M 1588 1442 L 1671.63 1442" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1676.88 1442 L 1669.88 1445.5 L 1671.63 1442 L 1669.88 1438.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1442px; margin-left: 1633px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">no</div></div></div></foreignObject><text x="1633" y="1445" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 1548 1402 L 1588 1442 L 1548 1482 L 1508 1442 Z" fill="#fff2cc" stroke="#d6b656" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 1442px; margin-left: 1509px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Finger up?</div></div></div></foreignObject><text x="1548" y="1446" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Finger up?</text></switch></g><path d="M 2048 667 L 2048 647 L 2048 651 L 2048 637.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2048 632.12 L 2051.5 639.12 L 2048 637.37 L 2044.5 639.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1988 727 L 2008 667 L 2108 667 L 2088 727 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 697px; margin-left: 1989px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">SWIPE_UPDATE</div></div></div></foreignObject><text x="2048" y="701" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">SWIPE_UPDATE</text></switch></g><path d="M 2048 857 L 2048 877 L 2048 861 L 2048 874.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2048 879.88 L 2044.5 872.88 L 2048 874.63 L 2051.5 872.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1988 857 L 2008 797 L 2108 797 L 2088 857 Z" fill="#ffe6cc" stroke="#d79b00" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 827px; margin-left: 1989px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">PINCH_UPDATE</div></div></div></foreignObject><text x="2048" y="831" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">PINCH_UPDATE</text></switch></g><path d="M 1743 1472 L 1743 1542 L 1612.46 1542" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1607.21 1542 L 1614.21 1538.5 L 1612.46 1542 L 1614.21 1545.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1668 1472 L 1688 1412 L 1818 1412 L 1798 1472 Z" fill="#fff2cc" stroke="#d6b656" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 148px; height: 1px; padding-top: 1442px; margin-left: 1669px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">POINTER_MOTION</div></div></div></foreignObject><text x="1743" y="1446" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">POINTER_MOTION</text></switch></g><path d="M 1708 1197 L 1708 1261 L 1619.37 1261" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1614.12 1261 L 1621.12 1257.5 L 1619.37 1261 L 1621.12 1264.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1261px; margin-left: 1692px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">no</div></div></div></foreignObject><text x="1692" y="1264" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 1928 1157 L 3458 1157 L 3458 107 L 1084.37 107" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1079.12 107 L 1086.12 103.5 L 1084.37 107 L 1086.12 110.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1154px; margin-left: 1971px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; "><span style="color: rgba(0 , 0 , 0 , 0) ; font-family: monospace ; font-size: 0px ; background-color: rgb(248 , 249 , 250)">%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E</span><span style="color: rgba(0 , 0 , 0 , 0) ; font-family: monospace ; font-size: 0px ; background-color: rgb(248 , 249 , 250)">%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E(to NONE)</span></div></div></div></foreignObject><text x="1971" y="1158" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E(to NONE)</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1158px; margin-left: 2248px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">(to NONE)</div></div></div></foreignObject><text x="2248" y="1162" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">(to NONE)</text></switch></g><path d="M 1748 1157 L 1791.63 1157" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1796.88 1157 L 1789.88 1160.5 L 1791.63 1157 L 1789.88 1153.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1157px; margin-left: 1773px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">all</div></div></div></foreignObject><text x="1773" y="1160" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">all</text></switch></g><path d="M 1708 1117 L 1708 1097 L 2983 1097 L 2983 953.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2983 948.12 L 2986.5 955.12 L 2983 953.37 L 2979.5 955.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1096px; margin-left: 1780px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; ">some (debounce)</div></div></div></foreignObject><text x="1780" y="1100" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">some (debounce)</text></switch></g><path d="M 1708 1117 L 1748 1157 L 1708 1197 L 1668 1157 Z" fill="#f8cecc" stroke="#b85450" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 1157px; margin-left: 1669px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Finger up?</div></div></div></foreignObject><text x="1708" y="1161" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Finger up?</text></switch></g><path d="M 1548 1231 L 1548 1211 L 1548 1217 L 1548 1203.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1548 1198.12 L 1551.5 1205.12 L 1548 1203.37 L 1544.5 1205.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1473 1291 L 1493 1231 L 1623 1231 L 1603 1291 Z" fill="#f8cecc" stroke="#b85450" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 148px; height: 1px; padding-top: 1261px; margin-left: 1474px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">AXIS</div></div></div></foreignObject><text x="1548" y="1265" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">AXIS</text></switch></g><path d="M 1788 1187 L 1808 1127 L 1938 1127 L 1918 1187 Z" fill="#f8cecc" stroke="#b85450" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 148px; height: 1px; padding-top: 1157px; margin-left: 1789px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">AXIS (0,0)</div></div></div></foreignObject><text x="1863" y="1161" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">AXIS (0,0)</text></switch></g><path d="M 938 107 L 864.37 107" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 859.12 107 L 866.12 103.5 L 864.37 107 L 866.12 110.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 938 87.56 Q 973 97.56 1008 87.56 Q 1043 77.56 1078 87.56 L 1078 126.44 Q 1043 116.44 1008 126.44 Q 973 136.44 938 126.44 L 938 87.56 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 107px; margin-left: 939px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">RESET</div></div></div></foreignObject><text x="1008" y="111" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">RESET</text></switch></g><path d="M 658 107 L 731.63 107" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 736.88 107 L 729.88 110.5 L 731.63 107 L 729.88 103.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 518 87.56 Q 553 97.56 588 87.56 Q 623 77.56 658 87.56 L 658 126.44 Q 623 116.44 588 126.44 Q 553 136.44 518 126.44 L 518 87.56 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 107px; margin-left: 519px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">RESET</div></div></div></foreignObject><text x="588" y="111" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">RESET</text></switch></g><path d="M 2848 1927 L 2848 1927 L 3538 1927 L 3538 1927" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2848 1927 L 2848 2247 L 3538 2247 L 3538 1927" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 2848 1927 L 3538 1927" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g fill="#000000" font-family="Helvetica" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px"><text x="3192.5" y="1921.5">LEGEND</text></g><ellipse cx="2948" cy="1997" rx="60" ry="40" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1997px; margin-left: 2889px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">STATE</div></div></div></foreignObject><text x="2948" y="2001" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">STATE</text></switch></g><path d="M 3048 1977.56 Q 3083 1987.56 3118 1977.56 Q 3153 1967.56 3188 1977.56 L 3188 2016.44 Q 3153 2006.44 3118 2016.44 Q 3083 2026.44 3048 2016.44 L 3048 1977.56 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 1997px; margin-left: 3049px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">EVENT</div></div></div></foreignObject><text x="3118" y="2001" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">EVENT</text></switch></g><path d="M 3118 2127 L 3158 2167 L 3118 2207 L 3078 2167 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 2167px; margin-left: 3079px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Conditional</div></div></div></foreignObject><text x="3118" y="2171" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Conditional</text></switch></g><path d="M 2888 2142 L 2988 2142 L 3008 2167 L 2988 2192 L 2888 2192 L 2908 2167 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 2167px; margin-left: 2889px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Time event</div></div></div></foreignObject><text x="2948" y="2171" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Time event</text></switch></g><path d="M 3228 2027 L 3248 1967 L 3348 1967 L 3328 2027 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1997px; margin-left: 3229px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">GESTURE</div></div></div></foreignObject><text x="3288" y="2001" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">GESTURE</text></switch></g><path d="M 3258 2147 C 3234 2147 3228 2167 3247.2 2171 C 3228 2179.8 3249.6 2199 3265.2 2191 C 3276 2207 3312 2207 3324 2191 C 3348 2191 3348 2175 3333 2167 C 3348 2151 3324 2135 3303 2143 C 3288 2131 3264 2131 3258 2147 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 2167px; margin-left: 3229px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Condition</div></div></div></foreignObject><text x="3288" y="2171" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Condition</text></switch></g><rect x="3388" y="2132" width="120" height="30" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 2147px; margin-left: 3389px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Hold</div></div></div></foreignObject><text x="3448" y="2151" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Hold</text></switch></g><rect x="3388" y="2172" width="120" height="30" fill="#e1d5e7" stroke="#9673a6" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 2187px; margin-left: 3389px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Hold and motion</div></div></div></foreignObject><text x="3448" y="2191" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Hold and motion</text></switch></g><rect x="3388" y="2092" width="120" height="30" fill="#ffe6cc" stroke="#d79b00" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 2107px; margin-left: 3389px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Pinch</div></div></div></foreignObject><text x="3448" y="2111" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Pinch</text></switch></g><rect x="3388" y="2052" width="120" height="30" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 2067px; margin-left: 3389px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Swipe</div></div></div></foreignObject><text x="3448" y="2071" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Swipe</text></switch></g><rect x="3388" y="1972" width="120" height="30" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1987px; margin-left: 3389px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Pointer motion</div></div></div></foreignObject><text x="3448" y="1991" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Pointer motion</text></switch></g><rect x="3388" y="2012" width="120" height="30" fill="#f8cecc" stroke="#b85450" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 2027px; margin-left: 3389px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">Scroll</div></div></div></foreignObject><text x="3448" y="2031" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Scroll</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="3548px" height="2248px" viewBox="-0.5 -0.5 3548 2248" content="<mxfile host="app.diagrams.net" modified="2022-01-22T18:22:22.351Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36" etag="UrdhAhHn5AH3wTDN2l_l" version="16.4.5" type="device"><diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">7V1bd6O2Fv41WWvOQ7KQQFwec/FkMs0k01ya9rx0EZvYPsUmxXgymV9/EEY2aMuAbZDkJGlXa2PAeN+096d9OTBPJz/PY/959C0aBOEBNgY/D8yzA4yRhfEB/dcYvOZHPActjgzj8SA/tjpwO/4V5AeN/Oh8PAhmpROTKAqT8XP5YD+aToN+Ujrmx3H0Uj7tKQrL3/rsDwNw4Lbvh/Dow3iQjNjPwMbqgy/BeDhiX42N/JOJz87OD8xG/iB6KRwyewfmaRxFyeLV5OdpEFLyMcI8XLw+hJf/2Odff5/969+f/HZ39cfh4mafN7lk+RviYJpsfevzp9vfT16+fp+64a8LY35xNYmG+SXGDz+c5wS7ur7q5b83eWVUTO+UMix9c/IyGifB7bPfp5+8pEKTHhslkzB9h9KXT+MwPI3CKM6uM58I/Sc9Pkvi6J+g8Imd/dEromlSOL74S483/M05bX4EcRL8LLA8p8F5EE2CJH5NT8k/daz8N+cSzbj7UpAOdmxUEAw3P+bnAjlc3nlF8/RFTvYNWGACFkDyTwfHVBfSd/3Qn83G/TLVg5/j5M/0tXFE8nd/FT45o7/cYG9e8zeb0XcWzeN+UC9IwaCkjpALBTITAZXZsTgI/WT8o6zEItLn3/A9Gqc/Yy2TTcRxb/F78quKSsPdyDXKN0IWd6PEj4dBAm6UScLyZ28vHBYQjs8XV+e9m7/Pene907veGZCV1Eo905dJ9r86fZ0tDLZxhLm/vdRl0xUos1UhZq0rM4IG9TVd/oBCp2pym7+N4mQUDaOpH/ZWR0/iaD4dBINcWVfnXEbRc867/wVJ8pqvuP48iXa3CSl74tfFRZZpswN/ZQeQy96vrs3elS7+HsTjlJJB3I2VIbkHkSldvdrUWqMdzQxvHSws1zoQB0jbNFIpbKggaivBqxU2UhK1GjlTJFKk6Qq3o0wtPVPmn3iSZQqI1HkwS+YxtWJGMPUfQyoon4GUxaNo8jifvQkX0eZYQOCy4sp0EW01LqIcDa3XPK1cS97mY97mb+taYkeuosO1YwehsnDZ9Ht2tWSlb3hXQZP1wGoolcjUSiwdzyu7Irw0NRVLcCPeqrUnll97f+F/ky/XN9ev/x34c/JPb3h3aBIlDgwTPlQSvZUkyhE+JLCJYiq17uHuFvawNXZlTO6vfru6friCzHy7UBKxBeGnVCwJicAk259Q0k4fZ88ZMYzbVLyoxo8omJoKW2qGY8AnhiPMkoBe9lyw1vRQwXrXM/JnwJDhAuaADcjkAQncgSVisosfzYzJspi5NKB1zOwOS4Dgzxty++ptodl0JUZ6rcQuZxW2XYldk7uRZHQBQ6P+LUrG0TQ9NkhVv5+8u0jQFhgFqZEgMwHv1SY0jRmx3jbB5kGdbW2CLXk/AkMHQ4hvNxTB7fBCpS46bgxb6LUlZpGy5HjmliK4lN38Ro5kgBJDt0gEejc1ghtIYEeS9NYExEGcgPCbr10LCISwv6winWieAGF5b7EO4VTYdglwa+TGOrhNiHubRWVD3EfGZiduujWFHa0NibutISFYsSGBEPmX68uzv+8uvvWu7+/WmpHWUy8UmgoLNTAVUlMsLAQIr386hcqgCbsN7YhmoLJl6sNoYytGI00ZbWGtGM2em7OzkPtbbh0oNJ+8o9UUVO4MQGKmWpFSSXDNWlYqszHk5GqlVOy5eeflpHd+AXflmOuSks0PwyCMhrE/4UKh0mc7xET6aCcmvHPTUD3trtTTbBPf3UTZqhIy1Cog88Lr3Re98RSXt+mNwyCjJp5qLwy69L/e+/NfF77bN5KT5Oar+/PsEIqk4pTmPUSNmWtdFGIhsW1Vi4jwaSDarza/eCv/QT/O74X/AGH2Tnd/FboBiMM4XATdAKm7vESw6OtuXpVGvmbTyFdWFj/hEgdcHg7rGLo0xSH1372r9KUdpiQ6eYzTV0P66tPp8dVp7/I/QOjeZ1QA/K2mJaKdRQUWtMU+vWo/0LGWdb198Eqswojz34nB3aLr0k+4jbl/rpfSVYFJSm02tdW0xCQXjUPjyHNI7hzvKGbY4cwNaZhwfxzH/mvhtGd6wmz9F/HJyh7XLqD6dMRSmNadjz22M7TmivTF4pG569nzR09Ps2BXTRocns7/5z39djYP/zg++/H8W2B+XspBQZNm6U3TI58GwWOqIP0Arn1UFi79xyAsq4MfjofT9HU/FdFsmaPryrjvh8f5B5PxYLDQvGA2/kXL5XLhzvmT3pycHJAzobhXGwJ+BVt2zci/5aDYl2Kd3BJSZtOOUpzf5ZC7ohVmVip1sSR+PB3SDHZj/vxGIxKiugLR8vbF29g27JeR0WEJoEyxxWo9TNmN+2sSIbJo4iNmOAD7fJYlMWQQujQsU1p/CKFlHWOWsh4K8NrWsTVxBOLSmBCyrU48PGQ45W9iCVPrfDZwASKowmdrq8QTK03s2AvZlNTABMim52ormkiGaJpKzKYqMbNlQSm8P2s5nqZixp6sWylTYgCVGbOm6IocZ5Y9d7Hn4XzymAWQ0VP6n6csnJy98dJGvs+Q8tJGRy28eeQ6ZAPPoLqDiX6hJ2m6De3oFXoSuPWBCzoKJGaZIsri0H4YzQdvQWER4mo/V2uXjGxSsSfv7rvOtq1mgpodMeX0yrUncLPJpOshXRStD31bu0LKVTfFIOwbXyG9hiuk3TpwtJvqekB10VJj37XCIstuWNfamcayJ9qPbmYy1IxhDrV7IGbr+ZDbQQqIr+FpF4YS/naYvfUp5TE2aHN+TbaqK8W9na1q7NklyueSsy0Y1f3eNJPtAt8I86ImURzA1LsPvwpjy1RtpZGaDQk9EtRtgd8jplLraPFuTZGh3/P9+uLqrnfz97fru4vr9UVu7Y9GeHrC/b5Iywb2o006zRQxwYQKmUMQhILivGNtcgSouJBIygp9Kh+7oEy3pzfXl5cSlcjtB2IlenQJLaaTqUSG8jYXzPd5n1rUtPenpxeM5sCCuduHi+9woFZ3rWL8wH0SapHdd4PHpy61yOb2UgnyVCuREny6bWVounXj6bXR6sCtm+8XV6dfZPplgb3GL3O8R6PTJYVXBtdSrQyuGizqjeXwOk1LDZ2mAyJ2Ta6xOefFZpFRTaOBtlAPF6Ies5dxqspa4FSVqrA7TmUcpQFXHvDsWglkl6/oDqdy97CF2j5bAlnZnLwlcCzJlgC6v8/jaX+ksyVYt7Jvg1gbyCoj1lYrhoHthJRv2r2ZcOA2RD4LDgLZySv13d50xhyyGnRz6yplTowhvWfc2muMtOmFW3sCqE2IEWzd7lAhBOBxKkIMC6iI3L0d5gy/Tx3BTXVEr+ZD7LlroYOtp4kpRAZ4HXFNiToiJreSHZu2Zb0xTKZXhrMHYbJsPdCwU6fChcXl21eghkrTWVMeT8nC0rbSNJ0xwCyyLkoD85WzBUI/pVG50vBK41oSlUbYUBLauj3qJbq97glp0bR+rv1EyJ1YiCAqsIdNQaX1NG7KejGtm052kcN6GLmylqA8HLScOpu/W86aHcXBLHvdIlYUoAEJHJGJ9WzH9LtMv+ITRzxB44+uICEhi2CnFjXK2bLC2PtpK6GpVLzc6T2+pinrq4yTJpyH88wKRTlv0/bJbJssTlBWoll6eBSoKRreTQPkjatq+Im4yM5rtdqqq6mkkuajIRUqNXL4blXEhGrd2XBI8QAKmOmvehmVEHK0nMIg1gdZOUomX5pp29aRV/hzy7dsr7eyeKWA8JHiGFbraXOVsqNx3VDlc28SxYZvO4pFFt/t2caw/kFqHIuUoOv7rI6Nx2QpK5mofG6+t+zx1dm6Or5tN30VaphXDxN1tuUr9qnwh35tpF9MAfYNs2U31n4OpD7aibDM9s3iwWtq+4YoVjVBYnWlbOuiamuGLkmfF6/SlcSIdyVFyiS1Hh0DtqiCD6RjhVUQYP1K1jo6sBu8CzH1j6B9d9ZLitnXAEOE8HCjpRIYgvhwXvEwo8SY0lqQNxP0EwDBSwz6hW2vFA0GkJ6rXdUQpLYvGm5dNZvyLIyDl1/Ww9N19Pvk9vPl+P7YOFe06SbdAnPU7pbvQkKvqT6Ts/bCpXdNe5itE/IVdn/h67o0aKzMspvfpSVkzke9g6rJZjbf6wERVNrMbnIFaXf7W7h0qE2QUOv5ioRKSCRleUSVj928y932JVHqmtgBC6y+cy+GW8R7lKquiSXHTWuyHGV5m+LnhhknFGow6rrwaooftZxK0pjVu/V1LnQCRqyGu+OF3OSW5apezx01Fq4krjRcQsf2C3wOkfL2CyaMilQDy6ktMMyycfCwBtbBbGodGk++XVkH1zRbtg7Qb+9exU2o4h3NtdZQt3kUmNiKVduCu+ZLbvRTbaUy0R/56ZG3bnYdm3fNVbMGOuZnvZPr+6vTXnr088XVee8mfXF5fX5xChgzexlPQn8aZCT24yS3qNTihbQf1fdoNs5yAQVNqC65E5bNqGrbVj1GSRJNOmQSBq1XMeSSbQrYZFbxKf++G9oFazpMf+vqCy2+ib9ol1ckF3zKhB+mNJv6SXBCF8EZEI8WTKva4fVqwrZK1aldrkWD6sUn6hW3CQbV31I1Tw8NgseUo30qw7TWI4amQUWlR6sGv9pcNl+M8REpm3wRGOMIdLuzDA6CVWhw61olyGsS/1xleU2Vz11cccvapE3llI76hG0NFUofdLO17YHdlJPpXL1yKsufFz+OGKrUh5Gbl4vLYqRevguBIad4Lrn+kWdLhtPygOEkioNPwTjq0+M08rxMj53e39z0ru7SV+e927v7m/VTP1S0odKRv8Th+CsKIkmDILI9/kJX52I4zUb3GcloPDtYDVbNtZA+xXSQ8TlDE8fT7FR6fOZPgsUHCWyGn9IoKXOwzJlplKEURTbmh5p3yRaJTNnOd8dbh9fdZZWFjKIKcRITtLBwoZwOjuM4eqH0Df3ZbNxft8p1GqHXB95Nq4wK1BZpEju26+wCYKk9jotrWs+DO7ngTg53p45TgIna8XUabu2S1rd2u93GNTE/EaViG7et3Crohu/HyF4m7u2M7HVZzUhOeVZ7o8XMXvGiACNhn16lTwAlOVFONKBbfKJegbANd+Nn0UQ8hUjb5ne7cYR5DxtsnjseQhqpqDht9Z009mrMfDGV9EiGxmDxtSSsvoI02TUomPRVt1KkW1l1XeTuOGhIwjILGdRReovCLvV0AldJ9kXjT+ROCPoIZtZ4LfsSzEB7KsGcQp94P4IZu9VghhBTe7O6bnhI7+oM8Ol9jg5ZZazlCrRMeVIGRDJE611W99lNsyAaRzNy4ksHejBr40s9rCETs3acTMspz7bUHtkRzB/XDNnZfGtcjua1P7p6p7YQrFvrfjixEpgmplI3U4Z39ldZp+9u4//GvYE0if/XbahuZZpNVKL4HoDucJu9q2IXdeO3ABogGvQoFQ1gK/h+GFIZaIAjaGItEw2A29+2MNqv2/zeeIvU5Js/GUbJTNdfIQOHgB7cfuAQTNHawSEczNl3nXZsKtUKjGfUDJZQujpwsITXtOlQd7AEhP2gjjXOj+oy1KntJ9F0L0xOdpTLucTLKufNk6O4G5nNloe27LFAHt6N/1DVLGhfNhNgu00T1yz7hB8NsfEVMhwFExb+ZfUstR1b9AgHGbTYjrvAquVeS3fSwlsQ/3rYdVV1CYssyGcno4KUFbBUPbaMmF5dpzLCtzc3Cazlk9o0FylumisrWbEy6al+fr2ytn6Vzw32be+/nx3faVU5pHDrFnlcX0Bb0NaisxhJzDglCTVta03Ttnwe1ktrIB60gBX00xqFyALQGkdQNSlXa5hE7LfWNN0+7Wh4wuYzdi2uksryZDQZhns7NR1rlaqpOlcS9IA2RW0huip/FeupNnNRpW++V85aqB/KoMfmO3L48ATna2anKo8h+rJPQrN1p66OwUWzqfTJ2pxEHg8GIoMzRWuQ7I33Jy2+7SBCNbAjf4UU2BGGcWyK8OzZn5Y0wP53HtEP+os15piyY/jof0pvkf6bfr8hfPWfA7wQLYP2Zzh88ifj8HVx+SSaRrNs5SudsmiPRE8wnn8uP3r0+/8MMxU7LD/BJ0z7O+Vfh2mvPPaa0C9nj72aiUwyoUpX2tG3aBCE9EAvOxpH6ZnLd4yCJKNheuSMvqY3J5RKJOVM3bloeS5Tqq1ug1e3WTBq+UmGDpMlPszOWjBtedYKJ04PLQwO/QxlbxdoMX2f48X0YBkxph/mmDH9cIUa0w+M7BjTh8VXEkplcpZ9Unj2hWshok4RJRaQCFBveemScCsjQahKrWhnIuvIdm2cOpOG59J6FnbT18L9DAMdGcR1sUmwZyEaJbPT/NnqvGHhW3jmZW+XHCweLMtVfh4QQDsf0v15oXnLCd4f2vihjR/aKFcbS7tuaxRT4B9qshnXbkcENkuCtThavNvREzvkruhuc47lluqcgyWDjd6OtWAs7ceTxzmYhKW8/mE/onkWeGkCe7O04f3Y4dtmNqMERksqMWsJtjFIdbSLPZdUXtFRvAvxwUUNnPGJ9dfWeUlYzthoZUkwHKfEAtzOAmHKWh/YA0tI2FA43BOg7KLhnnKnHKutwlCbsCEaE1Y1cVaTJVgwgOv4z4tbwEiVW1kqJ+g63Gq07EijbCvLhNZtwTGDYjynBlyn3invHDD9WNQfQS7v1Axs0WPP0RSkGZzvUuMgKUiB2/43vdve3Vo1S7L/1SlOPuvBOMLcn0CJ9Buexe+XmYINfkugWW3MfRAX1Kltpac2/meU3jPNYo/9oVkFzVoOONNGs6CHeNk7F9Y7vtEZdC5fW+QKHAnbEzCFlRS9kSF0QpuCIHRyeydKWg2azm+HjKwWzOa9+znVapg92kbALCYddC16f2STNjozgJ3Rlu+OYkm0W2Liwsblp9F0kBkYH+4WNIaAuqMgp/RLikrAc4QUFJSv3Y0zUDT4EUxVDUaTZR0wEkiwyDx0JsEYSrAOA3g6YwDfiEO06HWV3S9kgKAJ5dKEVCxvjBn9MJoPFBoUnp4ig9LZgiduvwp9hS9ROIDGuBSYbdgmmQTuwBL59C5+NG1x5ntLFOcrxLHR0Ibw7Q7aozjsH7ageD7caRIJhXkXBgQoZYEjYoBnO6YvlwEiN0QuA6AR/z6e9ketknyroqyOSC6cASqV5Db0W25fxs+wo+lOZmab6tGuSI6VkxwmU2Xbv9meawc2Zqvypo6or9zECEYQ3PbjSJAStRPJt9nK6YjkrkSSh3Hw8st6eLqOfp/cfr4c3x8b54eQ4qqmDG+RlLTbjjkHHm8HYwuJ2rjlARELS+uoddVTFlj/QHOPjedsVVfR4VOQ9dOMJ+v3TvluIJ4NQ4eusAgh1WHKJ8u/HiG+JoJC9iUWsOICrm4B4ULhQvbZS/5T6KfTKJ5QnIivTHigAMgkS4PrR9On+SyblLoUAHqnOD8yy62wMZ6mMWMafL8uSh7SV9ELlXSabpzE/nSWXjPJfPL0P9F0mC6dw/L12amFb1nmni9+bJkA6eEiVTh53H5AK60CoU9mnpHVu7vMUh3idStKlIrnU5g11huNB4NgCsxeZ1JscoiaZ7lw3RDh9qgKt18jxwd5BUEBXF/VDpi9/wM=</diagram></mxfile>"><defs/><g><ellipse cx="799" cy="107" rx="60" ry="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 107px; margin-left: 740px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">NONE</div></div></div></foreignObject><text x="799" y="111" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">NONE</text></switch></g><path d="M 799 147 L 799 180.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 799 185.88 L 795.5 178.88 L 799 180.63 L 802.5 178.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 739 432.56 Q 774 442.56 809 432.56 Q 844 422.56 879 432.56 L 879 471.44 Q 844 461.44 809 471.44 Q 774 481.44 739 471.44 L 739 432.56 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 452px; margin-left: 740px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FINGER_DETECTED</div></div></div></foreignObject><text x="809" y="456" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">FINGER_DETECTED</text></switch></g><path d="M 799 377 L 799 402 L 800 402 L 800.03 429.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 800.04 434.88 L 796.53 427.89 L 800.03 429.63 L 803.53 427.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 406px; margin-left: 800px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">yes</div></div></div></foreignObject><text x="800" y="409" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 839 337 L 959 337 L 959 710.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 959 715.88 L 955.5 708.88 L 959 710.63 L 962.5 708.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 467px; margin-left: 959px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">no</div></div></div></foreignObject><text x="959" y="470" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 799 297 L 839 337 L 799 377 L 759 337 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 337px; margin-left: 760px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Gestures enabled?</div></div></div></foreignObject><text x="799" y="341" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Gestures enab...</text></switch></g><path d="M 799 267 L 799 290.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 799 295.88 L 795.5 288.88 L 799 290.63 L 802.5 288.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 797.94 475 L 798.84 510.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 798.97 515.88 L 795.3 508.97 L 798.84 510.63 L 802.29 508.8 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 739 647 L 635.37 647" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 630.12 647 L 637.12 643.5 L 635.37 647 L 637.12 650.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="799" cy="647" rx="60" ry="40" fill="#f5f5f5" stroke="#666666" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 647px; margin-left: 740px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">UNKNOWN</div></div></div></foreignObject><text x="799" y="651" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">UNKNOWN</text></switch></g><path d="M 739 517 L 839 517 L 859 542 L 839 567 L 739 567 L 759 542 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 542px; margin-left: 740px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> Start hold timer</div></div></div></foreignObject><text x="799" y="546" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Start hold timer</text></switch></g><path d="M 799 567 L 799 600.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 799 605.88 L 795.5 598.88 L 799 600.63 L 802.5 598.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 799 717 L 839 757 L 799 797 L 759 757 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 757px; margin-left: 760px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Motion detected?</div></div></div></foreignObject><text x="799" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Motion detect...</text></switch></g><path d="M 799 687 L 799 710.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 799 715.88 L 795.5 708.88 L 799 710.63 L 802.5 708.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 839 757 L 912.63 757" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 917.88 757 L 910.88 760.5 L 912.63 757 L 910.88 753.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 757px; margin-left: 879px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">yes</div></div></div></foreignObject><text x="879" y="760" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 759 757 L 715.37 757" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 710.12 757 L 717.12 753.5 L 715.37 757 L 717.12 760.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 757px; margin-left: 734px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">no</div></div></div></foreignObject><text x="734" y="760" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 589 732 L 689 732 L 709 757 L 689 782 L 589 782 L 609 757 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 757px; margin-left: 590px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Hold timeout</div></div></div></foreignObject><text x="649" y="761" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Hold timeout</text></switch></g><path d="M 609 757 L 555.37 757" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 550.12 757 L 557.12 753.5 L 555.37 757 L 557.12 760.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 409 737.56 Q 444 747.56 479 737.56 Q 514 727.56 549 737.56 L 549 776.44 Q 514 766.44 479 776.44 Q 444 786.44 409 776.44 L 409 737.56 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 757px; margin-left: 410px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">HOLD_TIMEOUT</div></div></div></foreignObject><text x="479" y="761" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD_TIMEOUT</text></switch></g><path d="M 149 797 L 149 850.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 149 855.88 L 145.5 848.88 L 149 850.63 L 152.5 848.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 149 717 L 149 683.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 149 678.12 L 152.5 685.12 L 149 683.37 L 145.5 685.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="149" cy="757" rx="60" ry="40" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 757px; margin-left: 90px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">HOLD</div></div></div></foreignObject><text x="149" y="761" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD</text></switch></g><path d="M 259 757 L 215.37 757" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 210.12 757 L 217.12 753.5 L 215.37 757 L 217.12 760.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 249 787 L 269 727 L 369 727 L 349 787 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 757px; margin-left: 250px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">HOLD_BEGIN</div></div></div></foreignObject><text x="309" y="761" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD_BEGIN</text></switch></g><path d="M 409 757 L 365.37 757" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 360.12 757 L 367.12 753.5 L 365.37 757 L 367.12 760.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 189 897 L 292.63 897" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 297.88 897 L 290.88 900.5 L 292.63 897 L 290.88 893.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 897px; margin-left: 244px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">yes</div></div></div></foreignObject><text x="244" y="900" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 109 897 L 69 897 L 69 757 L 82.63 757" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 87.88 757 L 80.88 760.5 L 82.63 757 L 80.88 753.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 837px; margin-left: 69px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">no</div></div></div></foreignObject><text x="69" y="840" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 149 857 L 189 897 L 149 937 L 109 897 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 897px; margin-left: 110px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Motion detected?</div></div></div></foreignObject><text x="149" y="901" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Motion detect...</text></switch></g><path d="M 609 897 L 959 897 L 959 803.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 959 798.12 L 962.5 805.12 L 959 803.37 L 955.5 805.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 499 927 L 519 867 L 619 867 L 599 927 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 897px; margin-left: 500px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">HOLD_END<br />(CANCEL)</div></div></div></foreignObject><text x="559" y="901" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD_END...</text></switch></g><path d="M 149 597 L 149 554.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 149 549.12 L 152.5 556.12 L 149 554.37 L 145.5 556.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 572px; margin-left: 149px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">all</div></div></div></foreignObject><text x="149" y="575" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">all</text></switch></g><path d="M 109 637 L 39 637 L 39 1827 L 2984 1827 L 2984 953.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 2984 948.12 L 2987.5 955.12 L 2984 953.37 L 2980.5 955.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 680px; margin-left: 43px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">some (debounce)</div></div></div></foreignObject><text x="43" y="683" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">some (debounce)</text></switch></g><path d="M 149 597 L 189 637 L 149 677 L 109 637 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 637px; margin-left: 110px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Finger up?</div></div></div></foreignObject><text x="149" y="641" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Finger up?</text></switch></g><path d="M 149 487 L 149 107 L 512.63 107" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 517.88 107 L 510.88 110.5 L 512.63 107 L 510.88 103.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 89 547 L 109 487 L 209 487 L 189 547 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 517px; margin-left: 90px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">HOLD_END</div></div></div></foreignObject><text x="149" y="521" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD_END</text></switch></g><path d="M 999 757 L 1069 757 L 1069 1557 L 1123.1 1557" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1128.35 1557 L 1121.35 1560.5 L 1123.1 1557 L 1121.35 1553.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 999 757 L 1069 757 L 1069 1157 L 1122.63 1157" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1127.88 1157 L 1120.88 1160.5 L 1122.63 1157 L 1120.88 1153.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 999 757 L 1069 757 L 1069 526 L 1122.93 526" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1128.18 526 L 1121.18 529.5 L 1122.93 526 L 1121.18 522.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 999 757 L 1122.63 757" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1127.88 757 L 1120.88 760.5 L 1122.63 757 L 1120.88 753.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 959 717 L 999 757 L 959 797 L 919 757 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 757px; margin-left: 920px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Number of fingers?</div></div></div></foreignObject><text x="959" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Number of fin...</text></switch></g><path d="M 1234 1157 L 1292.63 1157" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1297.88 1157 L 1290.88 1160.5 L 1292.63 1157 L 1290.88 1153.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1159 1137 C 1135 1137 1129 1157 1148.2 1161 C 1129 1169.8 1150.6 1189 1166.2 1181 C 1177 1197 1213 1197 1225 1181 C 1249 1181 1249 1165 1234 1157 C 1249 1141 1225 1125 1204 1133 C 1189 1121 1165 1121 1159 1137 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1157px; margin-left: 1130px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">2 fingers</div></div></div></foreignObject><text x="1189" y="1161" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">2 fingers</text></switch></g><path d="M 1234 757 L 1322.63 757" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1327.88 757 L 1320.88 760.5 L 1322.63 757 L 1320.88 753.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1159 737 C 1135 737 1129 757 1148.2 761 C 1129 769.8 1150.6 789 1166.2 781 C 1177 797 1213 797 1225 781 C 1249 781 1249 765 1234 757 C 1249 741 1225 725 1204 733 C 1189 721 1165 721 1159 737 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 757px; margin-left: 1130px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">3 or 4 fingers</div></div></div></foreignObject><text x="1189" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">3 or 4 fingers</text></switch></g><path d="M 1234 1552 L 1292.63 1552" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1297.88 1552 L 1290.88 1555.5 L 1292.63 1552 L 1290.88 1548.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1159 1532 C 1135 1532 1129 1552 1148.2 1556 C 1129 1564.8 1150.6 1584 1166.2 1576 C 1177 1592 1213 1592 1225 1576 C 1249 1576 1249 1560 1234 1552 C 1249 1536 1225 1520 1204 1528 C 1189 1516 1165 1516 1159 1532 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1552px; margin-left: 1130px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">1 finger</div></div></div></foreignObject><text x="1189" y="1556" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">1 finger</text></switch></g><path d="M 1189 482 L 1189 107 L 1085.37 107" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1080.12 107 L 1087.12 103.5 L 1085.37 107 L 1087.12 110.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 466px; margin-left: 1188px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">(to NONE)</div></div></div></foreignObject><text x="1188" y="469" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">(to NONE)</text></switch></g><path d="M 1159 502 C 1135 502 1129 522 1148.2 526 C 1129 534.8 1150.6 554 1166.2 546 C 1177 562 1213 562 1225 546 C 1249 546 1249 530 1234 522 C 1249 506 1225 490 1204 498 C 1189 486 1165 486 1159 502 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 522px; margin-left: 1130px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">5 or more<br />fingers</div></div></div></foreignObject><text x="1189" y="526" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">5 or more...</text></switch></g><path d="M 1439 1552 L 1482.63 1552" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1487.88 1552 L 1480.88 1555.5 L 1482.63 1552 L 1480.88 1548.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1299 1532.56 Q 1334 1542.56 1369 1532.56 Q 1404 1522.56 1439 1532.56 L 1439 1571.44 Q 1404 1561.44 1369 1571.44 Q 1334 1581.44 1299 1571.44 L 1299 1532.56 Z" fill="#fff2cc" stroke="#d6b656" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 1552px; margin-left: 1300px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">POINTER_MOTION</div></div></div></foreignObject><text x="1369" y="1556" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">POINTER_MOTION</text></switch></g><path d="M 1439 1157 L 1482.63 1157" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1487.88 1157 L 1480.88 1160.5 L 1482.63 1157 L 1480.88 1153.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1299 1137.56 Q 1334 1147.56 1369 1137.56 Q 1404 1127.56 1439 1137.56 L 1439 1176.44 Q 1404 1166.44 1369 1176.44 Q 1334 1186.44 1299 1176.44 L 1299 1137.56 Z" fill="#f8cecc" stroke="#b85450" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 1157px; margin-left: 1300px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">SCROLL</div></div></div></foreignObject><text x="1369" y="1161" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">SCROLL</text></switch></g><path d="M 1809 591 L 1829 591 L 1819 591 L 1842.63 591" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1847.88 591 L 1840.88 594.5 L 1842.63 591 L 1840.88 587.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1669 571.56 Q 1704 581.56 1739 571.56 Q 1774 561.56 1809 571.56 L 1809 610.44 Q 1774 600.44 1739 610.44 Q 1704 620.44 1669 610.44 L 1669 571.56 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 591px; margin-left: 1670px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">SWIPE</div></div></div></foreignObject><text x="1739" y="595" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">SWIPE</text></switch></g><path d="M 1809 921 L 1829 921 L 1819 921 L 1842.63 921" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1847.88 921 L 1840.88 924.5 L 1842.63 921 L 1840.88 917.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1669 901.56 Q 1704 911.56 1739 901.56 Q 1774 891.56 1809 901.56 L 1809 940.44 Q 1774 930.44 1739 940.44 Q 1704 950.44 1669 940.44 L 1669 901.56 Z" fill="#ffe6cc" stroke="#d79b00" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 921px; margin-left: 1670px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">PINCH</div></div></div></foreignObject><text x="1739" y="925" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">PINCH</text></switch></g><path d="M 1529 717 L 1529 591 L 1662.63 591" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1667.88 591 L 1660.88 594.5 L 1662.63 591 L 1660.88 587.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 592px; margin-left: 1583px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">swipe</div></div></div></foreignObject><text x="1583" y="595" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">swipe</text></switch></g><path d="M 1529 797 L 1529 921 L 1662.63 921" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1667.88 921 L 1660.88 924.5 L 1662.63 921 L 1660.88 917.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 922px; margin-left: 1574px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">pinch</div></div></div></foreignObject><text x="1574" y="925" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">pinch</text></switch></g><path d="M 1529 717 L 1569 757 L 1529 797 L 1489 757 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 757px; margin-left: 1490px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Gesture<br />type?</div></div></div></foreignObject><text x="1529" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Gesture...</text></switch></g><path d="M 2109 591 L 2152.63 591" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 2157.88 591 L 2150.88 594.5 L 2152.63 591 L 2150.88 587.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="2049" cy="591" rx="60" ry="40" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 591px; margin-left: 1990px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">SWIPE</div></div></div></foreignObject><text x="2049" y="595" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">SWIPE</text></switch></g><path d="M 2109 921 L 2152.63 921" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 2157.88 921 L 2150.88 924.5 L 2152.63 921 L 2150.88 917.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="2049" cy="921" rx="60" ry="40" fill="#ffe6cc" stroke="#d79b00" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 921px; margin-left: 1990px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">PINCH</div></div></div></foreignObject><text x="2049" y="925" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">PINCH</text></switch></g><path d="M 1949 591 L 1979 591 L 1969 591 L 1982.63 591" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1987.88 591 L 1980.88 594.5 L 1982.63 591 L 1980.88 587.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1839 621 L 1859 561 L 1959 561 L 1939 621 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 591px; margin-left: 1840px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">SWIPE_BEGIN</div></div></div></foreignObject><text x="1899" y="595" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">SWIPE_BEGIN</text></switch></g><path d="M 1949 921 L 1979 921 L 1969 921 L 1982.63 921" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1987.88 921 L 1980.88 924.5 L 1982.63 921 L 1980.88 917.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1839 951 L 1859 891 L 1959 891 L 1939 951 Z" fill="#ffe6cc" stroke="#d79b00" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 921px; margin-left: 1840px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">PINCH_BEGIN</div></div></div></foreignObject><text x="1899" y="925" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">PINCH_BEGIN</text></switch></g><path d="M 379 1027 L 559 1027 L 559 933.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 559 928.12 L 562.5 935.12 L 559 933.37 L 555.5 935.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1027px; margin-left: 519px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">yes</div></div></div></foreignObject><text x="519" y="1030" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 299 1027 L 215.37 1027" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 210.12 1027 L 217.12 1023.5 L 215.37 1027 L 217.12 1030.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1027px; margin-left: 254px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">no</div></div></div></foreignObject><text x="254" y="1030" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 339 987 L 379 1027 L 339 1067 L 299 1027 Z" fill="#e1d5e7" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 1027px; margin-left: 300px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Motion<br />> hold threshold?</div></div></div></foreignObject><text x="339" y="1031" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Motion...</text></switch></g><path d="M 379 897 L 502.63 897" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 507.88 897 L 500.88 900.5 L 502.63 897 L 500.88 893.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 897px; margin-left: 444px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">no</div></div></div></foreignObject><text x="444" y="900" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 339 937 L 339 980.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 339 985.88 L 335.5 978.88 L 339 980.63 L 342.5 978.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 962px; margin-left: 339px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">yes</div></div></div></foreignObject><text x="339" y="965" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 339 857 L 379 897 L 339 937 L 299 897 Z" fill="#e1d5e7" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 897px; margin-left: 300px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">1 finger?</div></div></div></foreignObject><text x="339" y="901" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">1 finger?</text></switch></g><path d="M 1779 1627 L 1779 1712 L 1665.37 1712" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1660.12 1712 L 1667.12 1708.5 L 1665.37 1712 L 1667.12 1715.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1719 1577 L 1819 1577 L 1839 1602 L 1819 1627 L 1719 1627 L 1739 1602 Z" fill="#e1d5e7" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1602px; margin-left: 1720px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Hold timeout</div></div></div></foreignObject><text x="1779" y="1606" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Hold timeout</text></switch></g><path d="M 1439 1712 L 1335.37 1712" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1330.12 1712 L 1337.12 1708.5 L 1335.37 1712 L 1337.12 1715.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1712px; margin-left: 1384px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">yes</div></div></div></foreignObject><text x="1384" y="1715" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 1479 1672 L 1479 1632 L 1549 1632 L 1549 1598.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1549 1593.12 L 1552.5 1600.12 L 1549 1598.37 L 1545.5 1600.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1632px; margin-left: 1514px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">no</div></div></div></foreignObject><text x="1514" y="1635" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 1479 1672 L 1519 1712 L 1479 1752 L 1439 1712 Z" fill="#e1d5e7" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 1712px; margin-left: 1440px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Motion<br />< hold threshold?</div></div></div></foreignObject><text x="1479" y="1716" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Motion...</text></switch></g><path d="M 149 987 L 149 943.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 149 938.12 L 152.5 945.12 L 149 943.37 L 145.5 945.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="149" cy="1027" rx="60" ry="40" fill="#e1d5e7" stroke="#9673a6" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1027px; margin-left: 90px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">HOLD_AND_MOTION</div></div></div></foreignObject><text x="149" y="1031" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD_AND_MOTION</text></switch></g><path d="M 149 1287 L 149 1073.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 149 1068.12 L 152.5 1075.12 L 149 1073.37 L 145.5 1075.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 89 1347 L 109 1287 L 209 1287 L 189 1347 Z" fill="#e1d5e7" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1317px; margin-left: 90px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">HOLD_BEGIN</div></div></div></foreignObject><text x="149" y="1321" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD_BEGIN</text></switch></g><path d="M 1209 1712 L 149 1712 L 149 1353.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 149 1348.12 L 152.5 1355.12 L 149 1353.37 L 145.5 1355.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1209 1692.56 Q 1244 1702.56 1279 1692.56 Q 1314 1682.56 1349 1692.56 L 1349 1731.44 Q 1314 1721.44 1279 1731.44 Q 1244 1741.44 1209 1731.44 L 1209 1692.56 Z" fill="#e1d5e7" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 1712px; margin-left: 1210px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">HOLD_TIMEOUT</div></div></div></foreignObject><text x="1279" y="1716" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">HOLD_TIMEOUT</text></switch></g><path d="M 1579 1712 L 1525.37 1712" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1520.12 1712 L 1527.12 1708.5 L 1525.37 1712 L 1527.12 1715.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1712px; margin-left: 1549px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">yes</div></div></div></foreignObject><text x="1549" y="1715" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 1619 1672 L 1619 1632 L 1549 1632 L 1549 1598.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1549 1593.12 L 1552.5 1600.12 L 1549 1598.37 L 1545.5 1600.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1632px; margin-left: 1584px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">no</div></div></div></foreignObject><text x="1584" y="1635" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 1619 1672 L 1659 1712 L 1619 1752 L 1579 1712 Z" fill="#e1d5e7" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 1712px; margin-left: 1580px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Gestures enabled?</div></div></div></foreignObject><text x="1619" y="1716" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Gestures enab...</text></switch></g><path d="M 1609 1157 L 1662.63 1157" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1667.88 1157 L 1660.88 1160.5 L 1662.63 1157 L 1660.88 1153.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1549 1117 L 1549 1093.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1549 1088.12 L 1552.5 1095.12 L 1549 1093.37 L 1545.5 1095.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="1549" cy="1157" rx="60" ry="40" fill="#f8cecc" stroke="#b85450" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1157px; margin-left: 1490px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">SCROLL</div></div></div></foreignObject><text x="1549" y="1161" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">SCROLL</text></switch></g><path d="M 1607.09 1562 L 1669 1562 L 1669 1602 L 1732.63 1602" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1737.88 1602 L 1730.88 1605.5 L 1732.63 1602 L 1730.88 1598.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1549 1512 L 1549 1492 L 1549 1502 L 1549 1488.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1549 1483.12 L 1552.5 1490.12 L 1549 1488.37 L 1545.5 1490.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="1549" cy="1552" rx="60" ry="40" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1552px; margin-left: 1490px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">POINTER_MOTION</div></div></div></foreignObject><text x="1549" y="1556" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">POINTER_MOTION</text></switch></g><path d="M 1409 757 L 1482.63 757" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1487.88 757 L 1480.88 760.5 L 1482.63 757 L 1480.88 753.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 757px; margin-left: 1449px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">yes</div></div></div></foreignObject><text x="1449" y="760" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 1369 717 L 1369 107 L 1085.37 107" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1080.12 107 L 1087.12 103.5 L 1085.37 107 L 1087.12 110.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 679px; margin-left: 1369px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">no (to NONE)</div></div></div></foreignObject><text x="1369" y="682" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">no (to NONE)</text></switch></g><path d="M 1369 717 L 1409 757 L 1369 797 L 1329 757 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 757px; margin-left: 1330px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Gestures enabled?</div></div></div></foreignObject><text x="1369" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Gestures enab...</text></switch></g><path d="M 589 607 L 589 369.5 L 589.41 134.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 589.42 129.12 L 592.91 136.12 L 589.41 134.37 L 585.91 136.11 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 567px; margin-left: 589px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">yes</div></div></div></foreignObject><text x="589" y="570" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 589 607 L 629 647 L 589 687 L 549 647 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 647px; margin-left: 550px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Finger up?</div></div></div></foreignObject><text x="589" y="651" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Finger up?</text></switch></g><path d="M 799 187 L 839 227 L 799 267 L 759 227 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 227px; margin-left: 760px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Finger count changed?</div></div></div></foreignObject><text x="799" y="231" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Finger count...</text></switch></g><path d="M 2669 567 L 2669 567 L 3299 567 L 3299 567" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 2669 567 L 2669 947 L 3299 947 L 3299 567" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px"><text x="2983.5" y="561.5">DEBOUNCE FINGER LOGIC</text></g><path d="M 2891.5 757 L 2945.13 757" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 2950.38 757 L 2943.38 760.5 L 2945.13 757 L 2943.38 753.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 2721.5 732 L 2871.5 732 L 2891.5 757 L 2871.5 782 L 2721.5 782 L 2741.5 757 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 168px; height: 1px; padding-top: 757px; margin-left: 2723px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Start debounce timer</div></div></div></foreignObject><text x="2807" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Start debounce timer</text></switch></g><path d="M 3101.5 757 L 3155.13 757" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 3160.38 757 L 3153.38 760.5 L 3155.13 757 L 3153.38 753.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 2931.5 732 L 3081.5 732 L 3101.5 757 L 3081.5 782 L 2931.5 782 L 2951.5 757 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 168px; height: 1px; padding-top: 757px; margin-left: 2933px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Debounce timeout</div></div></div></foreignObject><text x="3017" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Debounce timeout</text></switch></g><path d="M 3201.5 717 L 3201.5 673.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 3201.5 668.12 L 3205 675.12 L 3201.5 673.37 L 3198 675.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 692px; margin-left: 3202px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">yes</div></div></div></foreignObject><text x="3202" y="695" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 3201.5 797 L 3201.5 850.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 3201.5 855.88 L 3198 848.88 L 3201.5 850.63 L 3205 848.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 827px; margin-left: 3202px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">no</div></div></div></foreignObject><text x="3202" y="830" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 3201.5 717 L 3241.5 757 L 3201.5 797 L 3161.5 757 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 757px; margin-left: 3163px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Number of fingers changed?</div></div></div></foreignObject><text x="3202" y="761" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Number of fin...</text></switch></g><path d="M 3126.5 667 L 3146.5 607 L 3276.5 607 L 3256.5 667 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 148px; height: 1px; padding-top: 637px; margin-left: 3128px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">CANCEL CURRENT GESTURE</div></div></div></foreignObject><text x="3202" y="641" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">CANCEL CURRENT GESTURE</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 887px; margin-left: 3143px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Ignore this finger change and stay in the same state</div></div></div></foreignObject><text x="3202" y="891" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Ignore this finger c...</text></switch></g><path d="M 2691.5 757 L 2735.13 757" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 2740.38 757 L 2733.38 760.5 L 2735.13 757 L 2733.38 753.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 3199 607 L 3199 107 L 1085.37 107" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1080.12 107 L 1087.12 103.5 L 1085.37 107 L 1087.12 110.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 584px; margin-left: 3202px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">(to NONE)</div></div></div></foreignObject><text x="3202" y="587" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">(to NONE)</text></switch></g><path d="M 2199 551 L 2199 493.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 2199 488.12 L 2202.5 495.12 L 2199 493.37 L 2195.5 495.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 519px; margin-left: 2199px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">all</div></div></div></foreignObject><text x="2199" y="522" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">all</text></switch></g><path d="M 2239 591 L 2454 591 L 2454 757 L 2662.63 757" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 2667.88 757 L 2660.88 760.5 L 2662.63 757 L 2660.88 753.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 591px; margin-left: 2301px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">some</div></div></div></foreignObject><text x="2301" y="594" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">some</text></switch></g><path d="M 2199 631 L 2199 687 L 2099 687 L 2099 690.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 2099 695.88 L 2095.5 688.88 L 2099 690.63 L 2102.5 688.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 647px; margin-left: 2200px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">no</div></div></div></foreignObject><text x="2200" y="650" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 2199 551 L 2239 591 L 2199 631 L 2159 591 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 591px; margin-left: 2160px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Finger up?</div></div></div></foreignObject><text x="2199" y="595" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Finger up?</text></switch></g><path d="M 2199 427 L 2199 107 L 1085.37 107" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1080.12 107 L 1087.12 103.5 L 1085.37 107 L 1087.12 110.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 396px; margin-left: 2200px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">(to NONE)</div></div></div></foreignObject><text x="2200" y="399" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">(to NONE)</text></switch></g><path d="M 2139 487 L 2159 427 L 2259 427 L 2239 487 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 457px; margin-left: 2140px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">SWIPE_END</div></div></div></foreignObject><text x="2199" y="461" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">SWIPE_END</text></switch></g><path d="M 2239 921 L 2454 921 L 2454 757 L 2662.63 757" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 2667.88 757 L 2660.88 760.5 L 2662.63 757 L 2660.88 753.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 920px; margin-left: 2285px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">some</div></div></div></foreignObject><text x="2285" y="923" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">some</text></switch></g><path d="M 2199 961 L 2199 1010.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 2199 1015.88 L 2195.5 1008.88 L 2199 1010.63 L 2202.5 1008.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 989px; margin-left: 2199px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">all</div></div></div></foreignObject><text x="2199" y="992" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">all</text></switch></g><path d="M 2199 881 L 2199 827 L 2105.37 827" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 2100.12 827 L 2107.12 823.5 L 2105.37 827 L 2107.12 830.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 869px; margin-left: 2202px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">no</div></div></div></foreignObject><text x="2202" y="872" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 2199 881 L 2239 921 L 2199 961 L 2159 921 Z" fill="#ffe6cc" stroke="#d79b00" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 921px; margin-left: 2160px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Finger up?</div></div></div></foreignObject><text x="2199" y="925" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Finger up?</text></switch></g><path d="M 2249 1047 L 3379 1047 L 3379 107 L 1085.37 107" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1080.12 107 L 1087.12 103.5 L 1085.37 107 L 1087.12 110.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1049px; margin-left: 2311px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">(to NONE)</div></div></div></foreignObject><text x="2311" y="1052" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">(to NONE)</text></switch></g><path d="M 2139 1077 L 2159 1017 L 2259 1017 L 2239 1077 Z" fill="#ffe6cc" stroke="#d79b00" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1047px; margin-left: 2140px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">PINCH_END</div></div></div></foreignObject><text x="2199" y="1051" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">PINCH_END</text></switch></g><path d="M 799 7 L 799 60.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 799 65.88 L 795.5 58.88 L 799 60.63 L 802.5 58.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1549 1402 L 1549 1367 L 3539 1367 L 3539 107 L 1085.37 107" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1080.12 107 L 1087.12 103.5 L 1085.37 107 L 1087.12 110.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1367px; margin-left: 1586px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">yes (to NONE)</div></div></div></foreignObject><text x="1586" y="1370" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">yes (to NONE)</text></switch></g><path d="M 1589 1442 L 1672.63 1442" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1677.88 1442 L 1670.88 1445.5 L 1672.63 1442 L 1670.88 1438.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1442px; margin-left: 1634px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">no</div></div></div></foreignObject><text x="1634" y="1445" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 1549 1402 L 1589 1442 L 1549 1482 L 1509 1442 Z" fill="#fff2cc" stroke="#d6b656" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 1442px; margin-left: 1510px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Finger up?</div></div></div></foreignObject><text x="1549" y="1446" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Finger up?</text></switch></g><path d="M 2049 667 L 2049 647 L 2049 651 L 2049 637.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 2049 632.12 L 2052.5 639.12 L 2049 637.37 L 2045.5 639.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1989 727 L 2009 667 L 2109 667 L 2089 727 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 697px; margin-left: 1990px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">SWIPE_UPDATE</div></div></div></foreignObject><text x="2049" y="701" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">SWIPE_UPDATE</text></switch></g><path d="M 2049 857 L 2049 877 L 2049 861 L 2049 874.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 2049 879.88 L 2045.5 872.88 L 2049 874.63 L 2052.5 872.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1989 857 L 2009 797 L 2109 797 L 2089 857 Z" fill="#ffe6cc" stroke="#d79b00" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 827px; margin-left: 1990px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">PINCH_UPDATE</div></div></div></foreignObject><text x="2049" y="831" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">PINCH_UPDATE</text></switch></g><path d="M 1744 1472 L 1744 1542 L 1613.46 1542" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1608.21 1542 L 1615.21 1538.5 L 1613.46 1542 L 1615.21 1545.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1669 1472 L 1689 1412 L 1819 1412 L 1799 1472 Z" fill="#fff2cc" stroke="#d6b656" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 148px; height: 1px; padding-top: 1442px; margin-left: 1670px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">POINTER_MOTION</div></div></div></foreignObject><text x="1744" y="1446" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">POINTER_MOTION</text></switch></g><path d="M 1709 1197 L 1709 1261 L 1620.37 1261" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1615.12 1261 L 1622.12 1257.5 L 1620.37 1261 L 1622.12 1264.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1261px; margin-left: 1693px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">no</div></div></div></foreignObject><text x="1693" y="1264" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">no</text></switch></g><path d="M 1929 1157 L 3459 1157 L 3459 107 L 1085.37 107" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1080.12 107 L 1087.12 103.5 L 1085.37 107 L 1087.12 110.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1154px; margin-left: 1971px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;"><span style="color: rgba(0 , 0 , 0 , 0) ; font-family: monospace ; font-size: 0px ; background-color: rgb(248 , 249 , 250)">%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E</span><span style="color: rgba(0 , 0 , 0 , 0) ; font-family: monospace ; font-size: 0px ; background-color: rgb(248 , 249 , 250)">%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E(to NONE)</span></div></div></div></foreignObject><text x="1971" y="1157" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22(to%20NONE)%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%222314.686274509804%22%20y%3D%221001.0588235294117%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E(to NONE)</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1158px; margin-left: 2248px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">(to NONE)</div></div></div></foreignObject><text x="2248" y="1161" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">(to NONE)</text></switch></g><path d="M 1749 1157 L 1792.63 1157" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1797.88 1157 L 1790.88 1160.5 L 1792.63 1157 L 1790.88 1153.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1157px; margin-left: 1774px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">all</div></div></div></foreignObject><text x="1774" y="1160" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">all</text></switch></g><path d="M 1709 1117 L 1709 1097 L 2984 1097 L 2984 953.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 2984 948.12 L 2987.5 955.12 L 2984 953.37 L 2980.5 955.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 1096px; margin-left: 1780px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">some (debounce)</div></div></div></foreignObject><text x="1780" y="1099" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">some (debounce)</text></switch></g><path d="M 1709 1117 L 1749 1157 L 1709 1197 L 1669 1157 Z" fill="#f8cecc" stroke="#b85450" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 1157px; margin-left: 1670px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Finger up?</div></div></div></foreignObject><text x="1709" y="1161" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Finger up?</text></switch></g><path d="M 1549 1231 L 1549 1211 L 1549 1217 L 1549 1203.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1549 1198.12 L 1552.5 1205.12 L 1549 1203.37 L 1545.5 1205.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1474 1291 L 1494 1231 L 1624 1231 L 1604 1291 Z" fill="#f8cecc" stroke="#b85450" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 148px; height: 1px; padding-top: 1261px; margin-left: 1475px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">AXIS</div></div></div></foreignObject><text x="1549" y="1265" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">AXIS</text></switch></g><path d="M 1789 1187 L 1809 1127 L 1939 1127 L 1919 1187 Z" fill="#f8cecc" stroke="#b85450" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 148px; height: 1px; padding-top: 1157px; margin-left: 1790px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">AXIS (0,0)</div></div></div></foreignObject><text x="1864" y="1161" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">AXIS (0,0)</text></switch></g><path d="M 939 107 L 865.37 107" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 860.12 107 L 867.12 103.5 L 865.37 107 L 867.12 110.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 939 87.56 Q 974 97.56 1009 87.56 Q 1044 77.56 1079 87.56 L 1079 126.44 Q 1044 116.44 1009 126.44 Q 974 136.44 939 126.44 L 939 87.56 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 107px; margin-left: 940px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">RESET</div></div></div></foreignObject><text x="1009" y="111" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">RESET</text></switch></g><path d="M 659 107 L 732.63 107" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 737.88 107 L 730.88 110.5 L 732.63 107 L 730.88 103.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 519 87.56 Q 554 97.56 589 87.56 Q 624 77.56 659 87.56 L 659 126.44 Q 624 116.44 589 126.44 Q 554 136.44 519 126.44 L 519 87.56 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 107px; margin-left: 520px;"><div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">RESET</div></div></div></foreignObject><text x="589" y="111" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">RESET</text></switch></g><path d="M 2849 1927 L 2849 1927 L 3539 1927 L 3539 1927" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 2849 1927 L 2849 2247 L 3539 2247 L 3539 1927" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px"><text x="3193.5" y="1921.5">LEGEND</text></g><ellipse cx="2949" cy="1997" rx="60" ry="40" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1997px; margin-left: 2890px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">STATE</div></div></div></foreignObject><text x="2949" y="2001" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">STATE</text></switch></g><path d="M 3049 1977.56 Q 3084 1987.56 3119 1977.56 Q 3154 1967.56 3189 1977.56 L 3189 2016.44 Q 3154 2006.44 3119 2016.44 Q 3084 2026.44 3049 2016.44 L 3049 1977.56 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 1997px; margin-left: 3050px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">EVENT</div></div></div></foreignObject><text x="3119" y="2001" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">EVENT</text></switch></g><path d="M 3119 2127 L 3159 2167 L 3119 2207 L 3079 2167 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 2167px; margin-left: 3080px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Conditional</div></div></div></foreignObject><text x="3119" y="2171" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Conditional</text></switch></g><path d="M 2889 2142 L 2989 2142 L 3009 2167 L 2989 2192 L 2889 2192 L 2909 2167 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 2167px; margin-left: 2890px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Time event</div></div></div></foreignObject><text x="2949" y="2171" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Time event</text></switch></g><path d="M 3229 2027 L 3249 1967 L 3349 1967 L 3329 2027 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1997px; margin-left: 3230px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">GESTURE</div></div></div></foreignObject><text x="3289" y="2001" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">GESTURE</text></switch></g><path d="M 3259 2147 C 3235 2147 3229 2167 3248.2 2171 C 3229 2179.8 3250.6 2199 3266.2 2191 C 3277 2207 3313 2207 3325 2191 C 3349 2191 3349 2175 3334 2167 C 3349 2151 3325 2135 3304 2143 C 3289 2131 3265 2131 3259 2147 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 2167px; margin-left: 3230px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Condition</div></div></div></foreignObject><text x="3289" y="2171" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Condition</text></switch></g><rect x="3389" y="2132" width="120" height="30" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 2147px; margin-left: 3390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Hold</div></div></div></foreignObject><text x="3449" y="2151" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Hold</text></switch></g><rect x="3389" y="2172" width="120" height="30" fill="#e1d5e7" stroke="#9673a6" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 2187px; margin-left: 3390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Hold and motion</div></div></div></foreignObject><text x="3449" y="2191" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Hold and motion</text></switch></g><rect x="3389" y="2092" width="120" height="30" fill="#ffe6cc" stroke="#d79b00" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 2107px; margin-left: 3390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Pinch</div></div></div></foreignObject><text x="3449" y="2111" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Pinch</text></switch></g><rect x="3389" y="2052" width="120" height="30" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 2067px; margin-left: 3390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Swipe</div></div></div></foreignObject><text x="3449" y="2071" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Swipe</text></switch></g><rect x="3389" y="1972" width="120" height="30" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 1987px; margin-left: 3390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Pointer motion</div></div></div></foreignObject><text x="3449" y="1991" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Pointer motion</text></switch></g><rect x="3389" y="2012" width="120" height="30" fill="#f8cecc" stroke="#b85450" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 2027px; margin-left: 3390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Scroll</div></div></div></foreignObject><text x="3449" y="2031" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Scroll</text></switch></g><path d="M 1549 1007 L 1549 979 L 1899 979 L 1899 957.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1899 952.12 L 1902.5 959.12 L 1899 957.37 L 1895.5 959.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 979px; margin-left: 1724px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; background-color: rgb(255, 255, 255); white-space: nowrap;">yes</div></div></div></foreignObject><text x="1724" y="982" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">yes</text></switch></g><path d="M 1549 1007 L 1589 1047 L 1549 1087 L 1509 1047 Z" fill="#ffe6cc" stroke="#d79b00" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 1047px; margin-left: 1510px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Was pinch?</div></div></div></foreignObject><text x="1549" y="1051" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Was pinch?</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 182px; height: 1px; padding-top: 985px; margin-left: 1334px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 130px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;"><h1><font style="font-size: 12px ; font-weight: normal">We may confuse a pinch for a scroll initially, allow to transform an ongoing scroll into a pinch</font></h1></div></div></div></foreignObject><text x="1334" y="997" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">We may confuse a pinch for a s...</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file
View file
_service:tar_scm:libinput-1.22.1.tar.gz/doc/user/clickpad-with-right-button.rst
Added
@@ -0,0 +1,47 @@ +.. _clickpads_with_right_buttons: + +============================================================================== +Clickpads with a fake right button +============================================================================== + +libinput relies on the kernel to label :ref:`Clickpads <touchpads_buttons_clickpads>` +with the ``INPUT_PROP_BUTTONPAD`` property so it can enable the correct +:ref:`clickpad_softbuttons`. Clickpads are not expected to have a right button +since the whole surface can be depressed. + +A common bug encountered with :ref:`Clickpads <touchpads_buttons_clickpads>` +is that the device advertises a physical right button where no such button +exists. This is usually a bug in the firmware of the device and causes the +following warning to be emitted by libinput:: + + "<device name> clickpad advertising right button" + +The user-visible effect of this is usually negligible since these devices +cannot actually trigger a right click and libinput's default behaviors for +clickpads work as expected. + +However, we should nonetheless correct the device to get rid of this warning +and avoid potential issues with future features. The :ref:`device-quirks` +provide a simple way to disable the fake right button on the device. The +following quirk disables the right button on the MyModel laptop from the +MyVendor OEM:: + + MyVendor MyModel Touchpad + MatchName=Foo Bar Touchpad + MatchUdevtype=touchpad + MatchDMIModAlias=dmi:*svnMyVendor:pnMyModel:* + AttrEventCodeDisable=BTN_RIGHT + +The name of the device can be obtained using :ref:`libinput record <libinput-record>`, +the modalias match is a shell-style glob against the value of ``/sys/class/dmi/id/modalias``. +In most cases, matching should be against ``svn`` (system vendor) and one of +``pn`` (product name) or ``pvr`` (product version), whichever provides a +useful description of the individual laptop model. See the +:ref:`device-quirks` documentation for details on testing local quirks. + +For reference, some example commits that add such a quirk are: + + - `bf61ab9bb0694d0ac3d60a7f815779abfe4886e6 <https://gitlab.freedesktop.org/libinput/libinput/-/commit/bf61ab9bb0694d0ac3d60a7f815779abfe4886e6>`__ + - `74fac6d040ac62048882dfb6f73da567ace6a6f5 <https://gitlab.freedesktop.org/libinput/libinput/-/commit/74fac6d040ac62048882dfb6f73da567ace6a6f5>`__ + - `89cd0f990e3bee9906754d6ca8484ed5aa392249 <https://gitlab.freedesktop.org/libinput/libinput/-/commit/89cd0f990e3bee9906754d6ca8484ed5aa392249>`__ +
View file
_service:tar_scm:libinput-1.19.2.tar.xz/doc/user/configuration.rst -> _service:tar_scm:libinput-1.22.1.tar.gz/doc/user/configuration.rst
Changed
@@ -143,6 +143,18 @@ most touchpads. ------------------------------------------------------------------------------ +Disable while trackpointing +------------------------------------------------------------------------------ + +DWTP is a form of palm detecion for devices that have a trackpoint (like +Thinkpads). While the user is using the trackpoint, the touchpad is disabled, +being enabled again after a timeout. See :ref:`disable-while-trackpointing` for +more info. + +Disable-while-trackpointing can be enabled or disabled, it is enabled by +default. + +------------------------------------------------------------------------------ Calibration ------------------------------------------------------------------------------
View file
_service:tar_scm:libinput-1.19.2.tar.xz/doc/user/contributing.rst -> _service:tar_scm:libinput-1.22.1.tar.gz/doc/user/contributing.rst
Changed
@@ -157,8 +157,8 @@ - `Register an account <https://gitlab.freedesktop.org/users/sign_in>`_ in the freedesktop.org GitLab instance. -- `Fork libinput <https://gitlab.freedesktop.org/libinput/libinput/forks/new>`_ - into your username's namespace +- `Fork libinput <https://gitlab.freedesktop.org/libinput/libinput/-/forks/new>`_ + into your username's namespace. Select public visibility. - Get libinput's main repository. git will call this repository ``origin``. :: git clone https://gitlab.freedesktop.org/libinput/libinput.git
View file
_service:tar_scm:libinput-1.19.2.tar.xz/doc/user/device-configuration-via-udev.rst -> _service:tar_scm:libinput-1.22.1.tar.gz/doc/user/device-configuration-via-udev.rst
Changed
@@ -68,10 +68,13 @@ Below is an example udev rule to assign "seat1" to a device from vendor -0x012a with the model ID of 0x034b. :: +``0x012a`` with the model ID of ``0x034b``. :: - ACTION=="add|change", KERNEL=="event0-9*", ENV{ID_VENDOR_ID}=="012a", \ - ENV{ID_MODEL_ID}=="034b", ENV{ID_SEAT}="seat1" + $ cat /etc/udev/rules.d/99-my-device-is-on-seat1.rules + ACTION=="add|change", KERNEL=="event0-9*", \ + ENV{ID_VENDOR_ID}=="012a", \ + ENV{ID_MODEL_ID}=="034b", \ + ENV{ID_SEAT}="seat1" @@ -96,10 +99,13 @@ Below is an example udev rule to remove an **ID_INPUT_TOUCHPAD** setting and change it into an **ID_INPUT_TABLET** setting. This rule would apply -for a device with the vendor/model ID of 012a/034b. :: +for a device with the vendor/model ID of ``012a``/``034b``. :: - ACTION=="add|change", KERNEL=="event0-9*", ENV{ID_VENDOR_ID}=="012a", \ - ENV{ID_MODEL_ID}=="034b", ENV{ID_INPUT_TOUCHPAD}="", ENV{ID_INPUT_TABLET}="1" + $ cat /etc/udev/rules.d/99-my-device-is-a-tablet.rules + ACTION=="add|change", KERNEL=="event0-9*", \ + ENV{ID_VENDOR_ID}=="012a", \ + ENV{ID_MODEL_ID}=="034b", \ + ENV{ID_INPUT_TOUCHPAD}="", ENV{ID_INPUT_TABLET}="1" @@ -128,6 +134,15 @@ ignore this property but other parts of the stack (if any) should continue treating this device normally. +Below is an example udev rule to assign **LIBINPUT_IGNORE_DEVICE** to the +device with the vendor/model ID of ``012a``/``034b``. :: + + $ cat /etc/udev/rules.d/99-ignore-my-device.rules + ACTION=="add|change", KERNEL=="event0-9*", \ + ENV{ID_VENDOR_ID}=="012a", \ + ENV{ID_MODEL_ID}=="034b", \ + ENV{LIBINPUT_IGNORE_DEVICE}="1" + .. _model_specific_configuration:
View file
_service:tar_scm:libinput-1.19.2.tar.xz/doc/user/device-quirks.rst -> _service:tar_scm:libinput-1.22.1.tar.gz/doc/user/device-quirks.rst
Changed
@@ -71,7 +71,7 @@ $ libinput quirks list /dev/input/event19 $ libinput quirks list /dev/input/event0 - AttrLidSwitchReliability=reliable + AttrLidSwitchReliability=unreliable The device `event19` does not have any quirks assigned. @@ -162,10 +162,11 @@ trigger a release (M), when a palm touch is triggered (O) and when a thumb touch is triggered (P). O > P > N > M. See :ref:`touchpad_pressure_hwdb` for more details. -AttrLidSwitchReliability=reliable|write_open - Indicates the reliability of the lid switch. This is a string enum. Do not - use "reliable" for any specific device. Very few devices need this, if in - doubt do not set. See :ref:`switches_lid` for details. +AttrLidSwitchReliability=reliable|unreliable|write_open + Indicates the reliability of the lid switch. This is a string enum. + Very few devices need this, if in doubt do not set. See :ref:`switches_lid` + for details. libinput 1.21.0 changed the default from unreliable to + reliable, which may be removed from local overrides. AttrKeyboardIntegration=internal|external Indicates the integration of the keyboard. This is a string enum. Generally only needed for USB keyboards.
View file
_service:tar_scm:libinput-1.19.2.tar.xz/doc/user/faqs.rst -> _service:tar_scm:libinput-1.22.1.tar.gz/doc/user/faqs.rst
Changed
@@ -335,3 +335,27 @@ devices directly but the compositor you want to use on your desktop needs an input stack that is more complex. And right now, libinput is the only input stack that exists for this use-case. + +.. _faq_separate_contexts: + +------------------------------------------------------------------------------ +Can I write a program to make libinput do $FOO +------------------------------------------------------------------------------ + +A common question is whether it's possible to write a program that can change +libinput's behavior - specifically the libinput that is used inside the +compositor. This indicates a misunderstanding of how libinput works: +libinput is a library that converts kernel events into libinput events, much +like ``sed`` reads data in, modifies it, and provides it to stdout. + +If ``sed`` is used by a shell-script, that script has full control over how +``sed`` processes data. In this analogy, ``sed`` is libinput and the +shell script is the compositor. It is not possible to write a program +to modify the behavior of the ``sed`` instance used inside that shell script + +Writing a program that uses libinput is akin to writing a new script that +invoke ``sed``. It will not have any effect on the original ``sed`` instance. + +The only way to modify libinput's behavior is to use the configuration options +exposed by the respective compositor. Those affect the libinput context inside +the compositor and thus have an effect on the input device behavior.
View file
_service:tar_scm:libinput-1.19.2.tar.xz/doc/user/meson.build -> _service:tar_scm:libinput-1.22.1.tar.gz/doc/user/meson.build
Changed
@@ -139,6 +139,7 @@ 'building.rst', 'button-debouncing.rst', 'clickpad-softbuttons.rst', + 'clickpad-with-right-button.rst', 'contributing.rst', 'device-configuration-via-udev.rst', 'device-quirks.rst', @@ -194,7 +195,8 @@ foreach distro : distributions yq_filter = '.distributions | select(.name == "@0@") | .packages | join(" ")'.format(distro) deps = run_command(yq, '-r', yq_filter, - meson.source_root() / '.gitlab-ci' / 'config.yml').stdout() + dir_gitlab_ci / 'config.yml', + check: true).stdout() dependencies_config.set('@0@_PACKAGES'.format(distro.to_upper()), deps) endforeach endif
View file
_service:tar_scm:libinput-1.19.2.tar.xz/doc/user/palm-detection.rst -> _service:tar_scm:libinput-1.22.1.tar.gz/doc/user/palm-detection.rst
Changed
@@ -27,6 +27,7 @@ - :ref:`palm_exclusion_zones` - :ref:`trackpoint-disabling` - :ref:`disable-while-typing` +- :ref:`disable-while-trackpointing` - :ref:`stylus-touch-arbitration` Palm detection is always enabled, with the exception of @@ -166,6 +167,20 @@ Disable-while-typing can be enabled and disabled by calling **libinput_device_config_dwt_set_enabled()**. +.. _disable-while-trackpointing: + +------------------------------------------------------------------------------ +Disable-while-trackpointing +------------------------------------------------------------------------------ + +libinput automatically disables the touchpad for a timeout after the trackpoint +is moved, a feature referred to as "disable while trackpointing". libinput does +not require an external command and the feature is currently enabled for all +touchpads. + +Disable-while-trackpointing can be enabled and disabled by calling +**libinput_device_config_dwtp_set_enabled()**. + .. _stylus-touch-arbitration: ------------------------------------------------------------------------------
View file
_service:tar_scm:libinput-1.19.2.tar.xz/doc/user/pointer-acceleration.rst -> _service:tar_scm:libinput-1.22.1.tar.gz/doc/user/pointer-acceleration.rst
Changed
@@ -19,12 +19,14 @@ ------------------------------------------------------------------------------ The profile decides the general method of pointer acceleration. -libinput currently supports two profiles: "adaptive" and "flat". The adaptive -profile is the default profile for all devices and takes the current speed -of the device into account when deciding on acceleration. The flat profile -is simply a constant factor applied to all device deltas, regardless of the -speed of motion (see :ref:`ptraccel-profile-flat`). Most of this document -describes the adaptive pointer acceleration. +libinput currently supports two profiles: **"adaptive"** and **"flat"**. + +- The **adaptive** profile is the default profile for all devices and takes the + current speed of the device into account when deciding on acceleration. +- The **flat** profile is simply a constant factor applied to all device deltas, + regardless of the speed of motion (see :ref:`ptraccel-profile-flat`). + +Most of this document describes the adaptive pointer acceleration. .. _ptraccel-velocity:
View file
_service:tar_scm:libinput-1.19.2.tar.xz/doc/user/reporting-bugs.rst -> _service:tar_scm:libinput-1.22.1.tar.gz/doc/user/reporting-bugs.rst
Changed
@@ -170,8 +170,7 @@ This is the most important piece of information, do not forget it! - the vendor model number of the device (e.g. "Logitech M325") - the output from udevadm info, see :ref:`udev_info`. -- the output of ``libinput measure trackpoint-range`` -- the sensitivity of the trackpoint (adjust the event node number as needed): :: +- the sensitivity of the trackpoint if it exists (adjust the event node number as needed): :: $ cat /sys/class/input/event17/device/device/sensitivity
View file
_service:tar_scm:libinput-1.19.2.tar.xz/doc/user/tablet-debugging.rst -> _service:tar_scm:libinput-1.22.1.tar.gz/doc/user/tablet-debugging.rst
Changed
@@ -39,6 +39,6 @@ - **resolution** indicates that the device does not have a resolution set for the x and y axes. This can be fixed with a hwdb entry, locate and read the `60-evdev.hwdb - <https://github.com/systemd/systemd/tree/master/hwdb/60-evdev.hwdb>`__ file + <https://github.com/systemd/systemd/blob/main/hwdb.d/60-evdev.hwdb>`__ file on your machine and file a pull request with the fixes against `systemd <https://github.com/systemd/systemd/>`__.
View file
_service:tar_scm:libinput-1.19.2.tar.xz/doc/user/tools.rst -> _service:tar_scm:libinput-1.22.1.tar.gz/doc/user/tools.rst
Changed
@@ -326,7 +326,7 @@ The ``libinput quirks`` tool can show quirks applied for any given device. :: $ libinput quirks list /dev/input/event0 - AttrLidSwitchReliability=reliable + AttrLidSwitchReliability=unreliable If the tool's output is empty, no quirk is applied. See :ref:`device-quirks` for more information.
View file
_service:tar_scm:libinput-1.19.2.tar.xz/doc/user/trackpoints.rst -> _service:tar_scm:libinput-1.22.1.tar.gz/doc/user/trackpoints.rst
Changed
@@ -50,7 +50,7 @@ trackpoint is in a neutral state and no events are reported. Trackpoint data is hard to generalize, see `Observations on trackpoint input data -<a href="https://who-t.blogspot.com/2018/06/observations-on-trackpoint-input-data.html">`_ +<https://who-t.blogspot.com/2018/06/observations-on-trackpoint-input-data.html>`_ for more details. .. figure:: trackpoint-delta-illustration.svg
View file
_service:tar_scm:libinput-1.19.2.tar.xz/doc/user/troubleshooting.rst -> _service:tar_scm:libinput-1.22.1.tar.gz/doc/user/troubleshooting.rst
Changed
@@ -15,3 +15,4 @@ trackpoint-configuration.rst tablet-debugging.rst incorrectly-enabled-hires.rst + clickpad-with-right-button.rst
View file
_service:tar_scm:libinput-1.19.2.tar.xz/include/valgrind/valgrind.h -> _service:tar_scm:libinput-1.22.1.tar.gz/include/valgrind/valgrind.h
Changed
@@ -21,16 +21,16 @@ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS @@ -52,13 +52,13 @@ the terms of the GNU General Public License, version 2. See the COPYING file in the source distribution for details. - ---------------------------------------------------------------- + ---------------------------------------------------------------- */ /* This file is for inclusion into client (your!) code. - You can use these macros to manipulate and query Valgrind's + You can use these macros to manipulate and query Valgrind's execution inside your own programs. The resulting executables will still run without Valgrind, just a @@ -89,7 +89,7 @@ || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6)) */ #define __VALGRIND_MAJOR__ 3 -#define __VALGRIND_MINOR__ 15 +#define __VALGRIND_MINOR__ 18 #include <stdarg.h> @@ -110,6 +110,8 @@ */ #undef PLAT_x86_darwin #undef PLAT_amd64_darwin +#undef PLAT_x86_freebsd +#undef PLAT_amd64_freebsd #undef PLAT_x86_win32 #undef PLAT_amd64_win64 #undef PLAT_x86_linux @@ -122,6 +124,7 @@ #undef PLAT_s390x_linux #undef PLAT_mips32_linux #undef PLAT_mips64_linux +#undef PLAT_nanomips_linux #undef PLAT_x86_solaris #undef PLAT_amd64_solaris @@ -130,12 +133,17 @@ # define PLAT_x86_darwin 1 #elif defined(__APPLE__) && defined(__x86_64__) # define PLAT_amd64_darwin 1 -#elif (defined(__MINGW32__) && !defined(__MINGW64__)) \ +#elif defined(__FreeBSD__) && defined(__i386__) +# define PLAT_x86_freebsd 1 +#elif defined(__FreeBSD__) && defined(__amd64__) +# define PLAT_amd64_freebsd 1 +#elif (defined(__MINGW32__) && defined(__i386__)) \ || defined(__CYGWIN32__) \ || (defined(_WIN32) && defined(_M_IX86)) # define PLAT_x86_win32 1 -#elif defined(__MINGW64__) \ - || (defined(_WIN64) && defined(_M_X64)) +#elif (defined(__MINGW32__) && defined(__x86_64__)) \ + || (defined(_WIN32) && defined(_M_X64)) +/* __MINGW32__ and _WIN32 are defined in 64 bit mode as well. */ # define PLAT_amd64_win64 1 #elif defined(__linux__) && defined(__i386__) # define PLAT_x86_linux 1 @@ -157,8 +165,10 @@ # define PLAT_s390x_linux 1 #elif defined(__linux__) && defined(__mips__) && (__mips==64) # define PLAT_mips64_linux 1 -#elif defined(__linux__) && defined(__mips__) && (__mips!=64) +#elif defined(__linux__) && defined(__mips__) && (__mips==32) # define PLAT_mips32_linux 1 +#elif defined(__linux__) && defined(__nanomips__) +# define PLAT_nanomips_linux 1 #elif defined(__sun) && defined(__i386__) # define PLAT_x86_solaris 1 #elif defined(__sun) && defined(__x86_64__) @@ -228,8 +238,8 @@ this is executed not under Valgrind. Args are passed in a memory block, and so there's no intrinsic limit to the number that could be passed, but it's currently five. - - The macro args are: + + The macro args are: _zzq_rlval result lvalue _zzq_default default value (result returned when running on real CPU) _zzq_request request code @@ -254,10 +264,10 @@ #if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ || (defined(PLAT_x86_win32) && defined(__GNUC__)) \ - || defined(PLAT_x86_solaris) + || defined(PLAT_x86_solaris) || defined(PLAT_x86_freebsd) typedef - struct { + struct { unsigned int nraddr; /* where's the code? */ } OrigFn; @@ -322,7 +332,7 @@ #if defined(PLAT_x86_win32) && !defined(__GNUC__) typedef - struct { + struct { unsigned int nraddr; /* where's the code? */ } OrigFn; @@ -394,10 +404,11 @@ #if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ || defined(PLAT_amd64_solaris) \ + || defined(PLAT_amd64_freebsd) \ || (defined(PLAT_amd64_win64) && defined(__GNUC__)) typedef - struct { + struct { unsigned long int nraddr; /* where's the code? */ } OrigFn; @@ -469,7 +480,7 @@ #if defined(PLAT_ppc32_linux) typedef - struct { + struct { unsigned int nraddr; /* where's the code? */ } OrigFn; @@ -538,7 +549,7 @@ #if defined(PLAT_ppc64be_linux) typedef - struct { + struct { unsigned long int nraddr; /* where's the code? */ unsigned long int r2; /* what tocptr do we need? */ } @@ -694,7 +705,7 @@ #if defined(PLAT_arm_linux) typedef - struct { + struct { unsigned int nraddr; /* where's the code? */ } OrigFn; @@ -762,7 +773,7 @@ #if defined(PLAT_arm64_linux) typedef - struct { + struct { unsigned long int nraddr; /* where's the code? */ } OrigFn; @@ -872,7 +883,8 @@ /* results = r3 */ \ "lgr %0, 3\n\t" \ : "=d" (_zzq_result) \ - : "a" (&_zzq_args0), "0" (_zzq_default) \ + : "a" (&_zzq_args0), \ + "0" ((unsigned long int)_zzq_default) \ : "cc", "2", "3", "memory" \ ); \ _zzq_result; \ @@ -908,7 +920,7 @@ #if defined(PLAT_mips32_linux) typedef - struct { + struct { unsigned int nraddr; /* where's the code? */ } OrigFn; @@ -922,7 +934,7 @@ "srl $0, $0, 29\n\t" \
View file
_service:tar_scm:libinput-1.19.2.tar.xz/meson.build -> _service:tar_scm:libinput-1.22.1.tar.gz/meson.build
Changed
@@ -1,5 +1,5 @@ project('libinput', 'c', - version : '1.19.2', + version : '1.22.1', license : 'MIT/Expat', default_options : 'c_std=gnu99', 'warning_level=2' , meson_version : '>= 0.49.0') @@ -16,6 +16,7 @@ dir_src_quirks = meson.current_source_dir() / 'quirks' dir_src_test = meson.current_source_dir() / 'test' dir_src = meson.current_source_dir() / 'src' +dir_gitlab_ci = meson.current_source_dir() / '.gitlab-ci' dir_udev = get_option('udev-dir') if dir_udev == '' @@ -138,6 +139,8 @@ config_h.set('PTRACE_DETACH', 'PT_DETACH') endif +config_h.set10('HAVE_INSTALLED_TESTS', get_option('install-tests')) + # Dependencies pkgconfig = import('pkgconfig') dep_udev = dependency('libudev') @@ -269,25 +272,16 @@ output : 'test-util-includes-@0@.c'.format(h), configuration : c) executable('test-build-@0@'.format(h), - testfile, dir_src / h, + testfile, include_directories : includes_src, includes_include, install : false) endforeach src_libinput_util = - 'src/util-bits.h', 'src/util-list.c', - 'src/util-list.h', - 'src/util-macros.h', - 'src/util-matrix.h', 'src/util-ratelimit.c', - 'src/util-ratelimit.h', - 'src/util-strings.h', 'src/util-strings.c', - 'src/util-time.h', - 'src/util-prop-parsers.h', 'src/util-prop-parsers.c', - 'src/libinput-util.h', libinput_util = static_library('libinput-util', src_libinput_util, @@ -306,8 +300,7 @@ 'src/filter-touchpad-x230.c', 'src/filter-tablet.c', 'src/filter-trackpoint.c', - 'src/filter.h', - 'src/filter-private.h' + 'src/filter-trackpoint-flat.c', libfilter = static_library('filter', src_libfilter, dependencies : dep_udev, dep_libwacom, @@ -328,8 +321,6 @@ src_libquirks = 'src/quirks.c', - 'src/quirks.h', - 'src/builddir.h', deps_libquirks = dep_udev, dep_libwacom, dep_libinput_util @@ -339,41 +330,35 @@ dep_libquirks = declare_dependency(link_with : libquirks) # Create /etc/libinput -install_subdir('libinput', install_dir : dir_etc) +if meson.version().version_compare('>= 0.60') + install_emptydir(dir_etc / 'libinput') +else + install_subdir('libinput', install_dir : dir_etc) +endif ############ libinput.so ############ install_headers('src/libinput.h') src_libinput = src_libfilter + 'src/libinput.c', - 'src/libinput.h', 'src/libinput-private-config.c', - 'src/libinput-private-config.h', - 'src/libinput-private.h', 'src/evdev.c', - 'src/evdev.h', 'src/evdev-debounce.c', 'src/evdev-fallback.c', - 'src/evdev-fallback.h', 'src/evdev-totem.c', 'src/evdev-middle-button.c', 'src/evdev-mt-touchpad.c', - 'src/evdev-mt-touchpad.h', 'src/evdev-mt-touchpad-tap.c', 'src/evdev-mt-touchpad-thumb.c', 'src/evdev-mt-touchpad-buttons.c', 'src/evdev-mt-touchpad-edge-scroll.c', 'src/evdev-mt-touchpad-gestures.c', 'src/evdev-tablet.c', - 'src/evdev-tablet.h', 'src/evdev-tablet-pad.c', - 'src/evdev-tablet-pad.h', 'src/evdev-tablet-pad-leds.c', + 'src/evdev-wheel.c', 'src/path-seat.c', 'src/udev-seat.c', - 'src/udev-seat.h', 'src/timer.c', - 'src/timer.h', - 'include/linux/input.h' deps_libinput = @@ -416,6 +401,10 @@ link_with : lib_libinput, dependencies : deps_libinput) +if meson.version().version_compare('>= 0.54.0') + meson.override_dependency('libinput', dep_libinput) +endif + pkgconfig.generate( filebase : 'libinput', name : 'Libinput', @@ -443,9 +432,7 @@ ############ tools ############ libinput_tool_path = dir_libexec config_h.set_quoted('LIBINPUT_TOOL_PATH', libinput_tool_path) -tools_shared_sources = 'tools/shared.c', - 'tools/shared.h', - 'src/builddir.h' +tools_shared_sources = 'tools/shared.c' deps_tools_shared = dep_libinput, dep_libevdev lib_tools_shared = static_library('tools_shared', tools_shared_sources, @@ -549,6 +536,7 @@ install : true, ) +config_h.set10('HAVE_DEBUG_GUI', get_option('debug-gui')) if get_option('debug-gui') dep_gtk = dependency('gtk4', version : '>= 4.0', required : false) config_h.set10('HAVE_GTK4', dep_gtk.found()) @@ -557,15 +545,22 @@ config_h.set10('HAVE_GTK3', dep_gtk.found()) endif + gtk_targets = dep_gtk.get_pkgconfig_variable('targets') + have_gtk_wayland = gtk_targets.contains('wayland') + have_gtk_x11 = gtk_targets.contains('x11') + dep_cairo = dependency('cairo') dep_glib = dependency('glib-2.0') + dep_x11 = dependency('x11', required : false) dep_wayland_client = dependency('wayland-client', required : false) dep_wayland_protocols = dependency('wayland-protocols', required : false) - dep_x11 = dependency('x11', required : false) + + config_h.set10('HAVE_GTK_X11', have_gtk_x11 and dep_x11.found()) + config_h.set10('HAVE_GTK_WAYLAND', false) debug_gui_sources = 'tools/libinput-debug-gui.c' - if dep_wayland_client.found() and dep_wayland_protocols.found() + if have_gtk_wayland and dep_wayland_client.found() and dep_wayland_protocols.found() wayland_scanner = find_program('wayland-scanner') wlproto_dir = dep_wayland_protocols.get_pkgconfig_variable('pkgdatadir') @@ -585,6 +580,7 @@ ) debug_gui_sources += wayland_headers, wayland_sources + config_h.set10('HAVE_GTK_WAYLAND', true) endif deps_debug_gui = @@ -695,6 +691,15 @@ install : false) endif +libinput_test_sources = 'tools/libinput-test.c' +executable('libinput-test', + libinput_test_sources, + dependencies : deps_tools, + include_directories : includes_src, includes_include, + install_dir : libinput_tool_path, + install : true, + ) + # This is the test suite runner, we allow disabling that one because of # dependencies if get_option('tests') @@ -709,9 +714,6 @@ litest_sources =
View file
_service:tar_scm:libinput-1.22.1.tar.gz/quirks/30-vendor-a4tech.quirks
Added
@@ -0,0 +1,5 @@ +A4TECH USB X-710BK +MatchVendor=0x09DA +MatchProduct=0x9090 +MatchUdevType=mouse +ModelBouncingKeys=1
View file
_service:tar_scm:libinput-1.22.1.tar.gz/quirks/30-vendor-glorious.quirks
Added
@@ -0,0 +1,6 @@ +Glorious Model O +MatchUdevType=mouse +MatchBus=usb +MatchVendor=0x258A +MatchProduct=0x0036 +ModelBouncingKeys=1
View file
_service:tar_scm:libinput-1.19.2.tar.xz/quirks/30-vendor-microsoft.quirks -> _service:tar_scm:libinput-1.22.1.tar.gz/quirks/30-vendor-microsoft.quirks
Changed
@@ -20,6 +20,18 @@ MatchDMIModalias=dmi:*svnMicrosoftCorporation:* AttrKeyboardIntegration=internal +Microsoft Surface Laptop Studio Touchpad +MatchVendor=0x045E +MatchProduct=0x09AF +MatchUdevType=touchpad +AttrPressureRange=25:10 +AttrPalmPressureThreshold=500 + +Microsoft Surface Laptop Studio Built-In Peripherals +MatchName=*Microsoft Surface* +MatchDMIModalias=dmi:*svnMicrosoftCorporation:*pnSurfaceLaptopStudio +ModelTabletModeNoSuspend=1 + Microsoft Nano Transceiver v2.0 MatchUdevType=mouse MatchBus=usb
View file
_service:tar_scm:libinput-1.19.2.tar.xz/quirks/30-vendor-synaptics.quirks -> _service:tar_scm:libinput-1.22.1.tar.gz/quirks/30-vendor-synaptics.quirks
Changed
@@ -6,3 +6,14 @@ MatchVendor=0x0002 MatchProduct=0x0007 ModelSynapticsSerialTouchpad=1 + +# SYNA3602:00 0911:5288 touchpad, clickpad pretending it has a right button. +# Integrated into several systems, including +# Purism Librem 14v1 +# Prestigio Smartbook 141 C2 +# StarLite Mk II +# Iota IOTA2320 +Synaptics 0911:5288 Touchpad +MatchUdevType=touchpad +MatchName=* 0911:5288 Touchpad +AttrEventCodeDisable=BTN_RIGHT
View file
_service:tar_scm:libinput-1.19.2.tar.xz/quirks/30-vendor-wacom.quirks -> _service:tar_scm:libinput-1.22.1.tar.gz/quirks/30-vendor-wacom.quirks
Changed
@@ -13,9 +13,16 @@ MatchProduct=0x0357 AttrPalmSizeThreshold=5 -Wacom ISDV4 Pen +Wacom ISDV4 4200 Pen MatchUdevType=tablet MatchBus=usb MatchVendor=0x56A MatchProduct=0x4200 AttrEventCodeDisable=ABS_TILT_X;ABS_TILT_Y; + +Wacom ISDV4 524c Pen +MatchUdevType=tablet +MatchBus=usb +MatchVendor=0x2D1F +MatchProduct=0x524C +AttrEventCodeDisable=ABS_TILT_X;ABS_TILT_Y;
View file
_service:tar_scm:libinput-1.19.2.tar.xz/quirks/50-framework.quirks -> _service:tar_scm:libinput-1.22.1.tar.gz/quirks/50-framework.quirks
Changed
@@ -1,5 +1,5 @@ Framework Laptop Touchpad MatchName=PIXA3854:00 093A:0274 Touchpad MatchUdevType=touchpad -MatchDMIModalias=dmi:*svnFramework:pnLaptop:* +MatchDMIModalias=dmi:*svnFramework:pnLaptop* AttrEventCodeDisable=BTN_RIGHT
View file
_service:tar_scm:libinput-1.19.2.tar.xz/quirks/50-system-apple.quirks -> _service:tar_scm:libinput-1.22.1.tar.gz/quirks/50-system-apple.quirks
Changed
@@ -105,6 +105,15 @@ AttrTouchSizeRange=150:130 AttrPalmSizeThreshold=1600 +Apple Laptop Touchpad (MTP) +MatchUdevType=touchpad +MatchName=Apple*MTP* +MatchVendor=0x5AC +ModelAppleTouchpad=1 +AttrSizeHint=104x75 +AttrTouchSizeRange=150:130 +AttrPalmSizeThreshold=1600 + # The Linux applespi driver currently uses the Synaptics vendor for some reason Apple Laptop Touchpad (SPI) MatchUdevType=touchpad
View file
_service:tar_scm:libinput-1.19.2.tar.xz/quirks/50-system-asus.quirks -> _service:tar_scm:libinput-1.22.1.tar.gz/quirks/50-system-asus.quirks
Changed
@@ -33,3 +33,11 @@ MatchProduct=0x19B6 MatchUdevType=keyboard AttrKeyboardIntegration=internal + +# keyboard has a different vid/pid to the touchpad +# so libinput won't pair the two together and dwt isn't active. +Asus ROG Strix G15 2021 keyboard +MatchVendor=0x0B05 +MatchProduct=0x1866 +MatchUdevType=keyboard +AttrKeyboardIntegration=internal
View file
_service:tar_scm:libinput-1.19.2.tar.xz/quirks/50-system-dell.quirks -> _service:tar_scm:libinput-1.22.1.tar.gz/quirks/50-system-dell.quirks
Changed
@@ -14,7 +14,8 @@ Dell Inspiron 15R N5110 Touchpad MatchUdevType=touchpad MatchName=*AlpsPS/2 ALPS GlidePoint -MatchDMIModalias=dmi:*bvrA07*svnDellInc.:*pnInspironN5110* +MatchVersion=0x0300 +MatchDMIModalias=dmi:*svnDellInc.:*pnInspironN5110* AttrPressureRange=100:95 Dell Latitude E5510 Touchpad @@ -107,3 +108,16 @@ MatchVendor=0x2575 MatchProduct=0x0204 ModelDellCanvasTotem=1 + +Dell Latitude 5290 2-in-1 +MatchName=AT Translated Set 2 keyboard +MatchDMIModalias=dmi:*:svnDellInc.:pnLatitude52902-in-1:* +ModelTabletModeNoSuspend=1 + +# This is a true pressurepad so disable pressure for contact size +# https://gitlab.freedesktop.org/libinput/libinput/-/issues/849 +Dell Precision5680 Touchpad +MatchBus=i2c +MatchVendor=0x27C6 +MatchProduct=0x0F60 +AttrEventCodeDisable=ABS_MT_PRESSURE;ABS_PRESSURE;
View file
_service:tar_scm:libinput-1.19.2.tar.xz/quirks/50-system-google.quirks -> _service:tar_scm:libinput-1.22.1.tar.gz/quirks/50-system-google.quirks
Changed
@@ -1,5 +1,10 @@ # Do not edit this file, it will be overwritten on update +Generic Google ARM device with Touchpad +MatchName=*Elan Touchpad* +MatchDeviceTree=*google* +ModelChromebook=1 + Google Chromebook R13 CB5-312T MatchName=*Elan Touchpad* MatchDeviceTree=*Chromebook R13 CB5-312T* @@ -94,3 +99,8 @@ ModelChromebook=1 AttrPressureRange=6:4 AttrThumbPressureThreshold=45 + +Google Chromebook Lazor Keyboard +MatchName=*cros_ec* +MatchDeviceTree=*lazor* +AttrKeyboardIntegration=internal
View file
_service:tar_scm:libinput-1.19.2.tar.xz/quirks/50-system-hp.quirks -> _service:tar_scm:libinput-1.22.1.tar.gz/quirks/50-system-hp.quirks
Changed
@@ -36,6 +36,11 @@ MatchDMIModalias=dmi:*:svnHewlett-Packard:pnHPStreamx360ConvertiblePC11:* ModelTabletModeNoSuspend=1 +HP Spectre x360 Convertible 15-bl000 +MatchName=AT Translated Set 2 keyboard +MatchDMIModalias=dmi:*:svnHP:pnHPSpectrex360Convertible15-bl0XX:* +ModelTabletModeNoSuspend=1 + HP ZBook Studio G3 MatchName=AlpsPS/2 ALPS GlidePoint MatchDMIModalias=dmi:*svnHP:pnHPZBookStudioG3:*
View file
_service:tar_scm:libinput-1.19.2.tar.xz/quirks/50-system-lenovo.quirks -> _service:tar_scm:libinput-1.22.1.tar.gz/quirks/50-system-lenovo.quirks
Changed
@@ -246,6 +246,27 @@ MatchProduct=0xC101 AttrKeyboardIntegration=internal +Lenovo Legion 7 Keyboard +MatchUdevType=keyboard +MatchBus=usb +MatchVendor=0x048D +MatchProduct=0xC968 +AttrKeyboardIntegration=internal + +Lenovo Legion Y740 Keyboard +MatchUdevType=keyboard +MatchBus=usb +MatchVendor=0x048D +MatchProduct=0xC936 +AttrKeyboardIntegration=internal + +Lenovo Legion Slim 7 +MatchUdevType=keyboard +MatchBus=usb +MatchVendor=0x048D +MatchProduct=0xC967 +AttrKeyboardIntegration=internal + # https://gitlab.freedesktop.org/libinput/libinput/-/issues/604 Lenovo Yoga Slim 9 14ITL5 Pressurepad MatchBus=i2c @@ -260,15 +281,16 @@ MatchDMIModalias=dmi:*svnLENOVO:*pvrYogaDuet713IML05:* ModelTabletModeNoSuspend=1 -# https://gitlab.freedesktop.org/libinput/libinput/-/issues/651 -Lenovo TrackPoint Keyboard II USB -MatchBus=usb -MatchVendor=0x17EF -MatchProduct=0x60EE -ModelLenovoTrackpointKeyboard2=1 +# Lenovo IdeaPad Duet 3 also comes with a detachable keyboard. +Lenovo IdeaPad Duet 3 +MatchName=AT Raw Set 2 keyboard +MatchDMIModalias=dmi:*svnLENOVO:*pvrIdeaPadDuet3*:* +ModelTabletModeNoSuspend=1 -Lenovo TrackPoint Keyboard II Bluetooth -MatchBus=bluetooth -MatchVendor=0x17EF -MatchProduct=0x60E1 -ModelLenovoTrackpointKeyboard2=1 +# Modifies pressure range to avoid random jumps. +# https://gitlab.freedesktop.org/libinput/libinput/-/issues/407 +Lenovo Yoga 2 Pro touchpad +MatchUdevType=touchpad +MatchName=*SynPS/2 Synaptics TouchPad +MatchDMIModalias=dmi:*svnLENOVO:*:pvrLenovoYoga2Pro* +AttrPressureRange=50:45
View file
_service:tar_scm:libinput-1.22.1.tar.gz/quirks/50-system-starlabs.quirks
Added
@@ -0,0 +1,6 @@ +Star Labs Touchpad +MatchName=*Touchpad +MatchUdevType=touchpad +MatchDMIModalias=dmi:*svnStarLabs:* +AttrEventCodeDisable=BTN_RIGHT +AttrInputPropEnable=INPUT_PROP_BUTTONPAD
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/evdev-fallback.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/evdev-fallback.c
Changed
@@ -68,18 +68,6 @@ int button, enum libinput_button_state state) { - if (button == BTN_MIDDLE) - dispatch->wheel.is_inhibited = (state == LIBINPUT_BUTTON_STATE_PRESSED); - - /* Lenovo TrackPoint Keyboard II sends its own scroll events when its - * trackpoint is moved while the middle button is pressed. - * Do not inhibit the scroll events. - * https://gitlab.freedesktop.org/libinput/libinput/-/issues/651 - */ - if (evdev_device_has_model_quirk(device, - QUIRK_MODEL_LENOVO_TRACKPOINT_KEYBOARD_2)) - dispatch->wheel.is_inhibited = false; - evdev_pointer_notify_physical_button(device, time, button, state); } @@ -102,19 +90,10 @@ LIBINPUT_SWITCH_STATE_OFF; } -static inline void -normalize_delta(struct evdev_device *device, - const struct device_coords *delta, - struct normalized_coords *normalized) -{ - normalized->x = delta->x * DEFAULT_MOUSE_DPI / (double)device->dpi; - normalized->y = delta->y * DEFAULT_MOUSE_DPI / (double)device->dpi; -} - static inline bool -post_trackpoint_scroll(struct evdev_device *device, - struct normalized_coords unaccel, - uint64_t time) +post_button_scroll(struct evdev_device *device, + struct device_float_coords raw, + uint64_t time) { if (device->scroll.method != LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) return false; @@ -132,9 +111,16 @@ device->scroll.button_scroll_state = BUTTONSCROLL_SCROLLING; _fallthrough_; case BUTTONSCROLL_SCROLLING: + { + const struct normalized_coords normalized = + filter_dispatch_constant(device->pointer.filter, + &raw, + device, + time); evdev_post_scroll(device, time, LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS, - &unaccel); + &normalized); + } return true; } @@ -187,7 +173,7 @@ uint64_t time) { struct libinput_device *base = &device->base; - struct normalized_coords accel, unaccel; + struct normalized_coords accel; struct device_float_coords raw; if (!(device->seat_caps & EVDEV_DEVICE_POINTER)) @@ -195,14 +181,13 @@ fallback_rotate_relative(dispatch, device); - normalize_delta(device, &dispatch->rel, &unaccel); raw.x = dispatch->rel.x; raw.y = dispatch->rel.y; dispatch->rel.x = 0; dispatch->rel.y = 0; /* Use unaccelerated deltas for pointing stick scroll */ - if (post_trackpoint_scroll(device, unaccel, time)) + if (post_button_scroll(device, raw, time)) return; if (device->pointer.filter) { @@ -214,120 +199,16 @@ } else { evdev_log_bug_libinput(device, "accel filter missing\n"); - accel = unaccel; + accel.x = accel.y = 0; } - if (normalized_is_zero(accel) && normalized_is_zero(unaccel)) + if (normalized_is_zero(accel)) return; pointer_notify_motion(base, time, &accel, &raw); } static void -fallback_flush_wheels(struct fallback_dispatch *dispatch, - struct evdev_device *device, - uint64_t time) -{ - struct normalized_coords wheel_degrees = { 0.0, 0.0 }; - struct discrete_coords discrete = { 0.0, 0.0 }; - struct wheel_v120 v120 = { 0.0, 0.0 }; - - if (!(device->seat_caps & EVDEV_DEVICE_POINTER)) - return; - - if (!dispatch->wheel.emulate_hi_res_wheel && - !dispatch->wheel.hi_res_event_received && - (dispatch->wheel.lo_res.x != 0 || dispatch->wheel.lo_res.y != 0)) { - evdev_log_bug_kernel(device, - "device supports high-resolution scroll but only low-resolution events have been received.\n" - "See %s/incorrectly-enabled-hires.html for details\n", - HTTP_DOC_LINK); - dispatch->wheel.emulate_hi_res_wheel = true; - dispatch->wheel.hi_res.x = dispatch->wheel.lo_res.x * 120; - dispatch->wheel.hi_res.y = dispatch->wheel.lo_res.y * 120; - } - - if (dispatch->wheel.is_inhibited) { - dispatch->wheel.hi_res.x = 0; - dispatch->wheel.hi_res.y = 0; - dispatch->wheel.lo_res.x = 0; - dispatch->wheel.lo_res.y = 0; - return; - } - - if (device->model_flags & EVDEV_MODEL_LENOVO_SCROLLPOINT) { - struct normalized_coords unaccel = { 0.0, 0.0 }; - - dispatch->wheel.hi_res.y *= -1; - normalize_delta(device, &dispatch->wheel.hi_res, &unaccel); - evdev_post_scroll(device, - time, - LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS, - &unaccel); - dispatch->wheel.hi_res.x = 0; - dispatch->wheel.hi_res.y = 0; - - return; - } - - if (dispatch->wheel.hi_res.y != 0) { - int value = dispatch->wheel.hi_res.y; - - v120.y = -1 * value; - wheel_degrees.y = -1 * value/120.0 * device->scroll.wheel_click_angle.y; - evdev_notify_axis_wheel( - device, - time, - bit(LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL), - &wheel_degrees, - &v120); - dispatch->wheel.hi_res.y = 0; - } - - if (dispatch->wheel.lo_res.y != 0) { - int value = dispatch->wheel.lo_res.y; - - wheel_degrees.y = -1 * value * device->scroll.wheel_click_angle.y; - discrete.y = -1 * value; - evdev_notify_axis_legacy_wheel( - device, - time, - bit(LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL), - &wheel_degrees, - &discrete); - dispatch->wheel.lo_res.y = 0; - } - - if (dispatch->wheel.hi_res.x != 0) { - int value = dispatch->wheel.hi_res.x; - - v120.x = value; - wheel_degrees.x = value/120.0 * device->scroll.wheel_click_angle.x; - evdev_notify_axis_wheel( - device, - time, - bit(LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL), - &wheel_degrees, - &v120); - dispatch->wheel.hi_res.x = 0; - } - - if (dispatch->wheel.lo_res.x != 0) { - int value = dispatch->wheel.lo_res.x; - - wheel_degrees.x = value * device->scroll.wheel_click_angle.x; - discrete.x = value; - evdev_notify_axis_legacy_wheel( - device, - time, - bit(LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL), - &wheel_degrees, - &discrete);
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/evdev-fallback.h -> _service:tar_scm:libinput-1.22.1.tar.gz/src/evdev-fallback.h
Changed
@@ -59,6 +59,20 @@ PALM_WAS_PALM, /* this touch sequence was a palm but isn't now */ }; +enum wheel_state { + WHEEL_STATE_NONE, + WHEEL_STATE_ACCUMULATING_SCROLL, + WHEEL_STATE_SCROLLING, +}; + +enum wheel_direction { + WHEEL_DIR_UNKNOW, + WHEEL_DIR_VPOS, + WHEEL_DIR_VNEG, + WHEEL_DIR_HPOS, + WHEEL_DIR_HNEG, +}; + struct mt_slot { bool dirty; enum mt_slot_state state; @@ -98,11 +112,13 @@ struct device_coords rel; struct { + enum wheel_state state; struct device_coords lo_res; struct device_coords hi_res; bool emulate_hi_res_wheel; - bool is_inhibited; bool hi_res_event_received; + struct libinput_timer scroll_timer; + enum wheel_direction dir; } wheel; struct { @@ -255,4 +271,18 @@ int button, enum libinput_button_state state); +void +fallback_init_wheel(struct fallback_dispatch *dispatch, + struct evdev_device *device); + +void +fallback_wheel_process_relative(struct fallback_dispatch *dispatch, + struct evdev_device *device, + struct input_event *e, uint64_t time); + +void +fallback_wheel_handle_state(struct fallback_dispatch *dispatch, + struct evdev_device *device, + uint64_t time); + #endif
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/evdev-middle-button.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/evdev-middle-button.c
Changed
@@ -583,7 +583,7 @@ enum evdev_middlebutton_event event; bool is_press = state == LIBINPUT_BUTTON_STATE_PRESSED; int rc; - unsigned int bit = (button - BTN_LEFT); + unsigned int btnbit = (button - BTN_LEFT); uint32_t old_mask = 0; if (!device->middlebutton.enabled) @@ -612,7 +612,7 @@ } if (button < BTN_LEFT || - bit >= sizeof(device->middlebutton.button_mask) * 8) { + btnbit >= sizeof(device->middlebutton.button_mask) * 8) { evdev_log_bug_libinput(device, "Button mask too small for %s\n", libevdev_event_code_get_name(EV_KEY, @@ -624,9 +624,9 @@ old_mask = device->middlebutton.button_mask; if (is_press) - device->middlebutton.button_mask |= 1 << bit; + device->middlebutton.button_mask |= bit(btnbit); else - device->middlebutton.button_mask &= ~(1 << bit); + device->middlebutton.button_mask &= ~bit(btnbit); if (old_mask != device->middlebutton.button_mask && device->middlebutton.button_mask == 0) {
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/evdev-mt-touchpad-buttons.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/evdev-mt-touchpad-buttons.c
Changed
@@ -592,7 +592,7 @@ const struct input_event *e, uint64_t time) { - uint32_t mask = 1 << (e->code - BTN_LEFT); + uint32_t mask = bit(e->code - BTN_LEFT); /* Ignore other buttons on clickpads */ if (tp->buttons.is_clickpad && e->code != BTN_LEFT) { @@ -923,6 +923,7 @@ { bool is_clickpad; bool has_left = libevdev_has_event_code(device->evdev, EV_KEY, BTN_LEFT), + has_middle = libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE), has_right = libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT); is_clickpad = libevdev_has_property(device->evdev, INPUT_PROP_BUTTONPAD); @@ -934,19 +935,26 @@ * single physical button * - Wacom touch devices have neither left nor right buttons */ - if (is_clickpad) { - if (has_right) { - evdev_log_bug_kernel(device, - "clickpad with right button, assuming it is not a clickpad\n"); - is_clickpad = false; - } - } else if (has_left && !has_right && - (tp->device->model_flags & EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON) == 0) { + if (!is_clickpad && has_left && !has_right && + (tp->device->model_flags & EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON) == 0) { evdev_log_bug_kernel(device, "missing right button, assuming it is a clickpad.\n"); is_clickpad = true; } + if (has_middle || has_right) { + if (is_clickpad) + evdev_log_bug_kernel(device, + "clickpad advertising right button. " + "See %s/clickpad-with-right-button.html for details\n", + HTTP_DOC_LINK); + } else if (has_left & + !is_clickpad && + libevdev_get_id_vendor(device->evdev) != VENDOR_ID_APPLE) { + evdev_log_bug_kernel(device, + "non clickpad without right button?\n"); + } + return is_clickpad; }
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/evdev-mt-touchpad-gestures.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/evdev-mt-touchpad-gestures.c
Changed
@@ -555,9 +555,9 @@ } static void -tp_gesture_none_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_none(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { switch(event) { case GESTURE_EVENT_RESET: @@ -584,9 +584,9 @@ } static void -tp_gesture_unknown_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_unknown(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { switch(event) { case GESTURE_EVENT_RESET: @@ -624,9 +624,9 @@ } static void -tp_gesture_hold_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_hold(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { switch(event) { case GESTURE_EVENT_RESET: @@ -662,9 +662,9 @@ } static void -tp_gesture_hold_and_motion_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_hold_and_motion(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { switch(event) { case GESTURE_EVENT_RESET: @@ -687,9 +687,9 @@ } static void -tp_gesture_pointer_motion_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_pointer_motion(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { struct tp_touch *first; struct phys_coords first_moved; @@ -725,31 +725,35 @@ } static void -tp_gesture_scroll_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_scroll(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { switch(event) { case GESTURE_EVENT_RESET: libinput_timer_cancel(&tp->gesture.hold_timer); tp->gesture.state = GESTURE_STATE_NONE; break; + case GESTURE_EVENT_PINCH: + tp_gesture_init_pinch(tp); + tp_gesture_cancel(tp, time); + tp->gesture.state = GESTURE_STATE_PINCH; + break; case GESTURE_EVENT_HOLD_AND_MOTION: case GESTURE_EVENT_FINGER_DETECTED: case GESTURE_EVENT_HOLD_TIMEOUT: case GESTURE_EVENT_POINTER_MOTION: case GESTURE_EVENT_SCROLL: case GESTURE_EVENT_SWIPE: - case GESTURE_EVENT_PINCH: log_gesture_bug(tp, event); break; } } static void -tp_gesture_pinch_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_pinch(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { switch(event) { case GESTURE_EVENT_RESET: @@ -769,9 +773,9 @@ } static void -tp_gesture_swipe_handle_event(struct tp_dispatch *tp, - enum gesture_event event, - uint64_t time) +tp_gesture_handle_event_on_state_swipe(struct tp_dispatch *tp, + enum gesture_event event, + uint64_t time) { switch(event) { case GESTURE_EVENT_RESET: @@ -801,28 +805,28 @@ switch(tp->gesture.state) { case GESTURE_STATE_NONE: - tp_gesture_none_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_none(tp, event, time); break; case GESTURE_STATE_UNKNOWN: - tp_gesture_unknown_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_unknown(tp, event, time); break; case GESTURE_STATE_HOLD: - tp_gesture_hold_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_hold(tp, event, time); break; case GESTURE_STATE_HOLD_AND_MOTION: - tp_gesture_hold_and_motion_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_hold_and_motion(tp, event, time); break; case GESTURE_STATE_POINTER_MOTION: - tp_gesture_pointer_motion_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_pointer_motion(tp, event, time); break; case GESTURE_STATE_SCROLL: - tp_gesture_scroll_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_scroll(tp, event, time); break; case GESTURE_STATE_PINCH: - tp_gesture_pinch_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_pinch(tp, event, time); break; case GESTURE_STATE_SWIPE: - tp_gesture_swipe_handle_event(tp, event, time); + tp_gesture_handle_event_on_state_swipe(tp, event, time); break; } @@ -958,7 +962,7 @@ */ if (tp->thumb.detect_thumbs && thumb_mm < min_move) { tp_thumb_suppress(tp, thumb); - tp_gesture_handle_event(tp, GESTURE_EVENT_RESET, time); + tp_gesture_cancel(tp, time); return; } @@ -1166,7 +1170,6 @@ */ if (time < (tp->gesture.initial_time + DEFAULT_GESTURE_PINCH_TIMEOUT) && tp_gesture_is_pinch(tp)) { - tp_gesture_cancel(tp, time); tp_gesture_handle_event(tp, GESTURE_EVENT_PINCH, time); return; } @@ -1283,6 +1286,9 @@ if (!thumb) return false; + if (!tp_touch_active_for_gesture(tp, thumb)) + return false; + thumb_moved = tp_gesture_mm_moved(tp, thumb); thumb_mm = hypot(thumb_moved.x, thumb_moved.y); return thumb_mm >= PINCH_DISAMBIGUATION_MOVE_THRESHOLD;
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/evdev-mt-touchpad-tap.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/evdev-mt-touchpad-tap.c
Changed
@@ -139,9 +139,9 @@ button = button_maptp->tap.mapnfingers - 1; if (state == LIBINPUT_BUTTON_STATE_PRESSED) - tp->tap.buttons_pressed |= (1 << nfingers); + tp->tap.buttons_pressed |= bit(nfingers); else - tp->tap.buttons_pressed &= ~(1 << nfingers); + tp->tap.buttons_pressed &= ~bit(nfingers); evdev_pointer_notify_button(tp->device, time, @@ -1603,7 +1603,7 @@ int i; for (i = 1; i <= 3; i++) { - if (tp->tap.buttons_pressed & (1 << i)) + if (tp->tap.buttons_pressed & bit(i)) tp_tap_notify(tp, now, i, LIBINPUT_BUTTON_STATE_RELEASED); }
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/evdev-mt-touchpad.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/evdev-mt-touchpad.c
Changed
@@ -39,7 +39,7 @@ #define DEFAULT_TRACKPOINT_EVENT_TIMEOUT ms2us(40) #define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_1 ms2us(200) #define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_2 ms2us(500) -#define FAKE_FINGER_OVERFLOW (1 << 7) +#define FAKE_FINGER_OVERFLOW bit(7) #define THUMB_IGNORE_SPEED_THRESHOLD 20 /* mm/s */ enum notify { @@ -198,7 +198,7 @@ if (dx > 0) { /* right move */ static const char r_l_r = 0x5; /* {Right, Left, Right} */ - t->hysteresis.x_motion_history |= (1 << 2); + t->hysteresis.x_motion_history |= bit(2); if (t->hysteresis.x_motion_history == r_l_r) { tp->hysteresis.enabled = true; evdev_log_debug(tp->device, @@ -303,10 +303,10 @@ if (is_press) { tp->fake_touches &= ~FAKE_FINGER_OVERFLOW; - tp->fake_touches |= 1 << shift; + tp->fake_touches |= bit(shift); } else { - tp->fake_touches &= ~(0x1 << shift); + tp->fake_touches &= ~bit(shift); } } @@ -1916,6 +1916,7 @@ tp_apply_rotation(tp->device); } +LIBINPUT_UNUSED static inline void tp_debug_touch_state(struct tp_dispatch *tp, struct evdev_device *device) @@ -2201,6 +2202,9 @@ { struct tp_dispatch *tp = data; + if (!tp->palm.dwtp_enabled) + return; + /* Buttons do not count as trackpad activity, as people may use the trackpoint buttons in combination with the touchpad. */ if (event->type == LIBINPUT_EVENT_POINTER_BUTTON) @@ -2281,7 +2285,13 @@ if (tp_key_is_modifier(keycode)) return false; - return keycode >= KEY_F1; + switch (keycode) { + case KEY_ESC: + case KEY_KPASTERISK: + return true; + default: + return keycode >= KEY_F1; + } } static void @@ -2881,7 +2891,6 @@ { BTN_TOOL_TRIPLETAP, 3 }, { BTN_TOOL_DOUBLETAP, 2 }, }; - struct map *m; unsigned int i, n_btn_tool_touches = 1; absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_SLOT); @@ -3199,6 +3208,60 @@ LIBINPUT_CONFIG_DWT_DISABLED; } +static int +tp_dwtp_config_is_available(struct libinput_device *device) +{ + return 1; +} + +static enum libinput_config_status +tp_dwtp_config_set(struct libinput_device *device, + enum libinput_config_dwtp_state enable) +{ + struct evdev_device *evdev = evdev_device(device); + struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch; + + switch(enable) { + case LIBINPUT_CONFIG_DWTP_ENABLED: + case LIBINPUT_CONFIG_DWTP_DISABLED: + break; + default: + return LIBINPUT_CONFIG_STATUS_INVALID; + } + + tp->palm.dwtp_enabled = (enable == LIBINPUT_CONFIG_DWTP_ENABLED); + + return LIBINPUT_CONFIG_STATUS_SUCCESS; +} + +static enum libinput_config_dwtp_state +tp_dwtp_config_get(struct libinput_device *device) +{ + struct evdev_device *evdev = evdev_device(device); + struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch; + + return tp->palm.dwtp_enabled ? + LIBINPUT_CONFIG_DWTP_ENABLED : + LIBINPUT_CONFIG_DWTP_DISABLED; +} + +static bool +tp_dwtp_default_enabled(struct tp_dispatch *tp) +{ + return true; +} + +static enum libinput_config_dwtp_state +tp_dwtp_config_get_default(struct libinput_device *device) +{ + struct evdev_device *evdev = evdev_device(device); + struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch; + + return tp_dwtp_default_enabled(tp) ? + LIBINPUT_CONFIG_DWTP_ENABLED : + LIBINPUT_CONFIG_DWTP_DISABLED; +} + static inline bool tp_is_tpkb_combo_below(struct evdev_device *device) { @@ -3245,6 +3308,22 @@ device->base.config.dwt = &tp->dwt.config; } +static void +tp_init_dwtp(struct tp_dispatch *tp, + struct evdev_device *device) +{ + tp->palm.dwtp_enabled = tp_dwtp_default_enabled(tp); + + if (device->tags & EVDEV_TAG_EXTERNAL_TOUCHPAD) + return; + + tp->palm.config.is_available = tp_dwtp_config_is_available; + tp->palm.config.set_enabled = tp_dwtp_config_set; + tp->palm.config.get_enabled = tp_dwtp_config_get; + tp->palm.config.get_default_enabled = tp_dwtp_config_get_default; + device->base.config.dwtp = &tp->palm.config; +} + static inline void tp_init_palmdetect_edge(struct tp_dispatch *tp, struct evdev_device *device) @@ -3674,6 +3753,7 @@ tp_init_tap(tp); tp_init_buttons(tp, device); tp_init_dwt(tp, device); + tp_init_dwtp(tp, device); tp_init_palmdetect(tp, device); tp_init_sendevents(tp, device); tp_init_scroll(tp, device);
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/evdev-mt-touchpad.h -> _service:tar_scm:libinput-1.22.1.tar.gz/src/evdev-mt-touchpad.h
Changed
@@ -438,6 +438,9 @@ } tap; struct { + struct libinput_device_config_dwtp config; + bool dwtp_enabled; + int32_t right_edge; /* in device coordinates */ int32_t left_edge; /* in device coordinates */ int32_t upper_edge; /* in device coordinates */
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/evdev-tablet-pad-leds.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/evdev-tablet-pad-leds.c
Changed
@@ -412,7 +412,7 @@ return 1; } - group->button_mask |= 1 << i; + group->button_mask |= bit(i); if (flags & WACOM_BUTTON_MODESWITCH) { struct pad_mode_toggle_button *b; @@ -423,7 +423,7 @@ return 1; g = (struct pad_led_group*)group; list_insert(&g->toggle_button_list, &b->link); - group->toggle_button_mask |= 1 << i; + group->toggle_button_mask |= bit(i); } }
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/evdev-tablet-pad.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/evdev-tablet-pad.c
Changed
@@ -556,15 +556,27 @@ WacomDevice *tablet = NULL; int num_buttons; int map = 0; + char event_path64; db = libinput_libwacom_ref(li); if (!db) goto out; - tablet = libwacom_new_from_usbid(db, - evdev_device_get_id_vendor(device), - evdev_device_get_id_product(device), - NULL); + snprintf(event_path, + sizeof(event_path), + "/dev/input/%s", + evdev_device_get_sysname(device)); + tablet = libwacom_new_from_path(db, + event_path, + WFALLBACK_NONE, + NULL); + if (!tablet) { + tablet = libwacom_new_from_usbid(db, + evdev_device_get_id_vendor(device), + evdev_device_get_id_product(device), + NULL); + } + if (!tablet) goto out; @@ -630,7 +642,6 @@ KEY_ONSCREEN_KEYBOARD, KEY_CONTROLPANEL, }; - unsigned int *code; /* Wacom's keys are the only ones we know anything about */ if (libevdev_get_id_vendor(device->evdev) != VENDOR_ID_WACOM)
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/evdev-tablet.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/evdev-tablet.c
Changed
@@ -353,30 +353,20 @@ normalize_pressure(const struct input_absinfo *absinfo, struct libinput_tablet_tool *tool) { - int offset; - double range; - double value; - /** - * If the tool has a pressure offset, we use that as the lower bound - * for the scaling range. If not, we use the upper threshold as the - * lower bound, so once we get past that minimum physical pressure - * we have logical 0 pressure. + * Note: the upper threshold takes the offset into account so that + * |- 4% -| + * min |------X------X-------------------------| max + * | | + * | + upper threshold / tip trigger + * +- offset and lower threshold * - * This means that there is a small range (lower-upper) where - * different physical pressure (default: 1-5%) result in the same - * logical pressure. This is, hopefully, not noticeable. - * - * Note that that lower-upper range gives us a negative pressure, so - * we have to clip to 0 for those. + * The axis is scaled into the range lower, max so that the lower + * threshold is 0 pressure. */ - - if (tool->pressure.has_offset) - offset = tool->pressure.offset; - else - offset = tool->pressure.threshold.upper; - range = absinfo->maximum - offset; - value = (absinfo->value - offset) / range; + int base = tool->pressure.threshold.lower; + double range = absinfo->maximum - base; + double value = (absinfo->value - base) / range; return max(0.0, value); } @@ -465,6 +455,10 @@ const struct input_absinfo *absinfo; int value; + if (!libevdev_has_event_code(device->evdev, EV_ABS, ABS_X) || + !libevdev_has_event_code(device->evdev, EV_ABS, ABS_Y)) + return; + if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_X) || bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_Y)) { absinfo = libevdev_get_abs_info(device->evdev, ABS_X); @@ -538,6 +532,9 @@ { const struct input_absinfo *absinfo; + if (!libevdev_has_event_code(device->evdev, EV_ABS, ABS_PRESSURE)) + return; + if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE)) { absinfo = libevdev_get_abs_info(device->evdev, ABS_PRESSURE); @@ -551,6 +548,9 @@ { const struct input_absinfo *absinfo; + if (!libevdev_has_event_code(device->evdev, EV_ABS, ABS_DISTANCE)) + return; + if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_DISTANCE)) { absinfo = libevdev_get_abs_info(device->evdev, ABS_DISTANCE); @@ -564,6 +564,9 @@ { const struct input_absinfo *absinfo; + if (!libevdev_has_event_code(device->evdev, EV_ABS, ABS_WHEEL)) + return; + if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_SLIDER)) { absinfo = libevdev_get_abs_info(device->evdev, ABS_WHEEL); @@ -577,6 +580,10 @@ { const struct input_absinfo *absinfo; + if (!libevdev_has_event_code(device->evdev, EV_ABS, ABS_TILT_X) || + !libevdev_has_event_code(device->evdev, EV_ABS, ABS_TILT_Y)) + return; + /* mouse rotation resets tilt to 0 so always fetch both axes if * either has changed */ if (bit_is_set(tablet->changed_axes, @@ -603,6 +610,9 @@ { const struct input_absinfo *absinfo; + if (!libevdev_has_event_code(device->evdev, EV_ABS, ABS_Z)) + return; + if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z)) { absinfo = libevdev_get_abs_info(device->evdev, @@ -1249,16 +1259,19 @@ if (!pressure || !distance) return; - if (!bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_DISTANCE) && - !bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE)) + bool pressure_changed = bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE); + bool distance_changed = bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_DISTANCE); + + if (!pressure_changed && !distance_changed) return; - tool_in_contact = (pressure->value > tool->pressure.offset); + /* Note: this is an arbitrary "in contact" decision rather than "tip + * down". We use the lower threshold as minimum pressure value, + * anything less than that gets filtered away */ + tool_in_contact = (pressure->value > tool->pressure.threshold.lower); /* Keep distance and pressure mutually exclusive */ if (distance && - (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_DISTANCE) || - bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE)) && distance->value > distance->minimum && pressure->value > pressure->minimum) { if (tool_in_contact) { @@ -1270,8 +1283,7 @@ LIBINPUT_TABLET_TOOL_AXIS_PRESSURE); tablet->axes.pressure = 0; } - } else if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE) && - !tool_in_contact) { + } else if (pressure_changed && !tool_in_contact) { /* Make sure that the last axis value sent to the caller is a 0 */ if (tablet->axes.pressure == 0) clear_bit(tablet->changed_axes, @@ -1328,7 +1340,7 @@ */ if (tool->pressure.has_offset) { if (offset < tool->pressure.offset) - tool->pressure.offset = offset; + goto set_offset; return; } @@ -1360,9 +1372,17 @@ tablet_tool_type_to_string(tool->type), tool->serial, HTTP_DOC_LINK); +set_offset: tool->pressure.offset = offset; tool->pressure.has_offset = true; - tool->pressure.threshold.lower = pressure->minimum; + + /* Adjust the tresholds accordingly - we use the same gap (4% in + * device coordinates) between upper and lower as before which isn't + * technically correct (our range shrunk) but it's easy to calculate. + */ + int gap = tool->pressure.threshold.upper - tool->pressure.threshold.lower; + tool->pressure.threshold.lower = offset; + tool->pressure.threshold.upper = offset + gap; } static void @@ -1393,9 +1413,6 @@ } pressure = p->value; - if (tool->pressure.has_offset) - pressure -= (tool->pressure.offset - p->minimum); - if (pressure <= tool->pressure.threshold.lower && tablet_has_status(tablet, TABLET_TOOL_IN_CONTACT)) { tablet_set_status(tablet, TABLET_TOOL_LEAVING_CONTACT); @@ -1484,8 +1501,8 @@ mm = evdev_device_units_to_mm(device, &tablet->axes.point); - /* The rect we disable is 20mm left of the tip, 50mm north of the - * tip, and 200x200mm large. + /* The rect we disable is 20mm left of the tip, 100mm north of the + * tip, and 200x250mm large. * If the stylus is tilted left (tip further right than the eraser * end) assume left-handed mode. * @@ -1506,8 +1523,8 @@ r.x = 0; } - r.y = mm.y - 50; - r.h = 200; + r.y = mm.y - 100; + r.h = 250; if (r.y < 0) { r.h -= r.y; r.y = 0; @@ -1810,20 +1827,35 @@
View file
_service:tar_scm:libinput-1.22.1.tar.gz/src/evdev-wheel.c
Added
@@ -0,0 +1,440 @@ +/* + * Copyright © 2010 Intel Corporation + * Copyright © 2013 Jonas Ådahl + * Copyright © 2013-2017 Red Hat, Inc. + * Copyright © 2017 James Ye <jye836@gmail.com> + * Copyright © 2021 José Expósito + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include "evdev-fallback.h" +#include "util-input-event.h" + +#define ACC_V120_THRESHOLD 60 +#define WHEEL_SCROLL_TIMEOUT ms2us(500) + +enum wheel_event { + WHEEL_EVENT_SCROLL_ACCUMULATED, + WHEEL_EVENT_SCROLL, + WHEEL_EVENT_SCROLL_TIMEOUT, + WHEEL_EVENT_SCROLL_DIR_CHANGED, +}; + +static inline const char * +wheel_state_to_str(enum wheel_state state) +{ + switch(state) { + CASE_RETURN_STRING(WHEEL_STATE_NONE); + CASE_RETURN_STRING(WHEEL_STATE_ACCUMULATING_SCROLL); + CASE_RETURN_STRING(WHEEL_STATE_SCROLLING); + } + return NULL; +} + +static inline const char* +wheel_event_to_str(enum wheel_event event) +{ + switch(event) { + CASE_RETURN_STRING(WHEEL_EVENT_SCROLL_ACCUMULATED); + CASE_RETURN_STRING(WHEEL_EVENT_SCROLL); + CASE_RETURN_STRING(WHEEL_EVENT_SCROLL_TIMEOUT); + CASE_RETURN_STRING(WHEEL_EVENT_SCROLL_DIR_CHANGED); + } + return NULL; +} + +static inline void +log_wheel_bug(struct fallback_dispatch *dispatch, enum wheel_event event) +{ + evdev_log_bug_libinput(dispatch->device, + "invalid wheel event %s in state %s\n", + wheel_event_to_str(event), + wheel_state_to_str(dispatch->wheel.state)); +} + +static inline void +wheel_set_scroll_timer(struct fallback_dispatch *dispatch, uint64_t time) +{ + libinput_timer_set(&dispatch->wheel.scroll_timer, + time + WHEEL_SCROLL_TIMEOUT); +} + +static inline void +wheel_cancel_scroll_timer(struct fallback_dispatch *dispatch) +{ + libinput_timer_cancel(&dispatch->wheel.scroll_timer); +} + +static void +wheel_handle_event_on_state_none(struct fallback_dispatch *dispatch, + enum wheel_event event, + uint64_t time) +{ + switch (event) { + case WHEEL_EVENT_SCROLL: + dispatch->wheel.state = WHEEL_STATE_ACCUMULATING_SCROLL; + break; + case WHEEL_EVENT_SCROLL_DIR_CHANGED: + break; + case WHEEL_EVENT_SCROLL_ACCUMULATED: + case WHEEL_EVENT_SCROLL_TIMEOUT: + log_wheel_bug(dispatch, event); + break; + } +} + +static void +wheel_handle_event_on_state_accumulating_scroll(struct fallback_dispatch *dispatch, + enum wheel_event event, + uint64_t time) +{ + switch (event) { + case WHEEL_EVENT_SCROLL_ACCUMULATED: + dispatch->wheel.state = WHEEL_STATE_SCROLLING; + wheel_set_scroll_timer(dispatch, time); + break; + case WHEEL_EVENT_SCROLL: + /* Ignore scroll while accumulating deltas */ + break; + case WHEEL_EVENT_SCROLL_DIR_CHANGED: + dispatch->wheel.state = WHEEL_STATE_NONE; + break; + case WHEEL_EVENT_SCROLL_TIMEOUT: + log_wheel_bug(dispatch, event); + break; + } +} + +static void +wheel_handle_event_on_state_scrolling(struct fallback_dispatch *dispatch, + enum wheel_event event, + uint64_t time) +{ + switch (event) { + case WHEEL_EVENT_SCROLL: + wheel_cancel_scroll_timer(dispatch); + wheel_set_scroll_timer(dispatch, time); + break; + case WHEEL_EVENT_SCROLL_TIMEOUT: + dispatch->wheel.state = WHEEL_STATE_NONE; + break; + case WHEEL_EVENT_SCROLL_DIR_CHANGED: + wheel_cancel_scroll_timer(dispatch); + dispatch->wheel.state = WHEEL_STATE_NONE; + break; + case WHEEL_EVENT_SCROLL_ACCUMULATED: + log_wheel_bug(dispatch, event); + break; + } +} + +static void +wheel_handle_event(struct fallback_dispatch *dispatch, + enum wheel_event event, + uint64_t time) +{ + enum wheel_state oldstate = dispatch->wheel.state; + + switch (oldstate) { + case WHEEL_STATE_NONE: + wheel_handle_event_on_state_none(dispatch, event, time); + break; + case WHEEL_STATE_ACCUMULATING_SCROLL: + wheel_handle_event_on_state_accumulating_scroll(dispatch, + event, + time); + break; + case WHEEL_STATE_SCROLLING: + wheel_handle_event_on_state_scrolling(dispatch, event, time); + break; + } + + if (oldstate != dispatch->wheel.state) { + evdev_log_debug(dispatch->device, + "wheel state %s → %s → %s\n", + wheel_state_to_str(oldstate), + wheel_event_to_str(event), + wheel_state_to_str(dispatch->wheel.state)); + } +} + +static void +wheel_flush_scroll(struct fallback_dispatch *dispatch, + struct evdev_device *device, + uint64_t time) +{ + struct normalized_coords wheel_degrees = { 0.0, 0.0 }; + struct discrete_coords discrete = { 0.0, 0.0 }; + struct wheel_v120 v120 = { 0.0, 0.0 }; + + /* This mouse has a trackstick instead of a mouse wheel and sends + * trackstick data via REL_WHEEL. Normalize it like normal x/y coordinates. + */ + if (device->model_flags & EVDEV_MODEL_LENOVO_SCROLLPOINT) { + const struct device_float_coords raw = { + .x = dispatch->wheel.lo_res.x, + .y = dispatch->wheel.lo_res.y * -1, + }; + const struct normalized_coords normalized = + filter_dispatch_constant(device->pointer.filter,
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/evdev.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/evdev.c
Changed
@@ -53,18 +53,18 @@ #define DEFAULT_BUTTON_SCROLL_TIMEOUT ms2us(200) enum evdev_device_udev_tags { - EVDEV_UDEV_TAG_INPUT = bit(0), - EVDEV_UDEV_TAG_KEYBOARD = bit(1), - EVDEV_UDEV_TAG_MOUSE = bit(2), - EVDEV_UDEV_TAG_TOUCHPAD = bit(3), - EVDEV_UDEV_TAG_TOUCHSCREEN = bit(4), - EVDEV_UDEV_TAG_TABLET = bit(5), - EVDEV_UDEV_TAG_JOYSTICK = bit(6), - EVDEV_UDEV_TAG_ACCELEROMETER = bit(7), - EVDEV_UDEV_TAG_TABLET_PAD = bit(8), - EVDEV_UDEV_TAG_POINTINGSTICK = bit(9), - EVDEV_UDEV_TAG_TRACKBALL = bit(10), - EVDEV_UDEV_TAG_SWITCH = bit(11), + EVDEV_UDEV_TAG_INPUT = bit(0), + EVDEV_UDEV_TAG_KEYBOARD = bit(1), + EVDEV_UDEV_TAG_MOUSE = bit(2), + EVDEV_UDEV_TAG_TOUCHPAD = bit(3), + EVDEV_UDEV_TAG_TOUCHSCREEN = bit(4), + EVDEV_UDEV_TAG_TABLET = bit(5), + EVDEV_UDEV_TAG_JOYSTICK = bit(6), + EVDEV_UDEV_TAG_ACCELEROMETER = bit(7), + EVDEV_UDEV_TAG_TABLET_PAD = bit(8), + EVDEV_UDEV_TAG_POINTINGSTICK = bit(9), + EVDEV_UDEV_TAG_TRACKBALL = bit(10), + EVDEV_UDEV_TAG_SWITCH = bit(11), }; struct evdev_udev_tag_match { @@ -88,6 +88,19 @@ {"ID_INPUT_SWITCH", EVDEV_UDEV_TAG_SWITCH}, }; +static const unsigned int well_known_keyboard_keys = { + KEY_LEFTCTRL, + KEY_CAPSLOCK, + KEY_NUMLOCK, + KEY_INSERT, + KEY_MUTE, + KEY_CALC, + KEY_FILE, + KEY_MAIL, + KEY_PLAYPAUSE, + KEY_BRIGHTNESSDOWN, +}; + static inline bool parse_udev_flag(struct evdev_device *device, struct udev_device *udev_device, @@ -994,13 +1007,13 @@ quirks = evdev_libinput_context(device)->quirks; q = quirks_fetch_for_device(quirks, device->udev_device); if (!q || !quirks_get_string(q, QUIRK_ATTR_LID_SWITCH_RELIABILITY, &prop)) { - r = RELIABILITY_UNKNOWN; + r = RELIABILITY_RELIABLE; } else if (!parse_switch_reliability_property(prop, &r)) { evdev_log_error(device, "%s: switch reliability set to unknown value '%s'\n", device->devname, prop); - r = RELIABILITY_UNKNOWN; + r = RELIABILITY_RELIABLE; } else if (r == RELIABILITY_WRITE_OPEN) { evdev_log_info(device, "will write switch open events\n"); } @@ -1010,6 +1023,7 @@ return r; } +LIBINPUT_UNUSED static inline void evdev_print_event(struct evdev_device *device, const struct input_event *e) @@ -1113,7 +1127,7 @@ return; tdelta = us2ms(libinput->dispatch_time - eventtime); - if (tdelta > 10) { + if (tdelta > 20) { evdev_log_bug_client_ratelimit(device, &device->delay_warning_limit, "event processing lagging behind by %dms, your system is too slow\n", @@ -1172,17 +1186,23 @@ evdev_init_accel(struct evdev_device *device, enum libinput_config_accel_profile which) { - struct motion_filter *filter; + struct motion_filter *filter = NULL; - if (which == LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT) - filter = create_pointer_accelerator_filter_flat(device->dpi); - else if (device->tags & EVDEV_TAG_TRACKPOINT) - filter = create_pointer_accelerator_filter_trackpoint(device->trackpoint_multiplier, - device->use_velocity_averaging); - else if (device->dpi < DEFAULT_MOUSE_DPI) - filter = create_pointer_accelerator_filter_linear_low_dpi(device->dpi, - device->use_velocity_averaging); - else + if (device->tags & EVDEV_TAG_TRACKPOINT) { + if (which == LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT) + filter = create_pointer_accelerator_filter_trackpoint_flat(device->trackpoint_multiplier); + else + filter = create_pointer_accelerator_filter_trackpoint(device->trackpoint_multiplier, + device->use_velocity_averaging); + } else { + if (which == LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT) + filter = create_pointer_accelerator_filter_flat(device->dpi); + else if (device->dpi < DEFAULT_MOUSE_DPI) + filter = create_pointer_accelerator_filter_linear_low_dpi(device->dpi, + device->use_velocity_averaging); + } + + if (!filter) filter = create_pointer_accelerator_filter_linear(device->dpi, device->use_velocity_averaging); @@ -1850,6 +1870,85 @@ libevdev_disable_event_code(evdev, EV_ABS, REL_Z); } +static bool +evdev_device_is_joystick_or_gamepad(struct evdev_device *device) +{ + enum evdev_device_udev_tags udev_tags; + bool has_joystick_tags; + struct libevdev *evdev = device->evdev; + unsigned int code; + + /* The EVDEV_UDEV_TAG_JOYSTICK is set when a joystick or gamepad button + * is found. However, it can not be used to identify joysticks or + * gamepads because there are keyboards that also have it. Even worse, + * many joysticks also map KEY_* and thus are tagged as keyboards. + * + * In order to be able to detect joysticks and gamepads and + * differentiate them from keyboards, apply the following rules: + * + * 1. The device is tagged as joystick but not as tablet + * 2. The device doesn't have 4 well-known keyboard keys + * 3. It has at least 2 joystick buttons + * 4. It doesn't have 10 keyboard keys */ + + udev_tags = evdev_device_get_udev_tags(device, device->udev_device); + has_joystick_tags = (udev_tags & EVDEV_UDEV_TAG_JOYSTICK) && + !(udev_tags & EVDEV_UDEV_TAG_TABLET) && + !(udev_tags & EVDEV_UDEV_TAG_TABLET_PAD); + + if (!has_joystick_tags) + return false; + + + unsigned int num_well_known_keys = 0; + + for (size_t i = 0; i < ARRAY_LENGTH(well_known_keyboard_keys); i++) { + code = well_known_keyboard_keysi; + if (libevdev_has_event_code(evdev, EV_KEY, code)) + num_well_known_keys++; + } + + if (num_well_known_keys >= 4) /* should not have 4 well-known keys */ + return false; + + unsigned int num_joystick_btns = 0; + + for (code = BTN_JOYSTICK; code < BTN_DIGI; code++) { + if (libevdev_has_event_code(evdev, EV_KEY, code)) + num_joystick_btns++; + } + + for (code = BTN_TRIGGER_HAPPY; code <= BTN_TRIGGER_HAPPY40; code++) { + if (libevdev_has_event_code(evdev, EV_KEY, code)) + num_joystick_btns++; + } + + if (num_joystick_btns < 2) /* require at least 2 joystick buttons */ + return false; + + unsigned int num_keys = 0; + + for (code = KEY_ESC; code <= KEY_MICMUTE; code++) { + if (libevdev_has_event_code(evdev, EV_KEY, code) ) + num_keys++; + } + + for (code = KEY_OK; code <= KEY_LIGHTS_TOGGLE; code++) { + if (libevdev_has_event_code(evdev, EV_KEY, code) ) + num_keys++; + } + + for (code = KEY_ALS_TOGGLE; code < BTN_TRIGGER_HAPPY; code++) { + if (libevdev_has_event_code(evdev, EV_KEY, code) ) + num_keys++; + } + + if (num_keys >= 10) /* should not have 10 keyboard keys */ + return false; + + return true; +}
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/evdev.h -> _service:tar_scm:libinput-1.22.1.tar.gz/src/evdev.h
Changed
@@ -169,6 +169,8 @@ struct udev_device *udev_device; char *output_name; const char *devname; + char *log_prefix_name; + char *sysname; bool was_removed; int fd; enum evdev_device_seat_capability seat_caps; @@ -786,7 +788,7 @@ sizeof(buf), "%-7s - %s%s%s", evdev_device_get_sysname(device), - (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? device->devname : "", + (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? device->log_prefix_name : "", (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? ": " : "", format); @@ -824,7 +826,7 @@ sizeof(buf), "%-7s - %s%s%s", evdev_device_get_sysname(device), - (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? device->devname : "", + (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? device->log_prefix_name : "", (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? ": " : "", format);
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/filter-flat.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/filter-flat.c
Changed
@@ -65,10 +65,18 @@ const struct device_float_coords *unaccelerated, void *data, uint64_t time) { - struct pointer_accelerator_flat *accel = - (struct pointer_accelerator_flat *) filter; - - return normalize_for_dpi(unaccelerated, accel->dpi); + /* We map the unaccelerated flat filter to have the same behavior as + * the "accelerated" flat filter. + * The filter by definition is flat, i.e. it does not actually + * apply any acceleration (merely a constant factor) and we can assume + * that a user wants all mouse movement to have the same speed, mapped + * 1:1 to the input speed. + * + * Thus we apply the same factor to our non-accelerated motion - this way + * things like button scrolling end up having the same movement as + * pointer motion. + */ + return accelerator_filter_flat(filter, unaccelerated, data, time); } static bool @@ -100,7 +108,7 @@ free(accel); } -struct motion_filter_interface accelerator_interface_flat = { +static const struct motion_filter_interface accelerator_interface_flat = { .type = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT, .filter = accelerator_filter_flat, .filter_constant = accelerator_filter_noop_flat,
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/filter-low-dpi.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/filter-low-dpi.c
Changed
@@ -125,42 +125,23 @@ return accel_factor; } -static struct device_float_coords -accelerator_filter_generic(struct motion_filter *filter, +static struct normalized_coords +accelerator_filter_low_dpi(struct motion_filter *filter, const struct device_float_coords *unaccelerated, void *data, uint64_t time) { struct pointer_accelerator_low_dpi *accel = (struct pointer_accelerator_low_dpi *) filter; - double accel_value; /* unitless factor */ - struct device_float_coords accelerated; - - accel_value = calculate_acceleration_factor(accel, - unaccelerated, - data, - time); - - accelerated.x = accel_value * unaccelerated->x; - accelerated.y = accel_value * unaccelerated->y; - - return accelerated; -} - -static struct normalized_coords -accelerator_filter_unnormalized(struct motion_filter *filter, - const struct device_float_coords *unaccelerated, - void *data, uint64_t time) -{ - struct device_float_coords accelerated; - struct normalized_coords normalized; /* Accelerate for device units and return device units */ - accelerated = accelerator_filter_generic(filter, - unaccelerated, - data, - time); - normalized.x = accelerated.x; - normalized.y = accelerated.y; + double accel_factor = calculate_acceleration_factor(accel, + unaccelerated, + data, + time); + const struct normalized_coords normalized = { + .x = accel_factor * unaccelerated->x, + .y = accel_factor * unaccelerated->y, + }; return normalized; } @@ -169,10 +150,11 @@ const struct device_float_coords *unaccelerated, void *data, uint64_t time) { - struct pointer_accelerator_low_dpi *accel = - (struct pointer_accelerator_low_dpi *) filter; - - return normalize_for_dpi(unaccelerated, accel->dpi); + const struct normalized_coords normalized = { + .x = unaccelerated->x, + .y = unaccelerated->y, + }; + return normalized; } static void @@ -224,9 +206,9 @@ return true; } -struct motion_filter_interface accelerator_interface_low_dpi = { +static const struct motion_filter_interface accelerator_interface_low_dpi = { .type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE, - .filter = accelerator_filter_unnormalized, + .filter = accelerator_filter_low_dpi, .filter_constant = accelerator_filter_noop, .restart = accelerator_restart, .destroy = accelerator_destroy,
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/filter-mouse.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/filter-mouse.c
Changed
@@ -72,84 +72,55 @@ */ static inline double calculate_acceleration_factor(struct pointer_accelerator *accel, - const struct device_float_coords *unaccelerated, + const struct normalized_coords *unaccelerated, void *data, uint64_t time) { - double velocity; /* units/us in device-native dpi*/ + double velocity; /* units/us in normalized 1000dpi units*/ double accel_factor; - trackers_feed(&accel->trackers, unaccelerated, time); + /* The trackers API need device_float_coords, but note that we have + * normalized coordinates */ + const struct device_float_coords unaccel = { + .x = unaccelerated->x, + .y = unaccelerated->y, + }; + trackers_feed(&accel->trackers, &unaccel, time); velocity = trackers_velocity(&accel->trackers, time); + /* This will call into our pointer_accel_profile_linear() profile func */ accel_factor = calculate_acceleration_simpsons(&accel->base, accel->profile, data, - velocity, - accel->last_velocity, + velocity, /* normalized coords */ + accel->last_velocity, /* normalized coords */ time); accel->last_velocity = velocity; return accel_factor; } -/** - * Generic filter that calculates the acceleration factor and applies it to - * the coordinates. - * - * @param filter The acceleration filter - * @param unaccelerated The raw delta in the device's dpi - * @param data Caller-specific data - * @param time Current time in µs - * - * @return An accelerated tuple of coordinates representing accelerated - * motion, still in device units. - */ -static struct device_float_coords -accelerator_filter_generic(struct motion_filter *filter, - const struct device_float_coords *unaccelerated, - void *data, uint64_t time) +static struct normalized_coords +accelerator_filter_linear(struct motion_filter *filter, + const struct device_float_coords *unaccelerated, + void *data, uint64_t time) { struct pointer_accelerator *accel = (struct pointer_accelerator *) filter; - double accel_value; /* unitless factor */ - struct device_float_coords accelerated; - - accel_value = calculate_acceleration_factor(accel, - unaccelerated, - data, - time); - - accelerated.x = accel_value * unaccelerated->x; - accelerated.y = accel_value * unaccelerated->y; + /* Accelerate for normalized units and return normalized units */ + const struct normalized_coords normalized = normalize_for_dpi(unaccelerated, + accel->dpi); + double accel_factor = calculate_acceleration_factor(accel, + &normalized, + data, + time); + struct normalized_coords accelerated = { + .x = normalized.x * accel_factor, + .y = normalized.y * accel_factor, + }; return accelerated; } -static struct normalized_coords -accelerator_filter_pre_normalized(struct motion_filter *filter, - const struct device_float_coords *unaccelerated, - void *data, uint64_t time) -{ - struct pointer_accelerator *accel = - (struct pointer_accelerator *) filter; - struct normalized_coords normalized; - struct device_float_coords converted, accelerated; - - /* Accelerate for normalized units and return normalized units. - API requires device_floats, so we just copy the bits around */ - normalized = normalize_for_dpi(unaccelerated, accel->dpi); - converted.x = normalized.x; - converted.y = normalized.y; - - accelerated = accelerator_filter_generic(filter, - &converted, - data, - time); - normalized.x = accelerated.x; - normalized.y = accelerated.y; - return normalized; -} - /** * Generic filter that does nothing beyond converting from the device's * native dpi into normalized coordinates. @@ -225,7 +196,7 @@ double pointer_accel_profile_linear(struct motion_filter *filter, void *data, - double speed_in, /* in device units (units/µs) */ + double speed_in, /* in normalized units */ uint64_t time) { struct pointer_accelerator *accel_filter = @@ -235,9 +206,6 @@ const double incline = accel_filter->incline; double factor; /* unitless */ - /* Normalize to 1000dpi, because the rest below relies on that */ - speed_in = speed_in * DEFAULT_MOUSE_DPI/accel_filter->dpi; - /* Our acceleration function calculates a factor to accelerate input deltas with. The function is a double incline with a plateau, @@ -298,9 +266,9 @@ return factor; } -struct motion_filter_interface accelerator_interface = { +static const struct motion_filter_interface accelerator_interface = { .type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE, - .filter = accelerator_filter_pre_normalized, + .filter = accelerator_filter_linear, .filter_constant = accelerator_filter_noop, .restart = accelerator_restart, .destroy = accelerator_destroy,
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/filter-private.h -> _service:tar_scm:libinput-1.22.1.tar.gz/src/filter-private.h
Changed
@@ -48,7 +48,7 @@ struct motion_filter { double speed_adjustment; /* normalized -1, 1 */ - struct motion_filter_interface *interface; + const struct motion_filter_interface *interface; }; struct pointer_tracker {
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/filter-tablet.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/filter-tablet.c
Changed
@@ -143,7 +143,7 @@ free(accel_filter); } -struct motion_filter_interface accelerator_interface_tablet = { +static const struct motion_filter_interface accelerator_interface_tablet = { .type = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT, .filter = tablet_accelerator_filter_flat, .filter_constant = NULL,
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/filter-touchpad-flat.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/filter-touchpad-flat.c
Changed
@@ -46,42 +46,46 @@ static struct normalized_coords accelerator_filter_touchpad_flat(struct motion_filter *filter, - const struct device_float_coords *unaccelerated, - void *data, uint64_t time) + const struct device_float_coords *unaccelerated, + void *data, uint64_t time) { - struct touchpad_accelerator_flat *accel_filter = + struct touchpad_accelerator_flat *accel = (struct touchpad_accelerator_flat *)filter; double factor; /* unitless factor */ - struct normalized_coords accelerated; + struct normalized_coords normalized; /* You want flat acceleration, you get flat acceleration for the * device */ - factor = accel_filter->factor; - accelerated.x = TP_MAGIC_SLOWDOWN_FLAT * factor * unaccelerated->x; - accelerated.y = TP_MAGIC_SLOWDOWN_FLAT * factor * unaccelerated->y; + factor = accel->factor; + normalized = normalize_for_dpi(unaccelerated, accel->dpi); + normalized.x = TP_MAGIC_SLOWDOWN_FLAT * factor * normalized.x; + normalized.y = TP_MAGIC_SLOWDOWN_FLAT * factor * normalized.y; - return accelerated; + return normalized; } static struct normalized_coords accelerator_filter_noop_touchpad_flat(struct motion_filter *filter, - const struct device_float_coords *unaccelerated, - void *data, uint64_t time) + const struct device_float_coords *unaccelerated, + void *data, uint64_t time) { - struct touchpad_accelerator_flat *accel = - (struct touchpad_accelerator_flat *) filter; - struct normalized_coords normalized; - - normalized = normalize_for_dpi(unaccelerated, accel->dpi); - normalized.x = TP_MAGIC_SLOWDOWN_FLAT * normalized.x; - normalized.y = TP_MAGIC_SLOWDOWN_FLAT * normalized.y; - - return normalized; + /* We map the unaccelerated flat filter to have the same behavior as + * the "accelerated" flat filter. + * The filter by definition is flat, i.e. it does not actually + * apply any acceleration (merely a constant factor) and we can assume + * that a user wants all mouse movement to have the same speed, mapped + * 1:1 to the input speed. + * + * Thus we apply the same factor to our non-accelerated motion - this way + * things like gestures end up having the same movement as + * pointer motion. + */ + return accelerator_filter_touchpad_flat(filter, unaccelerated, data, time); } static bool accelerator_set_speed_touchpad_flat(struct motion_filter *filter, - double speed_adjustment) + double speed_adjustment) { struct touchpad_accelerator_flat *accel_filter = (struct touchpad_accelerator_flat *)filter; @@ -103,7 +107,7 @@ free(accel); } -struct motion_filter_interface accelerator_interface_touchpad_flat = { +static const struct motion_filter_interface accelerator_interface_touchpad_flat = { .type = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT, .filter = accelerator_filter_touchpad_flat, .filter_constant = accelerator_filter_noop_touchpad_flat,
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/filter-touchpad-x230.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/filter-touchpad-x230.c
Changed
@@ -283,7 +283,7 @@ return factor * X230_MAGIC_SLOWDOWN / X230_TP_MAGIC_LOW_RES_FACTOR; } -struct motion_filter_interface accelerator_interface_x230 = { +static const struct motion_filter_interface accelerator_interface_x230 = { .type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE, .filter = accelerator_filter_x230, .filter_constant = accelerator_filter_constant_x230,
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/filter-touchpad.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/filter-touchpad.c
Changed
@@ -90,53 +90,24 @@ return accel_factor; } -/** - * Generic filter that calculates the acceleration factor and applies it to - * the coordinates. - * - * @param filter The acceleration filter - * @param unaccelerated The raw delta in the device's dpi - * @param data Caller-specific data - * @param time Current time in µs - * - * @return An accelerated tuple of coordinates representing accelerated - * motion, still in device units. - */ -static struct device_float_coords -accelerator_filter_generic(struct motion_filter *filter, - const struct device_float_coords *unaccelerated, - void *data, uint64_t time) -{ - struct touchpad_accelerator *accel = - (struct touchpad_accelerator *) filter; - double accel_value; /* unitless factor */ - struct device_float_coords accelerated; - - accel_value = calculate_acceleration_factor(accel, - unaccelerated, - data, - time); - - accelerated.x = accel_value * unaccelerated->x; - accelerated.y = accel_value * unaccelerated->y; - - return accelerated; -} - static struct normalized_coords -accelerator_filter_post_normalized(struct motion_filter *filter, - const struct device_float_coords *unaccelerated, - void *data, uint64_t time) +accelerator_filter_touchpad(struct motion_filter *filter, + const struct device_float_coords *unaccelerated, + void *data, uint64_t time) { struct touchpad_accelerator *accel = (struct touchpad_accelerator *) filter; - struct device_float_coords accelerated; /* Accelerate for device units, normalize afterwards */ - accelerated = accelerator_filter_generic(filter, - unaccelerated, - data, - time); + double accel_factor = calculate_acceleration_factor(accel, + unaccelerated, + data, + time); + const struct device_float_coords accelerated = { + .x = unaccelerated->x * accel_factor, + .y = unaccelerated->y * accel_factor, + }; + return normalize_for_dpi(&accelerated, accel->dpi); } @@ -313,9 +284,9 @@ return factor * TP_MAGIC_SLOWDOWN; } -struct motion_filter_interface accelerator_interface_touchpad = { +static const struct motion_filter_interface accelerator_interface_touchpad = { .type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE, - .filter = accelerator_filter_post_normalized, + .filter = accelerator_filter_touchpad, .filter_constant = touchpad_constant_filter, .restart = touchpad_accelerator_restart, .destroy = touchpad_accelerator_destroy,
View file
_service:tar_scm:libinput-1.22.1.tar.gz/src/filter-trackpoint-flat.c
Added
@@ -0,0 +1,148 @@ +/* + * Copyright © 2006-2009 Simon Thum + * Copyright © 2012 Jonas Ådahl + * Copyright © 2014-2015 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "filter.h" +#include "libinput-util.h" +#include "filter-private.h" + +struct trackpoint_flat_accelerator { + struct motion_filter base; + + double speed_factor; + double multiplier; +}; + +static struct normalized_coords +trackpoint_flat_filter(struct motion_filter *filter, + const struct device_float_coords *unaccelerated, + void *data, uint64_t time) +{ + struct trackpoint_flat_accelerator *accel_filter = + (struct trackpoint_flat_accelerator *) filter; + struct normalized_coords accelerated; + + double factor = accel_filter->speed_factor; + double multiplier = accel_filter->multiplier; + accelerated.x = factor * multiplier * unaccelerated->x; + accelerated.y = factor * multiplier * unaccelerated->y; + + return accelerated; +} + +static struct normalized_coords +trackpoint_flat_filter_noop(struct motion_filter *filter, + const struct device_float_coords *unaccelerated, + void *data, uint64_t time) +{ + /* We map the unaccelerated flat filter to have the same behavior as + * the "accelerated" flat filter. + * The filter by definition is flat, i.e. it does not actually + * apply any acceleration (merely a constant factor) and we can assume + * that a user wants all mouse movement to have the same speed, mapped + * 1:1 to the input speed. + * + * Thus we apply the same factor to our non-accelerated motion - this way + * things like button scrolling end up having the same movement as + * pointer motion. + */ + return trackpoint_flat_filter(filter, unaccelerated, data, time); +} + +/* Maps the -1, 1 speed setting into a constant acceleration + * range. This isn't a linear scale, we keep 0 as the 'optimized' + * mid-point and scale down to 0 for setting -1 and up to 5 for + * setting 1. On the premise that if you want a faster cursor, it + * doesn't matter as much whether you have 0.56789 or 0.56790, + * but for lower settings it does because you may lose movements. + * *shrug*. + * + * Magic numbers calculated by MyCurveFit.com, data points were + * 0.0 0.0 + * 0.1 0.1 (because we need 4 points) + * 1 1 + * 2 5 + * + * This curve fits nicely into the range necessary. + */ +static inline double +speed_factor(double s) +{ + s += 1; /* map to 0, 2 */ + return 435837.2 + (0.04762636 - 435837.2)/(1 + pow(s/240.4549, + 2.377168)); +} + +static bool +trackpoint_flat_set_speed(struct motion_filter *filter, + double speed_adjustment) +{ + struct trackpoint_flat_accelerator *accel_filter = + (struct trackpoint_flat_accelerator *) filter; + + assert(speed_adjustment >= -1.0 && speed_adjustment <= 1.0); + + filter->speed_adjustment = speed_adjustment; + accel_filter->speed_factor = speed_factor(speed_adjustment); + + + return true; +} + +static void +trackpoint_flat_destroy(struct motion_filter *filter) +{ + struct trackpoint_flat_accelerator *accel_filter = + (struct trackpoint_flat_accelerator *) filter; + + free(accel_filter); +} + +static struct motion_filter_interface accelerator_interface_flat = { + .type = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT, + .filter = trackpoint_flat_filter, + .filter_constant = trackpoint_flat_filter_noop, + .restart = NULL, + .destroy = trackpoint_flat_destroy, + .set_speed = trackpoint_flat_set_speed, +}; + +struct motion_filter * +create_pointer_accelerator_filter_trackpoint_flat(double multiplier) +{ + struct trackpoint_flat_accelerator *filter; + + filter = zalloc(sizeof *filter); + filter->base.interface = &accelerator_interface_flat; + filter->multiplier = multiplier; + + return &filter->base; +}
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/filter-trackpoint.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/filter-trackpoint.c
Changed
@@ -171,7 +171,7 @@ free(accel_filter); } -struct motion_filter_interface accelerator_interface_trackpoint = { +static const struct motion_filter_interface accelerator_interface_trackpoint = { .type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE, .filter = trackpoint_accelerator_filter, .filter_constant = trackpoint_accelerator_filter_noop,
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/filter.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/filter.c
Changed
@@ -160,9 +160,9 @@ } static double -calculate_trackers_velocity(struct pointer_tracker *tracker, - uint64_t time, - struct pointer_delta_smoothener *smoothener) +calculate_trackers_velocity(const struct pointer_tracker *tracker, + uint64_t time, + struct pointer_delta_smoothener *smoothener) { uint64_t tdelta = time - tracker->time + 1; @@ -174,8 +174,8 @@ } static double -trackers_velocity_after_timeout(struct pointer_tracker *tracker, - struct pointer_delta_smoothener *smoothener) +trackers_velocity_after_timeout(const struct pointer_tracker *tracker, + struct pointer_delta_smoothener *smoothener) { /* First movement after timeout needs special handling. * @@ -189,8 +189,8 @@ * movement in normal use-cases (pause, move, pause, move) */ return calculate_trackers_velocity(tracker, - tracker->time + MOTION_TIMEOUT, - smoothener); + tracker->time + MOTION_TIMEOUT, + smoothener); } /** @@ -204,19 +204,15 @@ trackers_velocity(struct pointer_trackers *trackers, uint64_t time) { const double MAX_VELOCITY_DIFF = v_ms2us(1); /* units/us */ - struct pointer_tracker *tracker; - double velocity; double result = 0.0; double initial_velocity = 0.0; - double velocity_diff; - unsigned int offset; unsigned int dir = trackers_by_offset(trackers, 0)->dir; /* Find least recent vector within a timelimit, maximum velocity diff * and direction threshold. */ - for (offset = 1; offset < trackers->ntrackers; offset++) { - tracker = trackers_by_offset(trackers, offset); + for (unsigned int offset = 1; offset < trackers->ntrackers; offset++) { + const struct pointer_tracker *tracker = trackers_by_offset(trackers, offset); /* Bug: time running backwards */ if (tracker->time > time) @@ -231,9 +227,9 @@ break; } - velocity = calculate_trackers_velocity(tracker, - time, - trackers->smoothener); + double velocity = calculate_trackers_velocity(tracker, + time, + trackers->smoothener); /* Stop if direction changed */ dir &= tracker->dir; @@ -252,7 +248,7 @@ result = initial_velocity = velocity; } else { /* Stop if velocity differs too much from initial */ - velocity_diff = fabs(initial_velocity - velocity); + double velocity_diff = fabs(initial_velocity - velocity); if (velocity_diff > MAX_VELOCITY_DIFF) break; @@ -269,7 +265,8 @@ * * @param accel The acceleration filter * @param data Caller-specific data - * @param velocity Velocity in device-units per µs + * @param velocity Velocity - depending on the caller this may be in + * device-units per µs or normalized per µs * @param last_velocity Previous velocity in device-units per µs * @param time Current time in µs *
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/filter.h -> _service:tar_scm:libinput-1.22.1.tar.gz/src/filter.h
Changed
@@ -129,6 +129,9 @@ create_pointer_accelerator_filter_trackpoint(double multiplier, bool use_velocity_averaging); struct motion_filter * +create_pointer_accelerator_filter_trackpoint_flat(double multiplier); + +struct motion_filter * create_pointer_accelerator_filter_tablet(int xres, int yres); /*
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/libinput-private.h -> _service:tar_scm:libinput-1.22.1.tar.gz/src/libinput-private.h
Changed
@@ -136,6 +136,8 @@ struct libinput_source *source; int fd; uint64_t next_expiry; + + struct ratelimit expiry_in_past_limit; } timer; struct libinput_event **events; @@ -304,6 +306,17 @@ struct libinput_device *device); }; +struct libinput_device_config_dwtp { + int (*is_available)(struct libinput_device *device); + enum libinput_config_status (*set_enabled)( + struct libinput_device *device, + enum libinput_config_dwtp_state enable); + enum libinput_config_dwtp_state (*get_enabled)( + struct libinput_device *device); + enum libinput_config_dwtp_state (*get_default_enabled)( + struct libinput_device *device); +}; + struct libinput_device_config_rotation { int (*is_available)(struct libinput_device *device); enum libinput_config_status (*set_angle)( @@ -331,6 +344,7 @@ struct libinput_device_config_click_method *click_method; struct libinput_device_config_middle_emulation *middle_emulation; struct libinput_device_config_dwt *dwt; + struct libinput_device_config_dwtp *dwtp; struct libinput_device_config_rotation *rotation; struct libinput_device_config_gesture *gesture; }; @@ -393,10 +407,8 @@ void *user_data; struct { - /* The pressure threshold assumes a pressure_offset of 0 */ - struct threshold threshold; - /* pressure_offset includes axis->minimum */ - int offset; + struct threshold threshold; /* in device coordinates */ + int offset; /* in device coordinates */ bool has_offset; } pressure; }; @@ -865,7 +877,7 @@ d1 = (int)(r + 0.9) % 8; d2 = (int)(r + 0.1) % 8; - dir = (1 << d1) | (1 << d2); + dir = bit(d1) | bit(d2); } return dir;
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/libinput-util.h -> _service:tar_scm:libinput-1.22.1.tar.gz/src/libinput-util.h
Changed
@@ -65,5 +65,6 @@ } while (0) #define LIBINPUT_EXPORT __attribute__ ((visibility("default"))) +#define LIBINPUT_UNUSED __attribute__ ((unused)) #endif /* LIBINPUT_UTIL_H */
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/libinput.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/libinput.c
Changed
@@ -75,6 +75,7 @@ ASSERT_INT_SIZE(enum libinput_config_middle_emulation_state); ASSERT_INT_SIZE(enum libinput_config_scroll_method); ASSERT_INT_SIZE(enum libinput_config_dwt_state); +ASSERT_INT_SIZE(enum libinput_config_dwtp_state); static inline const char * event_type_to_str(enum libinput_event_type type) @@ -3427,7 +3428,7 @@ libinput_device_tablet_pad_get_num_buttons(group->device)) return 0; - return !!(group->button_mask & (1 << button)); + return !!(group->button_mask & bit(button)); } LIBINPUT_EXPORT int @@ -3438,7 +3439,7 @@ libinput_device_tablet_pad_get_num_rings(group->device)) return 0; - return !!(group->ring_mask & (1 << ring)); + return !!(group->ring_mask & bit(ring)); } LIBINPUT_EXPORT int @@ -3449,7 +3450,7 @@ libinput_device_tablet_pad_get_num_strips(group->device)) return 0; - return !!(group->strip_mask & (1 << strip)); + return !!(group->strip_mask & bit(strip)); } LIBINPUT_EXPORT int @@ -3460,7 +3461,7 @@ libinput_device_tablet_pad_get_num_buttons(group->device)) return 0; - return !!(group->toggle_button_mask & (1 << button)); + return !!(group->toggle_button_mask & bit(button)); } LIBINPUT_EXPORT struct libinput_tablet_pad_mode_group * @@ -4517,6 +4518,48 @@ } LIBINPUT_EXPORT int +libinput_device_config_dwtp_is_available(struct libinput_device *device) +{ + if (!device->config.dwtp) + return 0; + + return device->config.dwtp->is_available(device); +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_dwtp_set_enabled(struct libinput_device *device, + enum libinput_config_dwtp_state enable) +{ + if (enable != LIBINPUT_CONFIG_DWTP_ENABLED && + enable != LIBINPUT_CONFIG_DWTP_DISABLED) + return LIBINPUT_CONFIG_STATUS_INVALID; + + if (!libinput_device_config_dwtp_is_available(device)) + return enable ? LIBINPUT_CONFIG_STATUS_UNSUPPORTED : + LIBINPUT_CONFIG_STATUS_SUCCESS; + + return device->config.dwtp->set_enabled(device, enable); +} + +LIBINPUT_EXPORT enum libinput_config_dwtp_state +libinput_device_config_dwtp_get_enabled(struct libinput_device *device) +{ + if (!libinput_device_config_dwtp_is_available(device)) + return LIBINPUT_CONFIG_DWTP_DISABLED; + + return device->config.dwtp->get_enabled(device); +} + +LIBINPUT_EXPORT enum libinput_config_dwtp_state +libinput_device_config_dwtp_get_default_enabled(struct libinput_device *device) +{ + if (!libinput_device_config_dwtp_is_available(device)) + return LIBINPUT_CONFIG_DWTP_DISABLED; + + return device->config.dwtp->get_default_enabled(device); +} + +LIBINPUT_EXPORT int libinput_device_config_rotation_is_available(struct libinput_device *device) { if (!device->config.rotation)
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/libinput.h -> _service:tar_scm:libinput-1.22.1.tar.gz/src/libinput.h
Changed
@@ -6036,6 +6036,106 @@ /** * @ingroup config * + * Possible states for the disable-while-trackpointing feature. + * + * @since 1.21 + */ +enum libinput_config_dwtp_state { + LIBINPUT_CONFIG_DWTP_DISABLED, + LIBINPUT_CONFIG_DWTP_ENABLED, +}; + +/** + * @ingroup config + * + * Check if this device supports configurable disable-while-trackpointing + * feature. This feature is usually available on Thinkpads and disables the + * touchpad while using the trackpoint. See the libinput documentation for + * details. + * + * @param device The device to configure + * @return 0 if this device does not support disable-while-trackpointing, or 1 + * otherwise. + * + * @see libinput_device_config_dwtp_set_enabled + * @see libinput_device_config_dwtp_get_enabled + * @see libinput_device_config_dwtp_get_default_enabled + * + * @since 1.21 + */ +int +libinput_device_config_dwtp_is_available(struct libinput_device *device); + +/** + * @ingroup config + * + * Enable or disable the disable-while-trackpointing feature. When enabled, the + * device will be disabled while using the trackpoint and for a short period + * after. See the libinput documentation for details. + * + * @note Enabling or disabling disable-while-trackpointing may not take effect + * immediately. + * + * @param device The device to configure + * @param enable @ref LIBINPUT_CONFIG_DWTP_DISABLED to disable + * disable-while-trackpointing, @ref LIBINPUT_CONFIG_DWTP_ENABLED to enable + * + * @return A config status code. Disabling disable-while-trackpointing on a + * device that does not support the feature always succeeds. + * + * @see libinput_device_config_dwtp_is_available + * @see libinput_device_config_dwtp_get_enabled + * @see libinput_device_config_dwtp_get_default_enabled + * + * @since 1.21 + */ +enum libinput_config_status +libinput_device_config_dwtp_set_enabled(struct libinput_device *device, + enum libinput_config_dwtp_state enable); + +/** + * @ingroup config + * + * Check if the disable-while trackpointing feature is currently enabled on + * this device. If the device does not support disable-while-trackpointing, + * this function returns @ref LIBINPUT_CONFIG_DWTP_DISABLED. + * + * @param device The device to configure + * @return @ref LIBINPUT_CONFIG_DWTP_DISABLED if disabled, @ref + * LIBINPUT_CONFIG_DWTP_ENABLED if enabled. + * + * @see libinput_device_config_dwtp_is_available + * @see libinput_device_config_dwtp_set_enabled + * @see libinput_device_config_dwtp_get_default_enabled + * + * @since 1.21 + */ +enum libinput_config_dwtp_state +libinput_device_config_dwtp_get_enabled(struct libinput_device *device); + +/** + * @ingroup config + * + * Check if the disable-while trackpointing feature is enabled on this device + * by default. If the device does not support disable-while-trackpointing, this + * function returns @ref LIBINPUT_CONFIG_DWTP_DISABLED. + * + * @param device The device to configure + * @return @ref LIBINPUT_CONFIG_DWTP_DISABLED if disabled, @ref + * LIBINPUT_CONFIG_DWTP_ENABLED if enabled. + * + * @see libinput_device_config_dwtp_is_available + * @see libinput_device_config_dwtp_set_enabled + * @see libinput_device_config_dwtp_get_enabled + * + * @since 1.21 + */ +enum libinput_config_dwtp_state +libinput_device_config_dwtp_get_default_enabled(struct libinput_device *device); + +/** + * @ingroup config + * * Check whether a device can have a custom rotation applied. * * @param device The device to configure
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/libinput.sym -> _service:tar_scm:libinput-1.22.1.tar.gz/src/libinput.sym
Changed
@@ -319,3 +319,10 @@ libinput_event_pointer_get_scroll_value_v120; libinput_event_pointer_get_scroll_value; } LIBINPUT_1.15; + +LIBINPUT_1.21 { + libinput_device_config_dwtp_is_available; + libinput_device_config_dwtp_set_enabled; + libinput_device_config_dwtp_get_enabled; + libinput_device_config_dwtp_get_default_enabled; +} LIBINPUT_1.19;
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/quirks.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/quirks.c
Changed
@@ -248,13 +248,12 @@ case QUIRK_MODEL_BOUNCING_KEYS: return "ModelBouncingKeys"; case QUIRK_MODEL_CHROMEBOOK: return "ModelChromebook"; case QUIRK_MODEL_CLEVO_W740SU: return "ModelClevoW740SU"; + case QUIRK_MODEL_DELL_CANVAS_TOTEM: return "ModelDellCanvasTotem"; case QUIRK_MODEL_HP_PAVILION_DM4_TOUCHPAD: return "ModelHPPavilionDM4Touchpad"; - case QUIRK_MODEL_HP_STREAM11_TOUCHPAD: return "ModelHPStream11Touchpad"; case QUIRK_MODEL_HP_ZBOOK_STUDIO_G3: return "ModelHPZBookStudioG3"; case QUIRK_MODEL_INVERT_HORIZONTAL_SCROLLING: return "ModelInvertHorizontalScrolling"; case QUIRK_MODEL_LENOVO_SCROLLPOINT: return "ModelLenovoScrollPoint"; case QUIRK_MODEL_LENOVO_T450_TOUCHPAD: return "ModelLenovoT450Touchpad"; - case QUIRK_MODEL_LENOVO_TRACKPOINT_KEYBOARD_2: return "ModelLenovoTrackpointKeyboard2"; case QUIRK_MODEL_LENOVO_X1GEN6_TOUCHPAD: return "ModelLenovoX1Gen6Touchpad"; case QUIRK_MODEL_LENOVO_X230: return "ModelLenovoX230"; case QUIRK_MODEL_SYNAPTICS_SERIAL_TOUCHPAD: return "ModelSynapticsSerialTouchpad"; @@ -266,7 +265,6 @@ case QUIRK_MODEL_TOUCHPAD_VISIBLE_MARKER: return "ModelTouchpadVisibleMarker"; case QUIRK_MODEL_TRACKBALL: return "ModelTrackball"; case QUIRK_MODEL_WACOM_TOUCHPAD: return "ModelWacomTouchpad"; - case QUIRK_MODEL_DELL_CANVAS_TOTEM: return "ModelDellCanvasTotem"; case QUIRK_ATTR_SIZE_HINT: return "AttrSizeHint"; case QUIRK_ATTR_TOUCH_SIZE_RANGE: return "AttrTouchSizeRange"; @@ -729,7 +727,8 @@ } else if (streq(key, quirk_get_name(QUIRK_ATTR_LID_SWITCH_RELIABILITY))) { p->id = QUIRK_ATTR_LID_SWITCH_RELIABILITY; if (!streq(value, "reliable") && - !streq(value, "write_open")) + !streq(value, "write_open") && + !streq(value, "unreliable")) goto out; p->type = PT_STRING; p->value.s = safe_strdup(value); @@ -880,18 +879,15 @@ static bool parse_value_line(struct quirks_context *ctx, struct section *s, const char *line) { - char **strv; - const char *key, *value; bool rc = false; - - strv = strv_from_string(line, "="); - if (strv0 == NULL || strv1 == NULL || strv2 != NULL) { + + size_t nelem; + char **strv = strv_from_string(line, "=", &nelem); + if (!strv || nelem != 2) goto out; - } - - key = strv0; - value = strv1; + const char *key = strv0; + const char *value = strv1; if (strlen(key) == 0 || strlen(value) == 0) goto out; @@ -1339,7 +1335,6 @@ { "ID_INPUT_KEYBOARD", UDEV_KEYBOARD }, { "ID_INPUT_KEY", UDEV_KEYBOARD }, }; - struct ut_map *map; ARRAY_FOR_EACH(mappings, map) { if (udev_prop(device, map->prop))
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/quirks.h -> _service:tar_scm:libinput-1.22.1.tar.gz/src/quirks.h
Changed
@@ -68,13 +68,12 @@ QUIRK_MODEL_BOUNCING_KEYS, QUIRK_MODEL_CHROMEBOOK, QUIRK_MODEL_CLEVO_W740SU, + QUIRK_MODEL_DELL_CANVAS_TOTEM, QUIRK_MODEL_HP_PAVILION_DM4_TOUCHPAD, - QUIRK_MODEL_HP_STREAM11_TOUCHPAD, QUIRK_MODEL_HP_ZBOOK_STUDIO_G3, QUIRK_MODEL_INVERT_HORIZONTAL_SCROLLING, QUIRK_MODEL_LENOVO_SCROLLPOINT, QUIRK_MODEL_LENOVO_T450_TOUCHPAD, - QUIRK_MODEL_LENOVO_TRACKPOINT_KEYBOARD_2, QUIRK_MODEL_LENOVO_X1GEN6_TOUCHPAD, QUIRK_MODEL_LENOVO_X230, QUIRK_MODEL_SYNAPTICS_SERIAL_TOUCHPAD, @@ -86,7 +85,6 @@ QUIRK_MODEL_TOUCHPAD_VISIBLE_MARKER, QUIRK_MODEL_TRACKBALL, QUIRK_MODEL_WACOM_TOUCHPAD, - QUIRK_MODEL_DELL_CANVAS_TOTEM, _QUIRK_LAST_MODEL_QUIRK_, /* Guard: do not modify */
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/timer.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/timer.c
Changed
@@ -43,6 +43,9 @@ timer->timer_name = safe_strdup(timer_name); timer->timer_func = timer_func; timer->timer_func_data = timer_func_data; + /* at most 5 "expiry in the past" log messages per hour */ + ratelimit_init(&libinput->timer.expiry_in_past_limit, + s2us(60 * 60), 5); } void @@ -89,13 +92,17 @@ uint32_t flags) { #ifndef NDEBUG + /* We only warn if we're more than 20ms behind */ + const uint64_t timer_warning_limit = ms2us(20); uint64_t now = libinput_now(timer->libinput); if (expire < now) { - if ((flags & TIMER_FLAG_ALLOW_NEGATIVE) == 0) - log_bug_client(timer->libinput, - "timer %s: scheduled expiry is in the past (-%dms), your system is too slow\n", - timer->timer_name, - us2ms(now - expire)); + if ((flags & TIMER_FLAG_ALLOW_NEGATIVE) == 0 && + now - expire > timer_warning_limit) + log_bug_client_ratelimit(timer->libinput, + &timer->libinput->timer.expiry_in_past_limit, + "timer %s: scheduled expiry is in the past (-%dms), your system is too slow\n", + timer->timer_name, + us2ms(now - expire)); } else if ((expire - now) > ms2us(5000)) { log_bug_libinput(timer->libinput, "timer %s: offset more than 5s, now %d expire %d\n",
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/timer.h -> _service:tar_scm:libinput-1.22.1.tar.gz/src/timer.h
Changed
@@ -54,7 +54,7 @@ enum timer_flags { TIMER_FLAG_NONE = 0, - TIMER_FLAG_ALLOW_NEGATIVE = (1 << 0), + TIMER_FLAG_ALLOW_NEGATIVE = bit(0), }; void
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/util-macros.h -> _service:tar_scm:libinput-1.22.1.tar.gz/src/util-macros.h
Changed
@@ -28,8 +28,14 @@ #include "config.h" #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)0) +/** + * Iterate through the array _arr, assigning the variable elem to each + * element. elem only exists within the loop. + */ #define ARRAY_FOR_EACH(_arr, _elem) \ - for (size_t _i = 0; _i < ARRAY_LENGTH(_arr) && (_elem = &_arr_i); _i++) + for (__typeof__((_arr)0) *_elem = _arr; \ + _elem < (_arr) + ARRAY_LENGTH(_arr); \ + _elem++) #define min(a, b) (((a) < (b)) ? (a) : (b)) #define max(a, b) (((a) > (b)) ? (a) : (b))
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/util-prop-parsers.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/util-prop-parsers.c
Changed
@@ -176,32 +176,31 @@ bool parse_calibration_property(const char *prop, float calibration_out6) { - int idx; - char **strv; - float calibration6; - if (!prop) return false; + + bool rc = false; - strv = strv_from_string(prop, " "); - if (!strv) - return false; + size_t num_calibration; + char **strv = strv_from_string(prop, " ", &num_calibration); + if (!strv || num_calibration < 6) + goto out; - for (idx = 0; idx < 6; idx++) { + float calibration6; + for (size_t idx = 0; idx < 6; idx++) { double v; - if (strvidx == NULL || !safe_atod(strvidx, &v)) { - strv_free(strv); - return false; - } + if (!safe_atod(strvidx, &v)) + goto out; calibrationidx = v; } - strv_free(strv); - memcpy(calibration_out, calibration, sizeof(calibration)); + rc = true; - return true; +out: + strv_free(strv); + return rc; } bool @@ -209,12 +208,14 @@ enum switch_reliability *reliability) { if (!prop) { - *reliability = RELIABILITY_UNKNOWN; + *reliability = RELIABILITY_RELIABLE; return true; } if (streq(prop, "reliable")) *reliability = RELIABILITY_RELIABLE; + else if (streq(prop, "unreliable")) + *reliability = RELIABILITY_UNRELIABLE; else if (streq(prop, "write_open")) *reliability = RELIABILITY_WRITE_OPEN; else @@ -321,7 +322,6 @@ { "REL_", EV_REL }, { "SW_", EV_SW }, }; - struct map *m; bool found = false; ARRAY_FOR_EACH(map, m) { @@ -366,27 +366,19 @@ bool parse_evcode_property(const char *prop, struct input_event *events, size_t *nevents) { - char **strv = NULL; bool rc = false; - size_t ncodes = 0; - size_t idx; /* A randomly chosen max so we avoid crazy quirks */ struct input_event evs32; memset(evs, 0, sizeof evs); - strv = strv_from_string(prop, ";"); - if (!strv) - goto out; - - for (idx = 0; strvidx; idx++) - ncodes++; - - if (ncodes == 0 || ncodes > ARRAY_LENGTH(evs)) + size_t ncodes; + char **strv = strv_from_string(prop, ";", &ncodes); + if (!strv || ncodes == 0 || ncodes > ARRAY_LENGTH(evs)) goto out; ncodes = min(*nevents, ncodes); - for (idx = 0; strvidx; idx++) { + for (size_t idx = 0; strvidx; idx++) { char *s = strvidx; int type, code; @@ -433,24 +425,16 @@ bool parse_input_prop_property(const char *prop, unsigned int *props_out, size_t *nprops) { - char **strv = NULL; bool rc = false; - size_t count = 0; - size_t idx; unsigned int propsINPUT_PROP_CNT; /* doubling up on quirks is a bug */ - strv = strv_from_string(prop, ";"); - if (!strv) - goto out; - - for (idx = 0; strvidx; idx++) - count++; - - if (count == 0 || count > ARRAY_LENGTH(props)) + size_t count; + char **strv = strv_from_string(prop, ";", &count); + if (!strv || count == 0 || count > ARRAY_LENGTH(props)) goto out; count = min(*nprops, count); - for (idx = 0; strvidx; idx++) { + for (size_t idx = 0; strvidx; idx++) { char *s = strvidx; unsigned int prop;
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/util-prop-parsers.h -> _service:tar_scm:libinput-1.22.1.tar.gz/src/util-prop-parsers.h
Changed
@@ -49,8 +49,8 @@ enum tpkbcombo_layout *layout); enum switch_reliability { - RELIABILITY_UNKNOWN, RELIABILITY_RELIABLE, + RELIABILITY_UNRELIABLE, RELIABILITY_WRITE_OPEN, };
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/util-strings.c -> _service:tar_scm:libinput-1.22.1.tar.gz/src/util-strings.c
Changed
@@ -91,47 +91,54 @@ /** * Return a null-terminated string array with the tokens in the input * string, e.g. "one two\tthree" with a separator list of " \t" will return - * an array "one", "two", "three", NULL . + * an array "one", "two", "three", NULL and num elements 3. * * Use strv_free() to free the array. * + * Another example: + * result = strv_from_string("+1-2++3--4++-+5-+-", "+-", &nelem) + * result == "1", "2", "3", "4", "5", NULL and nelem == 5 + * * @param in Input string * @param separators List of separator characters + * @param num_elements Number of elements found in the input string * * @return A null-terminated string array or NULL on errors */ char ** -strv_from_string(const char *in, const char *separators) +strv_from_string(const char *in, const char *separators, size_t *num_elements) { - const char *s, *word; - char **strv = NULL; - int nelems = 0, idx; - size_t l; - assert(in != NULL); - s = in; + + const char *s = in; + size_t l, nelems = 0; while (next_word(&s, &l, separators) != NULL) - nelems++; + nelems++; - if (nelems == 0) + if (nelems == 0) { + *num_elements = 0; return NULL; + } - nelems++; /* NULL-terminated */ - strv = zalloc(nelems * sizeof *strv); - - idx = 0; + size_t strv_len = nelems + 1; /* NULL-terminated */ + char **strv = zalloc(strv_len * sizeof *strv); + size_t idx = 0; + const char *word; s = in; while ((word = next_word(&s, &l, separators)) != NULL) { char *copy = strndup(word, l); if (!copy) { strv_free(strv); + *num_elements = 0; return NULL; } strvidx++ = copy; } + + *num_elements = nelems; return strv; }
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/util-strings.h -> _service:tar_scm:libinput-1.22.1.tar.gz/src/util-strings.h
Changed
@@ -43,6 +43,8 @@ #include <xlocale.h> #endif +#include "util-macros.h" + static inline bool streq(const char *str1, const char *str2) { @@ -253,7 +255,7 @@ } char **strv_from_argv(int argc, char **argv); -char **strv_from_string(const char *in, const char *separator); +char **strv_from_string(const char *in, const char *separator, size_t *num_elements); char *strv_join(char **strv, const char *joiner); static inline void @@ -289,33 +291,26 @@ struct key_value_double **result_out) { - char **pairs; - char **pair; struct key_value_double *result = NULL; - ssize_t npairs = 0; - unsigned int idx = 0; if (!pair_separator || pair_separator0 == '\0' || !kv_separator || kv_separator0 == '\0') return -1; - pairs = strv_from_string(string, pair_separator); - if (!pairs) - return -1; - - for (pair = pairs; *pair; pair++) - npairs++; - - if (npairs == 0) + size_t npairs; + char **pairs = strv_from_string(string, pair_separator, &npairs); + if (!pairs || npairs == 0) goto error; result = zalloc(npairs * sizeof *result); - for (pair = pairs; *pair; pair++) { - char **kv = strv_from_string(*pair, kv_separator); + for (size_t idx = 0; idx < npairs; idx++) { + char *pair = pairsidx; + size_t nelem; + char **kv = strv_from_string(pair, kv_separator, &nelem); double k, v; - if (!kv || !kv0 || !kv1 || kv2 || + if (!kv || nelem != 2 || !safe_atod(kv0, &k) || !safe_atod(kv1, &v)) { strv_free(kv); @@ -324,7 +319,6 @@ resultidx.key = k; resultidx.value = v; - idx++; strv_free(kv); } @@ -398,3 +392,31 @@ char * trunkname(const char *filename); + +/** + * Return a copy of str with all % converted to %% to make the string + * acceptable as printf format. + */ +static inline char * +str_sanitize(const char *str) +{ + if (!str) + return NULL; + + if (!strchr(str, '%')) + return strdup(str); + + size_t slen = min(strlen(str), 512); + char *sanitized = zalloc(2 * slen + 1); + const char *src = str; + char *dst = sanitized; + + for (size_t i = 0; i < slen; i++) { + if (*src == '%') + *dst++ = '%'; + *dst++ = *src++; + } + *dst = '\0'; + + return sanitized; +}
View file
_service:tar_scm:libinput-1.19.2.tar.xz/src/util-time.h -> _service:tar_scm:libinput-1.22.1.tar.gz/src/util-time.h
Changed
@@ -116,7 +116,6 @@ {"h", 60, 48}, {"d", 24, ~0}, }; - struct c *c; uint64_t value = us; ARRAY_FOR_EACH(conversion, c) {
View file
_service:tar_scm:libinput-1.19.2.tar.xz/test/litest-device-aiptek-tablet.c -> _service:tar_scm:libinput-1.22.1.tar.gz/test/litest-device-aiptek-tablet.c
Changed
@@ -32,6 +32,7 @@ { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, /* Note: this device does not send tilt, despite claiming it has it */ { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_KEY, .code = LITEST_BTN_TOOL_AUTO, .value = LITEST_AUTO_ASSIGN }, { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, { .type = -1, .code = -1 }, };
View file
_service:tar_scm:libinput-1.22.1.tar.gz/test/litest-device-format-string.c
Added
@@ -0,0 +1,56 @@ + +/* + * Copyright © 2013 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include "litest.h" +#include "litest-int.h" + +static struct input_id input_id = { + .bustype = 0x3, + .vendor = 0x0123, + .product = 0x0456, +}; + +static int events = { + EV_KEY, BTN_LEFT, + EV_KEY, BTN_RIGHT, + EV_KEY, BTN_MIDDLE, + EV_REL, REL_X, + EV_REL, REL_Y, + EV_REL, REL_WHEEL, + EV_REL, REL_WHEEL_HI_RES, + -1 , -1, +}; + +TEST_DEVICE("mouse-format-string", + .type = LITEST_MOUSE_FORMAT_STRING, + .features = LITEST_RELATIVE | LITEST_BUTTON | LITEST_WHEEL, + .interface = NULL, + + .name = "Evil %s %d %x Mouse %p %", + .id = &input_id, + .absinfo = NULL, + .events = events, +)
View file
_service:tar_scm:libinput-1.22.1.tar.gz/test/litest-device-lenovo-scrollpoint.c
Added
@@ -0,0 +1,60 @@ +/* + * Copyright © 2013 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include "litest.h" +#include "litest-int.h" + +static struct input_id input_id = { + .bustype = 0x3, + .vendor = 0x04b3, + .product = 0x3109, +}; + +static int events = { + EV_KEY, BTN_LEFT, + EV_KEY, BTN_RIGHT, + EV_KEY, BTN_MIDDLE, + EV_REL, REL_X, + EV_REL, REL_Y, + EV_REL, REL_WHEEL, + EV_REL, REL_WHEEL_HI_RES, + EV_REL, REL_HWHEEL, + -1 , -1, +}; + +/* Note: device is not tagged with LITEST_WHEEL to avoid running the + * "standard" wheel tests. Device has a custom wheel + * behavior that is tested directly. + */ +TEST_DEVICE("lenovo-scrollpoint", + .type = LITEST_LENOVO_SCROLLPOINT, + .features = LITEST_RELATIVE | LITEST_BUTTON, + .interface = NULL, + + .name = "HID 04b3:3109", + .id = &input_id, + .absinfo = NULL, + .events = events, +)
View file
_service:tar_scm:libinput-1.22.1.tar.gz/test/litest-device-wacom-isdv4-524c-pen.c
Added
@@ -0,0 +1,165 @@ +/* + * Copyright © 2019 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include "litest.h" +#include "litest-int.h" + +struct priv { + unsigned int tool; +}; + +static bool +create(struct litest_device *d) +{ + d->private = zalloc(sizeof(struct priv)); + return true; /* we want litest to create our device */ +} + +static struct input_event proximity_in = { + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_KEY, .code = LITEST_BTN_TOOL_AUTO, .value = 1 }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; + +static struct input_event proximity_out = { + { .type = EV_KEY, .code = LITEST_BTN_TOOL_AUTO, .value = 0 }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; + +static struct input_event motion = { + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; + +static int +get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value) +{ + switch (evcode) { + case ABS_PRESSURE: + *value = 4000; + return 0; + case ABS_TILT_X: + case ABS_TILT_Y: + abort(); + } + return 1; +} + +static bool prox_in(struct litest_device *d, + unsigned int tool_type, + double x, double y, + struct axis_replacement *axes) +{ + struct priv *priv = d->private; + priv->tool = tool_type; + + return false; +} + +static bool prox_out(struct litest_device *d, unsigned int tool_type) +{ + struct priv *priv = d->private; + priv->tool = 0; + + return false; +} + +static bool +tip_down(struct litest_device *d, + int x, int y, + struct axis_replacement *axes) +{ + litest_event(d, EV_KEY, BTN_TOOL_PEN, 1); + return false; /* use the default behavior otherwise */ +} + +static bool +tip_up(struct litest_device *d, + int x, int y, + struct axis_replacement *axes) +{ + struct priv *priv = d->private; + if (priv->tool != BTN_TOOL_PEN) + litest_event(d, EV_KEY, BTN_TOOL_PEN, 0); + return false; /* use the default behavior otherwise */ +} + +static struct litest_device_interface interface = { + .tablet_proximity_in_events = proximity_in, + .tablet_proximity_out_events = proximity_out, + .tablet_motion_events = motion, + + .tablet_proximity_in = prox_in, + .tablet_proximity_out = prox_out, + .tablet_tip_down = tip_down, + .tablet_tip_up = tip_up, + + .get_axis_default = get_axis_default, +}; + +static struct input_absinfo absinfo = { + { ABS_X, 0, 30931, 0, 0, 100 }, + { ABS_Y, 0, 17399, 0, 0, 100 }, + /* This pen has tilt, but doesn't send events */ + { ABS_TILT_X, -90, 90, 0, 0, 57 }, + { ABS_TILT_Y, -90, 90, 0, 0, 57 }, + { ABS_PRESSURE, 0, 4095, 0, 0, 0 }, + { .value = -1 }, +}; + +static struct input_id input_id = { + .bustype = 0x3, + .vendor = 0x2d1f, /* Note: this is Wacom's Android VID */ + .product = 0x524c, +}; + +static int events = { + EV_KEY, BTN_TOOL_PEN, + EV_KEY, BTN_TOOL_RUBBER, + EV_KEY, BTN_TOUCH, + EV_KEY, BTN_STYLUS, + EV_KEY, BTN_STYLUS2, + INPUT_PROP_MAX, INPUT_PROP_DIRECT, + -1, -1, +}; + +TEST_DEVICE("wacom-isdv4-524c-tablet", + .type = LITEST_WACOM_ISDV4_524C_PEN, + .features = LITEST_TABLET|LITEST_HOVER, + .interface = &interface, + + .name = "Wacom Co.,Ltd. Pen and multitouch sensor Stylus", + .id = &input_id, + .events = events, + .absinfo = absinfo, + .create = create, +)
View file
_service:tar_scm:libinput-1.19.2.tar.xz/test/litest-int.h -> _service:tar_scm:libinput-1.22.1.tar.gz/test/litest-int.h
Changed
@@ -119,6 +119,12 @@ double x, double y, struct axis_replacement *axes); bool (*tablet_proximity_out)(struct litest_device *d, unsigned int tool_type); + bool (*tablet_tip_down)(struct litest_device *d, + int x, int y, + struct axis_replacement *axes); + bool (*tablet_tip_up)(struct litest_device *d, + int x, int y, + struct axis_replacement *axes); /** * Pad events, LITEST_AUTO_ASSIGN is allowed on event values
View file
_service:tar_scm:libinput-1.19.2.tar.xz/test/litest.c -> _service:tar_scm:libinput-1.22.1.tar.gz/test/litest.c
Changed
@@ -2542,6 +2542,36 @@ } void +litest_tablet_tip_down(struct litest_device *d, + int x, int y, + struct axis_replacement *axes) +{ + /* If the test device overrides tip_down and says it didn't + * handle the event, let's continue normally */ + if (d->interface->tablet_tip_down && + d->interface->tablet_tip_down(d, x, y, axes)) + return; + + litest_event(d, EV_KEY, BTN_TOUCH, 1); + litest_tablet_motion(d, x, y, axes); +} + +void +litest_tablet_tip_up(struct litest_device *d, + int x, int y, + struct axis_replacement *axes) +{ + /* If the test device overrides tip_down and says it didn't + * handle the event, let's continue normally */ + if (d->interface->tablet_tip_up && + d->interface->tablet_tip_up(d, x, y, axes)) + return; + + litest_event(d, EV_KEY, BTN_TOUCH, 0); + litest_tablet_motion(d, x, y, axes); +} + +void litest_touch_move_two_touches(struct litest_device *d, double x0, double y0, double x1, double y1, @@ -2704,7 +2734,6 @@ unsigned int button, bool is_press) { - struct input_event *ev; struct input_event click = { { .type = EV_KEY, .code = button, .value = is_press ? 1 : 0 }, { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, @@ -2773,7 +2802,6 @@ void litest_keyboard_key(struct litest_device *d, unsigned int key, bool is_press) { - struct input_event *ev; struct input_event click = { { .type = EV_KEY, .code = key, .value = is_press ? 1 : 0 }, { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, @@ -4300,6 +4328,12 @@ } void +litest_timeout_wheel_scroll(void) +{ + msleep(600); +} + +void litest_timeout_edgescroll(void) { msleep(300);
View file
_service:tar_scm:libinput-1.19.2.tar.xz/test/litest.h -> _service:tar_scm:libinput-1.22.1.tar.gz/test/litest.h
Changed
@@ -320,6 +320,9 @@ LITEST_KEYBOARD_QUIRKED, LITEST_SYNAPTICS_PRESSUREPAD, LITEST_GENERIC_PRESSUREPAD, + LITEST_WACOM_ISDV4_524C_PEN, + LITEST_MOUSE_FORMAT_STRING, + LITEST_LENOVO_SCROLLPOINT, }; #define LITEST_DEVICELESS -2 @@ -630,6 +633,16 @@ litest_tablet_proximity_out(struct litest_device *d); void +litest_tablet_tip_down(struct litest_device *d, + int x, int y, + struct axis_replacement *axes); + +void +litest_tablet_tip_up(struct litest_device *d, + int x, int y, + struct axis_replacement *axes); + +void litest_tablet_motion(struct litest_device *d, int x, int y, struct axis_replacement *axes); @@ -895,6 +908,9 @@ litest_timeout_buttonscroll(void); void +litest_timeout_wheel_scroll(void); + +void litest_timeout_edgescroll(void); void
View file
_service:tar_scm:libinput-1.19.2.tar.xz/test/test-device.c -> _service:tar_scm:libinput-1.22.1.tar.gz/test/test-device.c
Changed
@@ -56,7 +56,7 @@ device = dev->libinput_device; status = libinput_device_config_send_events_set_mode(device, - LIBINPUT_CONFIG_SEND_EVENTS_DISABLED | (1 << 4)); + LIBINPUT_CONFIG_SEND_EVENTS_DISABLED | bit(4)); ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED); } END_TEST @@ -1448,7 +1448,7 @@ const char *format, va_list args) { - char *message, **dmsg; + char *message; int n; if (priority != LIBINPUT_LOG_PRIORITY_DEBUG) @@ -1542,7 +1542,6 @@ LIBINPUT_DEVICE_CAP_GESTURE, LIBINPUT_DEVICE_CAP_SWITCH, }; - enum libinput_device_capability *cap; int ncaps = 0; ARRAY_FOR_EACH(caps, cap) {
View file
_service:tar_scm:libinput-1.19.2.tar.xz/test/test-keyboard.c -> _service:tar_scm:libinput-1.22.1.tar.gz/test/test-keyboard.c
Changed
@@ -111,7 +111,6 @@ EV_KEY, KEY_A, -1, -1, }; - enum libinput_key_state *state; enum libinput_key_state expected_states = { LIBINPUT_KEY_STATE_PRESSED, LIBINPUT_KEY_STATE_RELEASED,
View file
_service:tar_scm:libinput-1.19.2.tar.xz/test/test-misc.c -> _service:tar_scm:libinput-1.22.1.tar.gz/test/test-misc.c
Changed
@@ -721,7 +721,7 @@ for (int i = 0; i < 20; i++) { litest_event(dev, EV_REL, REL_X, -1); litest_event(dev, EV_SYN, SYN_REPORT, 0); - msleep(11); + msleep(21); libinput_dispatch(li); }
View file
_service:tar_scm:libinput-1.19.2.tar.xz/test/test-pointer.c -> _service:tar_scm:libinput-1.22.1.tar.gz/test/test-pointer.c
Changed
@@ -30,6 +30,7 @@ #include <libinput.h> #include <math.h> #include <unistd.h> +#include <valgrind/valgrind.h> #include "libinput-util.h" #include "litest.h" @@ -632,6 +633,7 @@ LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL; event = libinput_get_event(li); + litest_assert_notnull(event); while(event) { ptrev = litest_is_axis_event(event, @@ -701,54 +703,6 @@ } END_TEST -START_TEST(pointer_scroll_wheel_pressed_noscroll) -{ - struct litest_device *dev = litest_current_device(); - struct libinput *li = dev->libinput; - - litest_drain_events(li); - - litest_button_click_debounced(dev, li, BTN_MIDDLE, true); - litest_drain_events(li); - - for (int i = 0; i < 10; i++) { - litest_event(dev, EV_REL, REL_WHEEL, 1); - litest_event(dev, EV_REL, REL_HWHEEL, 1); - litest_event(dev, EV_SYN, SYN_REPORT, 0); - } - - libinput_dispatch(li); - - litest_assert_empty_queue(li); - - litest_button_click_debounced(dev, li, BTN_MIDDLE, false); -} -END_TEST - -START_TEST(pointer_scroll_hi_res_wheel_pressed_noscroll) -{ - struct litest_device *dev = litest_current_device(); - struct libinput *li = dev->libinput; - - litest_drain_events(li); - - litest_button_click_debounced(dev, li, BTN_MIDDLE, true); - litest_drain_events(li); - - for (int i = 0; i < 10; i++) { - litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 12); - litest_event(dev, EV_REL, REL_HWHEEL_HI_RES, 12); - litest_event(dev, EV_SYN, SYN_REPORT, 0); - } - - libinput_dispatch(li); - - litest_assert_empty_queue(li); - - litest_button_click_debounced(dev, li, BTN_MIDDLE, false); -} -END_TEST - static void test_hi_res_wheel_event(struct litest_device *dev, int which, int v120_amount) { @@ -796,46 +750,67 @@ test_hi_res_wheel_event(dev, axis, 6 * 120); test_hi_res_wheel_event(dev, axis, 30); - test_hi_res_wheel_event(dev, axis, -40); test_hi_res_wheel_event(dev, axis, -60); + test_hi_res_wheel_event(dev, axis, -40); test_hi_res_wheel_event(dev, axis, 180); } } END_TEST -START_TEST(pointer_scroll_wheel_hires_send_only_lores_vertical) +START_TEST(pointer_scroll_wheel_hires_send_only_lores) { struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + enum libinput_pointer_axis axis = _i; /* ranged test */ + unsigned int lores_code, hires_code; + int direction; - if (!libevdev_has_event_code(dev->evdev, EV_REL, REL_WHEEL_HI_RES) && - !libevdev_has_event_code(dev->evdev, EV_REL, REL_HWHEEL_HI_RES)) + switch (axis) { + case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: + lores_code = REL_WHEEL; + hires_code = REL_WHEEL_HI_RES; + direction = -1; + break; + case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: + lores_code = REL_HWHEEL; + hires_code = REL_HWHEEL_HI_RES; + direction = 1; + break; + default: + abort(); + } + + if (!libevdev_has_event_code(dev->evdev, EV_REL, lores_code) && + !libevdev_has_event_code(dev->evdev, EV_REL, hires_code)) return; + /* Device claims to have HI_RES, but doesn't send events for it. Make + * sure we handle this correctly. + */ litest_drain_events(dev->libinput); litest_set_log_handler_bug(li); - litest_event(dev, EV_REL, REL_WHEEL, 1); + litest_event(dev, EV_REL, lores_code, 1); litest_event(dev, EV_SYN, SYN_REPORT, 0); libinput_dispatch(li); - test_high_and_low_wheel_events_value(dev, REL_WHEEL, -120); + test_high_and_low_wheel_events_value(dev, lores_code, direction * 120); - litest_event(dev, EV_REL, REL_WHEEL, -1); + litest_event(dev, EV_REL, lores_code, -1); litest_event(dev, EV_SYN, SYN_REPORT, 0); libinput_dispatch(li); - test_high_and_low_wheel_events_value(dev, REL_WHEEL, 120); + test_high_and_low_wheel_events_value(dev, lores_code, direction * -120); - litest_event(dev, EV_REL, REL_HWHEEL, 1); + litest_event(dev, EV_REL, lores_code, 2); litest_event(dev, EV_SYN, SYN_REPORT, 0); libinput_dispatch(li); - test_high_and_low_wheel_events_value(dev, REL_HWHEEL, 120); + test_high_and_low_wheel_events_value(dev, lores_code, direction * 240); litest_assert_empty_queue(li); litest_restore_log_handler(li); } END_TEST -START_TEST(pointer_scroll_wheel_hires_send_only_lores_horizontal) +START_TEST(pointer_scroll_wheel_inhibit_small_deltas) { struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; @@ -845,25 +820,145 @@ return; litest_drain_events(dev->libinput); - litest_set_log_handler_bug(li); - litest_event(dev, EV_REL, REL_HWHEEL, 2); + /* Scroll deltas below the threshold (60) must be ignored */ + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 15); + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 15); litest_event(dev, EV_SYN, SYN_REPORT, 0); libinput_dispatch(li); - test_high_and_low_wheel_events_value(dev, REL_HWHEEL, 240); + litest_assert_empty_queue(li); - litest_event(dev, EV_REL, REL_WHEEL, -1); + /* The accumulated scroll is 30, add 30 to trigger scroll */ + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 30); litest_event(dev, EV_SYN, SYN_REPORT, 0); libinput_dispatch(li); - test_high_and_low_wheel_events_value(dev, REL_WHEEL, 120); + test_high_and_low_wheel_events_value(dev, REL_WHEEL_HI_RES, -60); - litest_event(dev, EV_REL, REL_HWHEEL, 1); + /* Once the threshold is reached, small scroll deltas are reported */ + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 5); litest_event(dev, EV_SYN, SYN_REPORT, 0); libinput_dispatch(li); - test_high_and_low_wheel_events_value(dev, REL_HWHEEL, 120); + test_high_and_low_wheel_events_value(dev, REL_WHEEL_HI_RES, -5); + /* When the scroll timeout is triggered, ignore small deltas again */ + litest_timeout_wheel_scroll(); + + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, -15); + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, -15); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + litest_assert_empty_queue(li); + + litest_event(dev, EV_REL, REL_HWHEEL_HI_RES, 15); + litest_event(dev, EV_REL, REL_HWHEEL_HI_RES, 15); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); litest_assert_empty_queue(li); - litest_restore_log_handler(li); +} +END_TEST + +START_TEST(pointer_scroll_wheel_inhibit_dir_change)
View file
_service:tar_scm:libinput-1.19.2.tar.xz/test/test-quirks.c -> _service:tar_scm:libinput-1.22.1.tar.gz/test/test-quirks.c
Changed
@@ -561,7 +561,6 @@ "MatchVendor=123\n" "ModelAppleTouchpad=1\n", }; - const char **qf; ARRAY_FOR_EACH(quirks_file, qf) { struct data_dir dd = make_data_dir(*qf); @@ -622,7 +621,6 @@ "MatchProduct=123\n" "ModelAppleTouchpad=1\n", }; - const char **qf; ARRAY_FOR_EACH(quirks_file, qf) { struct data_dir dd = make_data_dir(*qf); @@ -683,7 +681,6 @@ "MatchVersion=123\n" "ModelAppleTouchpad=1\n", }; - const char **qf; ARRAY_FOR_EACH(quirks_file, qf) { struct data_dir dd = make_data_dir(*qf); @@ -747,7 +744,6 @@ "MatchName=\n" "ModelAppleTouchpad=1\n", }; - const char **qf; ARRAY_FOR_EACH(quirks_file, qf) { struct data_dir dd = make_data_dir(*qf); @@ -821,7 +817,6 @@ "MatchUdevType=123\n" "ModelAppleTouchpad=1\n", }; - const char **qf; ARRAY_FOR_EACH(quirks_file, qf) { struct data_dir dd = make_data_dir(*qf); @@ -878,7 +873,6 @@ "MatchDMIModalias=foo\n" "ModelAppleTouchpad=1\n", }; - const char **qf; ARRAY_FOR_EACH(quirks_file, qf) { struct data_dir dd = make_data_dir(*qf); @@ -965,7 +959,6 @@ QUIRK_ATTR_SIZE_HINT, QUIRK_ATTR_RESOLUTION_HINT, }; - enum quirk *a; struct qtest_dim test_values = { { "10x10", true, 10, 10 }, { "20x30", true, 20, 30 }, @@ -975,7 +968,6 @@ { "0x00", false, 0, 0 }, { "0xa0", false, 0, 0 }, }; - struct qtest_dim *t; ARRAY_FOR_EACH(attrs, a) { ARRAY_FOR_EACH(test_values, t) { @@ -1011,7 +1003,6 @@ QUIRK_ATTR_TOUCH_SIZE_RANGE, QUIRK_ATTR_PRESSURE_RANGE, }; - enum quirk *a; struct qtest_range test_values = { { "20:10", true, 20, 10 }, { "30:5", true, 30, 5 }, @@ -1029,7 +1020,6 @@ { "0xa0", false, 0, 0 }, { "0x10:0x5", false, 0, 0 }, }; - struct qtest_range *t; ARRAY_FOR_EACH(attrs, a) { ARRAY_FOR_EACH(test_values, t) { @@ -1066,7 +1056,6 @@ QUIRK_ATTR_PALM_PRESSURE_THRESHOLD, QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD, }; - enum quirk *a; struct qtest_uint test_values = { { "10", true, 10 }, { "0", true, 0 }, @@ -1078,7 +1067,6 @@ { "0xab", false, 0 }, { "ab", false, 0 }, }; - struct qtest_uint *t; ARRAY_FOR_EACH(attrs, a) { ARRAY_FOR_EACH(test_values, t) { @@ -1112,7 +1100,6 @@ enum quirk attrs = { QUIRK_ATTR_TRACKPOINT_MULTIPLIER, }; - enum quirk *a; struct qtest_double test_values = { { "10", true, 10.0 }, { "10.0", true, 10.0 }, @@ -1132,7 +1119,6 @@ { "10:5", false, 0 }, { "10x5", false, 0 }, }; - struct qtest_double *t; ARRAY_FOR_EACH(attrs, a) { ARRAY_FOR_EACH(test_values, t) { @@ -1167,7 +1153,6 @@ QUIRK_ATTR_LID_SWITCH_RELIABILITY, QUIRK_ATTR_KEYBOARD_INTEGRATION, }; - enum quirk *a; struct qtest_str test_values = { { "below", QUIRK_ATTR_TPKBCOMBO_LAYOUT }, { "reliable", QUIRK_ATTR_LID_SWITCH_RELIABILITY }, @@ -1185,7 +1170,6 @@ { "0xa", 0 }, { "0.0", 0 }, }; - struct qtest_str *t; ARRAY_FOR_EACH(attrs, a) { ARRAY_FOR_EACH(test_values, t) { @@ -1219,7 +1203,6 @@ QUIRK_ATTR_USE_VELOCITY_AVERAGING, QUIRK_ATTR_TABLET_SMOOTHING, }; - enum quirk *a; struct qtest_bool test_values = { { "0", true, false }, { "1", true, true }, @@ -1227,7 +1210,6 @@ { "-1", false, false }, { "a", false, false }, }; - struct qtest_bool *t; ARRAY_FOR_EACH(attrs, a) { ARRAY_FOR_EACH(test_values, t) {
View file
_service:tar_scm:libinput-1.19.2.tar.xz/test/test-tablet.c -> _service:tar_scm:libinput-1.22.1.tar.gz/test/test-tablet.c
Changed
@@ -223,10 +223,7 @@ litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 30); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 10, 10, axes); libinput_dispatch(li); @@ -240,10 +237,7 @@ litest_axis_set_value(axes, ABS_DISTANCE, 10); litest_axis_set_value(axes, ABS_PRESSURE, 0); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 0); - litest_pop_event_frame(dev); + litest_tablet_tip_up(dev, 10, 10, axes); libinput_dispatch(li); event = libinput_get_event(li); @@ -258,6 +252,62 @@ } END_TEST +START_TEST(tip_down_up_eraser) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_tablet_tool *tablet_event; + struct libinput_tablet_tool *tool; + struct axis_replacement axes = { + { ABS_DISTANCE, 10 }, + { ABS_PRESSURE, 0 }, + { -1, -1 } + }; + + if (!libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_RUBBER)) + return; + + litest_tablet_set_tool_type(dev, BTN_TOOL_RUBBER); + + litest_tablet_proximity_in(dev, 10, 10, axes); + litest_drain_events(li); + + litest_axis_set_value(axes, ABS_DISTANCE, 0); + litest_axis_set_value(axes, ABS_PRESSURE, 30); + litest_tablet_tip_down(dev, 10, 10, axes); + + libinput_dispatch(li); + + event = libinput_get_event(li); + tablet_event = litest_is_tablet_event(event, + LIBINPUT_EVENT_TABLET_TOOL_TIP); + ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event), + LIBINPUT_TABLET_TOOL_TIP_DOWN); + tool = libinput_event_tablet_tool_get_tool(tablet_event); + ck_assert_int_eq(libinput_tablet_tool_get_type(tool), LIBINPUT_TABLET_TOOL_TYPE_ERASER); + libinput_event_destroy(event); + litest_assert_empty_queue(li); + + litest_axis_set_value(axes, ABS_DISTANCE, 10); + litest_axis_set_value(axes, ABS_PRESSURE, 0); + litest_tablet_tip_up(dev, 10, 10, axes); + + libinput_dispatch(li); + event = libinput_get_event(li); + tablet_event = litest_is_tablet_event(event, + LIBINPUT_EVENT_TABLET_TOOL_TIP); + ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event), + LIBINPUT_TABLET_TOOL_TIP_UP); + tool = libinput_event_tablet_tool_get_tool(tablet_event); + ck_assert_int_eq(libinput_tablet_tool_get_type(tool), LIBINPUT_TABLET_TOOL_TYPE_ERASER); + libinput_event_destroy(event); + + litest_assert_empty_queue(li); + +} +END_TEST + START_TEST(tip_down_prox_in) { struct litest_device *dev = litest_current_device(); @@ -274,8 +324,7 @@ litest_push_event_frame(dev); litest_tablet_proximity_in(dev, 10, 10, axes); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); + litest_tablet_tip_down(dev, 10, 10, axes); litest_pop_event_frame(dev); libinput_dispatch(li); @@ -311,15 +360,13 @@ }; litest_tablet_proximity_in(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_tablet_tip_down(dev, 10, 10, axes); litest_drain_events(li); litest_axis_set_value(axes, ABS_DISTANCE, 30); litest_axis_set_value(axes, ABS_PRESSURE, 0); litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 0); + litest_tablet_tip_up(dev, 10, 10, axes); litest_tablet_proximity_out(dev); litest_pop_event_frame(dev); @@ -357,19 +404,15 @@ { -1, -1 } }; - litest_push_event_frame(dev); litest_tablet_proximity_in(dev, 10, 10, axes); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 10, 10, axes); litest_drain_events(li); litest_axis_set_value(axes, ABS_DISTANCE, 30); litest_axis_set_value(axes, ABS_PRESSURE, 0); litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 20, axes); + litest_tablet_tip_up(dev, 10, 20, axes); litest_event(dev, EV_KEY, BTN_STYLUS, 1); - litest_event(dev, EV_KEY, BTN_TOUCH, 0); litest_pop_event_frame(dev); libinput_dispatch(li); @@ -394,18 +437,14 @@ litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 30); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 10, 10, axes); litest_drain_events(li); /* same thing with a release at tip-up */ litest_axis_set_value(axes, ABS_DISTANCE, 30); litest_axis_set_value(axes, ABS_PRESSURE, 0); litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 10, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 0); + litest_tablet_tip_up(dev, 10, 10, axes); litest_event(dev, EV_KEY, BTN_STYLUS, 0); litest_pop_event_frame(dev); @@ -449,9 +488,8 @@ litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 30); litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 20, axes); + litest_tablet_tip_down(dev, 10, 20, axes); litest_event(dev, EV_KEY, BTN_STYLUS, 1); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); litest_pop_event_frame(dev); libinput_dispatch(li); @@ -477,18 +515,14 @@ litest_axis_set_value(axes, ABS_DISTANCE, 30); litest_axis_set_value(axes, ABS_PRESSURE, 0); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 20, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 0); - litest_pop_event_frame(dev); + litest_tablet_tip_up(dev, 10, 20, axes); litest_drain_events(li); /* same thing with a release at tip-down */ litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 30); litest_push_event_frame(dev); - litest_tablet_motion(dev, 10, 20, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); + litest_tablet_tip_down(dev, 10, 20, axes); litest_event(dev, EV_KEY, BTN_STYLUS, 0); litest_pop_event_frame(dev); @@ -542,11 +576,7 @@ /* move x/y on tip down, make sure x/y changed */ litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 20); - litest_push_event_frame(dev); - litest_tablet_motion(dev, 70, 70, axes); - litest_event(dev, EV_KEY, BTN_TOUCH, 1); - litest_event(dev, EV_SYN, SYN_REPORT, 0); - litest_pop_event_frame(dev); + litest_tablet_tip_down(dev, 70, 70, axes);
View file
_service:tar_scm:libinput-1.19.2.tar.xz/test/test-touchpad-buttons.c -> _service:tar_scm:libinput-1.22.1.tar.gz/test/test-touchpad-buttons.c
Changed
@@ -2098,29 +2098,6 @@ } END_TEST -START_TEST(touchpad_clickpad_detection) -{ - struct litest_device *dev; - uint32_t methods; - int codes = { - INPUT_PROP_MAX, INPUT_PROP_BUTTONPAD, - -1, -1, - }; - - /* Create a device with LR buttons and INPUT_PROP_BUTTONPAD set - we - * should ignore the property and assume it's a non-clickpad. - * Only way to check that is to verify no click methods are set. - */ - dev = litest_create_device_with_overrides(LITEST_SYNAPTICS_TOUCHPAD, - "litest Fake Clickpad", - NULL, NULL, codes); - - methods = libinput_device_config_click_get_methods(dev->libinput_device); - ck_assert(methods == 0); - litest_delete_device(dev); -} -END_TEST - TEST_COLLECTION(touchpad_buttons) { struct range finger_count = {1, 4}; @@ -2191,6 +2168,5 @@ litest_add(clickpad_middleemulation_click_enable_while_down, LITEST_CLICKPAD, LITEST_ANY); litest_add(clickpad_middleemulation_click_disable_while_down, LITEST_CLICKPAD, LITEST_ANY); - litest_add_no_device(touchpad_clickpad_detection); litest_add_no_device(touchpad_non_clickpad_detection); }
View file
_service:tar_scm:libinput-1.19.2.tar.xz/test/test-touchpad.c -> _service:tar_scm:libinput-1.22.1.tar.gz/test/test-touchpad.c
Changed
@@ -3346,7 +3346,6 @@ { BTN_1, BTN_RIGHT }, { BTN_2, BTN_MIDDLE }, }; - const struct buttons *b; trackpoint = litest_add_device(li, LITEST_TRACKPOINT); @@ -4196,8 +4195,10 @@ KEY_COMPOSE, KEY_RIGHTMETA, KEY_LEFTMETA, + KEY_ESC, + KEY_KPASTERISK, + KEY_F1, }; - unsigned int *key; if (!has_disable_while_typing(touchpad)) return; @@ -4243,7 +4244,6 @@ KEY_RIGHTMETA, KEY_LEFTMETA, }; - unsigned int *key; if (!has_disable_while_typing(touchpad)) return; @@ -4293,7 +4293,6 @@ KEY_RIGHTMETA, KEY_LEFTMETA, }; - unsigned int *key; if (!has_disable_while_typing(touchpad)) return; @@ -4347,7 +4346,6 @@ KEY_RIGHTMETA, KEY_LEFTMETA, }; - unsigned int *key; if (!has_disable_while_typing(touchpad)) return; @@ -4650,6 +4648,36 @@ } END_TEST +START_TEST(touchpad_dwtp_config_default_on) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + enum libinput_config_status status; + enum libinput_config_dwtp_state state; + + if (litest_touchpad_is_external(dev)) { + ck_assert(!libinput_device_config_dwtp_is_available(device)); + return; + } + + ck_assert(libinput_device_config_dwtp_is_available(device)); + state = libinput_device_config_dwtp_get_enabled(device); + ck_assert_int_eq(state, LIBINPUT_CONFIG_DWTP_ENABLED); + state = libinput_device_config_dwtp_get_default_enabled(device); + ck_assert_int_eq(state, LIBINPUT_CONFIG_DWTP_ENABLED); + + status = libinput_device_config_dwtp_set_enabled(device, + LIBINPUT_CONFIG_DWTP_ENABLED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + status = libinput_device_config_dwtp_set_enabled(device, + LIBINPUT_CONFIG_DWTP_DISABLED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + status = libinput_device_config_dwtp_set_enabled(device, 3); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID); +} +END_TEST + START_TEST(touchpad_dwt_config_default_off) { struct litest_device *dev = litest_current_device(); @@ -4675,6 +4703,31 @@ } END_TEST +START_TEST(touchpad_dwtp_config_default_off) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + enum libinput_config_status status; + enum libinput_config_dwtp_state state; + + ck_assert(!libinput_device_config_dwtp_is_available(device)); + state = libinput_device_config_dwtp_get_enabled(device); + ck_assert_int_eq(state, LIBINPUT_CONFIG_DWTP_DISABLED); + state = libinput_device_config_dwtp_get_default_enabled(device); + ck_assert_int_eq(state, LIBINPUT_CONFIG_DWTP_DISABLED); + + status = libinput_device_config_dwtp_set_enabled(device, + LIBINPUT_CONFIG_DWTP_ENABLED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED); + status = libinput_device_config_dwtp_set_enabled(device, + LIBINPUT_CONFIG_DWTP_DISABLED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + status = libinput_device_config_dwtp_set_enabled(device, 3); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID); +} +END_TEST + static inline void disable_dwt(struct litest_device *dev) { @@ -7304,6 +7357,8 @@ litest_add(touchpad_dwt_enable_before_touch, LITEST_TOUCHPAD, LITEST_ANY); litest_add(touchpad_dwt_enable_during_tap, LITEST_TOUCHPAD, LITEST_ANY); litest_add(touchpad_dwt_remove_kbd_while_active, LITEST_TOUCHPAD, LITEST_ANY); + litest_add(touchpad_dwtp_config_default_on, LITEST_TOUCHPAD, LITEST_ANY); + litest_add(touchpad_dwtp_config_default_off, LITEST_ANY, LITEST_TOUCHPAD); litest_add_for_device(touchpad_dwt_apple, LITEST_BCM5974); litest_add_for_device(touchpad_dwt_acer_hawaii, LITEST_ACER_HAWAII_TOUCHPAD); litest_add_for_device(touchpad_dwt_multiple_keyboards, LITEST_SYNAPTICS_I2C);
View file
_service:tar_scm:libinput-1.19.2.tar.xz/test/test-trackpoint.c -> _service:tar_scm:libinput-1.22.1.tar.gz/test/test-trackpoint.c
Changed
@@ -32,6 +32,12 @@ #include "libinput-util.h" #include "litest.h" +static inline bool +has_disable_while_trackpointing(struct litest_device *device) +{ + return libinput_device_config_dwtp_is_available(device->libinput_device); +} + START_TEST(trackpoint_middlebutton) { struct litest_device *dev = litest_current_device(); @@ -303,6 +309,27 @@ } END_TEST +static inline void +enable_dwtp(struct litest_device *dev) +{ + enum libinput_config_status status, + expected = LIBINPUT_CONFIG_STATUS_SUCCESS; + status = libinput_device_config_dwtp_set_enabled(dev->libinput_device, + LIBINPUT_CONFIG_DWTP_ENABLED); + litest_assert_int_eq(status, expected); +} + +static inline void +disable_dwtp(struct litest_device *dev) +{ + enum libinput_config_status status, + expected = LIBINPUT_CONFIG_STATUS_SUCCESS; + status = libinput_device_config_dwtp_set_enabled(dev->libinput_device, + LIBINPUT_CONFIG_DWTP_DISABLED); + litest_assert_int_eq(status, expected); +} + + START_TEST(trackpoint_palmdetect) { struct litest_device *trackpoint = litest_current_device(); @@ -311,6 +338,9 @@ int i; touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C); + if (has_disable_while_trackpointing(touchpad)) + enable_dwtp(touchpad); + litest_disable_hold_gestures(touchpad->libinput_device); litest_drain_events(li); @@ -339,6 +369,37 @@ } END_TEST +START_TEST(trackpoint_palmdetect_dwtp_disabled) +{ + struct litest_device *trackpoint = litest_current_device(); + struct litest_device *touchpad; + struct libinput *li = trackpoint->libinput; + int i; + + touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C); + if (has_disable_while_trackpointing(touchpad)) + disable_dwtp(touchpad); + + litest_disable_hold_gestures(touchpad->libinput_device); + litest_drain_events(li); + + for (i = 0; i < 10; i++) { + litest_event(trackpoint, EV_REL, REL_X, 1); + litest_event(trackpoint, EV_REL, REL_Y, 1); + litest_event(trackpoint, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + } + litest_drain_events(li); + + litest_touch_down(touchpad, 0, 30, 30); + litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10); + litest_touch_up(touchpad, 0); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); + + litest_delete_device(touchpad); +} +END_TEST + START_TEST(trackpoint_palmdetect_resume_touch) { struct litest_device *trackpoint = litest_current_device(); @@ -347,6 +408,10 @@ int i; touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C); + + if (has_disable_while_trackpointing(touchpad)) + enable_dwtp(touchpad); + litest_disable_hold_gestures(touchpad->libinput_device); litest_drain_events(li); @@ -381,6 +446,10 @@ struct libinput *li = trackpoint->libinput; touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C); + + if (has_disable_while_trackpointing(touchpad)) + enable_dwtp(touchpad); + litest_disable_hold_gestures(touchpad->libinput_device); litest_drain_events(li); @@ -407,6 +476,10 @@ struct libinput *li = trackpoint->libinput; touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C); + + if (has_disable_while_trackpointing(touchpad)) + enable_dwtp(touchpad); + litest_disable_hold_gestures(touchpad->libinput_device); litest_drain_events(li); @@ -441,6 +514,7 @@ litest_add(trackpoint_topsoftbuttons_left_handed_both, LITEST_TOPBUTTONPAD, LITEST_ANY); litest_add(trackpoint_palmdetect, LITEST_POINTINGSTICK, LITEST_ANY); + litest_add(trackpoint_palmdetect_dwtp_disabled, LITEST_POINTINGSTICK, LITEST_ANY); litest_add(trackpoint_palmdetect_resume_touch, LITEST_POINTINGSTICK, LITEST_ANY); litest_add(trackpoint_palmdetect_require_min_events, LITEST_POINTINGSTICK, LITEST_ANY); litest_add(trackpoint_palmdetect_require_min_events_timeout, LITEST_POINTINGSTICK, LITEST_ANY);
View file
_service:tar_scm:libinput-1.19.2.tar.xz/test/test-utils.c -> _service:tar_scm:libinput-1.22.1.tar.gz/test/test-utils.c
Changed
@@ -41,6 +41,57 @@ #include "check-double-macros.h" +START_TEST(array_for_each) +{ + int ai6; + char ac10; + struct as { + int a; + char b; + int *ptr; + } as32; + + for (size_t i = 0; i < 6; i++) + aii = 20 + i; + for (size_t i = 0; i < 10; i++) + aci = 100 + i; + for (size_t i = 0; i < 32; i++) { + asi.a = 10 + i; + asi.b = 20 + i; + asi.ptr = (int*)0xab + i; + } + + int iexpected = 20; + ARRAY_FOR_EACH(ai, entry) { + ck_assert_int_eq(*entry, iexpected); + ++iexpected; + } + ck_assert_int_eq(iexpected, 26); + + int cexpected = 100; + ARRAY_FOR_EACH(ac, entry) { + ck_assert_int_eq(*entry, cexpected); + ++cexpected; + } + ck_assert_int_eq(cexpected, 110); + + struct as sexpected = { + .a = 10, + .b = 20, + .ptr = (int*)0xab, + }; + ARRAY_FOR_EACH(as, entry) { + ck_assert_int_eq(entry->a, sexpected.a); + ck_assert_int_eq(entry->b, sexpected.b); + ck_assert_ptr_eq(entry->ptr, sexpected.ptr); + ++sexpected.a; + ++sexpected.b; + ++sexpected.ptr; + } + ck_assert_int_eq(sexpected.a, 42); +} +END_TEST + START_TEST(bitfield_helpers) { /* This value has a bit set on all of the word boundaries we want to @@ -351,7 +402,8 @@ enum switch_reliability reliability; } tests = { { "reliable", true, RELIABILITY_RELIABLE }, - { "unreliable", false, 0 }, + { "unreliable", true, RELIABILITY_UNRELIABLE }, + { "write_open", true, RELIABILITY_WRITE_OPEN }, { "", false, 0 }, { "0", false, 0 }, { "1", false, 0 }, @@ -373,7 +425,7 @@ success = parse_switch_reliability_property(NULL, &r); ck_assert(success == true); - ck_assert_int_eq(r, RELIABILITY_UNKNOWN); + ck_assert_int_eq(r, RELIABILITY_RELIABLE); success = parse_switch_reliability_property("foo", NULL); ck_assert(success == false); @@ -678,7 +730,6 @@ { .which = 0, .prop = ":asb::::" }, { .which = 0, .prop = "foo" }, }; - struct test *t; ARRAY_FOR_EACH(tests, t) { struct input_absinfo abs; @@ -1019,39 +1070,48 @@ const char *string; const char *delim; const char *results10; + const size_t nresults; } tests = { - { "one two three", " ", { "one", "two", "three", NULL } }, - { "one", " ", { "one", NULL } }, - { "one two ", " ", { "one", "two", NULL } }, - { "one two", " ", { "one", "two", NULL } }, - { " one two", " ", { "one", "two", NULL } }, - { "one", "\t \r", { "one", NULL } }, - { "one two three", " t", { "one", "wo", "hree", NULL } }, - { " one two three", "te", { " on", " ", "wo ", "hr", NULL } }, - { "one", "ne", { "o", NULL } }, - { "onene", "ne", { "o", NULL } }, - { NULL, NULL, { NULL }} + { "one two three", " ", { "one", "two", "three", NULL }, 3 }, + { "one two\tthree", " \t", { "one", "two", "three", NULL }, 3 }, + { "one", " ", { "one", NULL }, 1 }, + { "one two ", " ", { "one", "two", NULL }, 2 }, + { "one two", " ", { "one", "two", NULL }, 2 }, + { " one two", " ", { "one", "two", NULL }, 2 }, + { "one", "\t \r", { "one", NULL }, 1 }, + { "one two three", " t", { "one", "wo", "hree", NULL }, 3 }, + { " one two three", "te", { " on", " ", "wo ", "hr", NULL }, 4 }, + { "one", "ne", { "o", NULL }, 1 }, + { "onene", "ne", { "o", NULL }, 1 }, + { "+1-2++3--4++-+5-+-", "+-", { "1", "2", "3", "4", "5", NULL }, 5 }, + /* special cases */ + { "", " ", { NULL }, 0 }, + { " ", " ", { NULL }, 0 }, + { " ", " ", { NULL }, 0 }, + { "oneoneone", "one", { NULL} , 0 }, + { NULL, NULL, { NULL }, 0} }; struct strsplit_test *t = tests; while (t->string) { - char **strv; - int idx = 0; - strv = strv_from_string(t->string, t->delim); - while (t->resultsidx) { + size_t nelem; + char **strv = strv_from_string(t->string, t->delim, &nelem); + + for (size_t idx = 0; idx < t->nresults; idx++) ck_assert_str_eq(t->resultsidx, strvidx); - idx++; - } - ck_assert_ptr_eq(strvidx, NULL); + + ck_assert_uint_eq(nelem, t->nresults); + + /* When there are no elements validate return value is Null, + otherwise validate result array is Null terminated. */ + if(t->nresults == 0) + ck_assert_ptr_eq(strv, NULL); + else + ck_assert_ptr_eq(strvt->nresults, NULL); + strv_free(strv); t++; } - - /* Special cases */ - ck_assert_ptr_eq(strv_from_string("", " "), NULL); - ck_assert_ptr_eq(strv_from_string(" ", " "), NULL); - ck_assert_ptr_eq(strv_from_string(" ", " "), NULL); - ck_assert_ptr_eq(strv_from_string("oneoneone", "one"), NULL); } END_TEST @@ -1071,7 +1131,6 @@ { 1, {NULL, NULL}, 0 }, { 3, {"hello", NULL, "World"}, 0 }, }; - struct argv_test *t; ARRAY_FOR_EACH(tests, t) { char **strv = strv_from_argv(t->argc, t->argv); @@ -1267,6 +1326,31 @@ } END_TEST +START_TEST(strsanitize_test) +{ + struct strsanitize_test { + const char *string; + const char *expected; + } tests = { + { "foobar", "foobar" }, + { "", "" }, + { "%", "%%" }, + { "%%%%", "%%%%%%%%" }, + { "x %s", "x %%s" }, + { "x %", "x %%" }, + { "%sx", "%%sx" }, + { "%s%s", "%%s%%s" }, + { NULL, NULL }, + }; + + for (struct strsanitize_test *t = tests; t->string; t++) { + char *sanitized = str_sanitize(t->string); + ck_assert_str_eq(sanitized, t->expected); + free(sanitized); + } +} +END_TEST + START_TEST(list_test_insert) { struct list_test { @@ -1414,7 +1498,6 @@ { "/bar", "bar" },
View file
_service:tar_scm:libinput-1.19.2.tar.xz/tools/libinput-analyze-recording.py -> _service:tar_scm:libinput-1.22.1.tar.gz/tools/libinput-analyze-recording.py
Changed
@@ -30,6 +30,7 @@ # Input is a libinput record yaml file import argparse +import os import sys import yaml import libevdev @@ -52,7 +53,7 @@ # The list of axes we want to track -def is_tracked_axis(code): +def is_tracked_axis(code, allowlist, denylist): if code.type in (libevdev.EV_KEY, libevdev.EV_SW, libevdev.EV_SYN): return False @@ -61,7 +62,10 @@ if libevdev.EV_ABS.ABS_MT_SLOT <= code <= libevdev.EV_ABS.ABS_MAX: return False - return True + if allowlist: + return code in allowlist + else: + return code not in denylist def main(argv): @@ -71,7 +75,34 @@ parser.add_argument( "path", metavar="recording", nargs=1, help="Path to libinput-record YAML file" ) + parser.add_argument( + "--ignore", + metavar="ABS_X,ABS_Y,...", + default="", + help="A comma-separated list of axis names to ignore", + ) + parser.add_argument( + "--only", + metavar="ABS_X,ABS_Y,...", + default="", + help="A comma-separated list of axis names to print, ignoring all others", + ) + parser.add_argument( + "--print-state", + action="store_true", + default=False, + help="Always print all axis values, even unchanged ones", + ) + args = parser.parse_args() + if args.ignore and args.only: + print("Only one of --ignore and --only may be given", file=sys.stderr) + sys.exit(2) + + ignored_axes = libevdev.evbit(axis) for axis in args.ignore.split(",") if axis + only_axes = libevdev.evbit(axis) for axis in args.only.split(",") if axis + + isatty = os.isatty(sys.stdout.fileno()) yml = yaml.safe_load(open(args.path0)) if yml"ndevices" > 1: @@ -101,7 +132,9 @@ """ used_axes = for e in events: - if e.code not in used_axes and is_tracked_axis(e.code): + if e.code not in used_axes and is_tracked_axis( + e.code, only_axes, ignored_axes + ): yield e.code used_axes.append(e.code) @@ -121,6 +154,7 @@ print(header_line) print("-" * len(header_line)) + current_codes = current_frame = {} # {evdev-code: value} axes_in_use = {} # to print axes never sending events last_fields = # to skip duplicate lines @@ -135,22 +169,28 @@ if e.code.type == libevdev.EV_KEY: keystatee.code = e.value keystate_changed = True - elif is_tracked_axis(e.code): + elif is_tracked_axis(e.code, only_axes, ignored_axes): current_framee.code = e.value + current_codes.append(e.code) elif e.code == libevdev.EV_SYN.SYN_REPORT: fields = for a in axes: - s = format_value(a, current_framea) if a in current_frame else " " + if args.print_state or a in current_codes: + s = format_value(a, current_frame.get(a, 0)) + else: + s = "" fields.append(s.rjust(max(MIN_FIELD_WIDTH, axesa))) - current_frame = {} + current_codes = if last_fields != fields or keystate_changed: last_fields = fields.copy() keystate_changed = False if continuation_count: - continuation_count = 0 + if not isatty: + print(f" ... +{continuation_count}", end="") print("") + continuation_count = 0 fields.insert(0, f"{e.sec: 3d}.{e.usec//1000:03d}") keys_down = k.name for k, v in keystate.items() if v @@ -158,7 +198,8 @@ print(" | ".join(fields)) else: continuation_count += 1 - print(f"\r ... +{continuation_count}", end="", flush=True) + if isatty: + print(f"\r ... +{continuation_count}", end="", flush=True) # Print out any rel/abs axes that not generate events in # this recording @@ -166,7 +207,10 @@ for evtype, evcodes in device"evdev""codes".items(): for c in evcodes: code = libevdev.evbit(int(evtype), int(c)) - if is_tracked_axis(code) and code not in axes_in_use: + if ( + is_tracked_axis(code, only_axes, ignored_axes) + and code not in axes_in_use + ): unused_axes.append(code) if unused_axes:
View file
_service:tar_scm:libinput-1.19.2.tar.xz/tools/libinput-debug-events.c -> _service:tar_scm:libinput-1.22.1.tar.gz/tools/libinput-debug-events.c
Changed
@@ -226,6 +226,14 @@ printq(" dwt-off)"); } + if (libinput_device_config_dwtp_is_available(dev)) { + if (libinput_device_config_dwtp_get_enabled(dev) == + LIBINPUT_CONFIG_DWTP_ENABLED) + printq(" dwtp-on"); + else + printq(" dwtp-off)"); + } + if (libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_TABLET_PAD)) { int nbuttons, nstrips, nrings, ngroups; @@ -944,6 +952,9 @@ libinput_event_destroy(ev); rc = 0; } + + fflush(stdout); + return rc; }
View file
_service:tar_scm:libinput-1.19.2.tar.xz/tools/libinput-debug-events.man -> _service:tar_scm:libinput-1.22.1.tar.gz/tools/libinput-debug-events.man
Changed
@@ -79,6 +79,9 @@ .B \-\-enable\-dwt|\-\-disable\-dwt Enable or disable disable-while-typing .TP 8 +.B \-\-enable\-dwtp|\-\-disable\-dwtp +Enable or disable disable-while-trackpointing +.TP 8 .B \-\-enable\-scroll-button-lock|\-\-disable\-scroll-button-lock Enable or disable the scroll button lock .TP 8
View file
_service:tar_scm:libinput-1.19.2.tar.xz/tools/libinput-debug-gui.c -> _service:tar_scm:libinput-1.22.1.tar.gz/tools/libinput-debug-gui.c
Changed
@@ -48,7 +48,7 @@ #include "shared.h" -#ifdef GDK_WINDOWING_WAYLAND +#if HAVE_GTK_WAYLAND #include <wayland-client.h> #include "pointer-constraints-unstable-v1-client-protocol.h" #if HAVE_GTK4 @@ -58,7 +58,7 @@ #endif #endif -#ifdef GDK_WINDOWING_X11 +#if HAVE_GTK_X11 #include <X11/X.h> #include <X11/Xlib.h> #if HAVE_GTK4 @@ -120,7 +120,7 @@ struct { bool locked; -#ifdef GDK_WINDOWING_WAYLAND +#if HAVE_GTK_WAYLAND struct zwp_pointer_constraints_v1 *wayland_pointer_constraints; struct zwp_locked_pointer_v1 *wayland_locked_pointer; #endif @@ -207,7 +207,7 @@ struct libinput_device *devices50; }; -#ifdef GDK_WINDOWING_WAYLAND +#if HAVE_GTK_WAYLAND static void wayland_registry_global(void *data, struct wl_registry *registry, @@ -297,9 +297,9 @@ { return GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default()); } -#endif /* GDK_WINDOWING_WAYLAND */ +#endif /* HAVE_GTK_WAYLAND */ -#ifdef GDK_WINDOWING_X11 +#if HAVE_GTK_X11 static bool x_lock_pointer(struct window *w) { @@ -342,19 +342,20 @@ { return GDK_IS_X11_DISPLAY(gdk_display_get_default()); } -#endif /* GDK_WINDOWING_X11 */ +#endif /* HAVE_GTK_X11 */ static bool window_lock_pointer(struct window *w) { - w->lock_pointer.locked = false; + if (w->lock_pointer.locked) + return true; -#ifdef GDK_WINDOWING_WAYLAND +#if HAVE_GTK_WAYLAND if (backend_is_wayland()) w->lock_pointer.locked = wayland_lock_pointer(w); #endif -#ifdef GDK_WINDOWING_X11 +#if HAVE_GTK_X11 if (backend_is_x11()) w->lock_pointer.locked = x_lock_pointer(w); #endif @@ -370,12 +371,12 @@ w->lock_pointer.locked = false; -#ifdef GDK_WINDOWING_WAYLAND +#if HAVE_GTK_WAYLAND if (backend_is_wayland()) wayland_unlock_pointer(w); #endif -#ifdef GDK_WINDOWING_X11 +#if HAVE_GTK_X11 if (backend_is_x11()) x_unlock_pointer(w); #endif @@ -603,8 +604,6 @@ static inline void draw_touchpoints(struct window *w, cairo_t *cr) { - struct touch *t; - cairo_save(cr); ARRAY_FOR_EACH(w->touches, t) { if (t->state == TOUCH_ACTIVE) @@ -1155,7 +1154,6 @@ static void window_cleanup(struct window *w) { - struct libinput_device **dev; ARRAY_FOR_EACH(w->devices, dev) { if (*dev) libinput_device_unref(*dev); @@ -1165,8 +1163,6 @@ static void change_ptraccel(struct window *w, double amount) { - struct libinput_device **dev; - ARRAY_FOR_EACH(w->devices, dev) { double speed; enum libinput_config_status status; @@ -1341,7 +1337,6 @@ handle_event_device_notify(struct libinput_event *ev) { struct libinput_device *dev = libinput_event_get_device(ev); - struct libinput_device **device; struct libinput *li; struct window *w; const char *type;
View file
_service:tar_scm:libinput-1.19.2.tar.xz/tools/libinput-debug-tablet.c -> _service:tar_scm:libinput-1.22.1.tar.gz/tools/libinput-debug-tablet.c
Changed
@@ -307,7 +307,6 @@ { struct libinput_event_tablet_tool *t = libinput_event_get_tablet_tool_event(ev); unsigned int button = libinput_event_tablet_tool_get_button(t); - unsigned int *btn; enum libinput_button_state state = libinput_event_tablet_tool_get_button_state(t); ARRAY_FOR_EACH(ctx->buttons_down, btn) {
View file
_service:tar_scm:libinput-1.19.2.tar.xz/tools/libinput-list-devices.c -> _service:tar_scm:libinput-1.22.1.tar.gz/tools/libinput-list-devices.c
Changed
@@ -226,6 +226,18 @@ return "disabled"; } +static const char * +dwtp_default(struct libinput_device *device) +{ + if (!libinput_device_config_dwtp_is_available(device)) + return "n/a"; + + if (libinput_device_config_dwtp_get_default_enabled(device)) + return "enabled"; + + return "disabled"; +} + static char * rotation_default(struct libinput_device *device) { @@ -344,6 +356,7 @@ free(str); printf("Disable-w-typing: %s\n", dwt_default(dev)); + printf("Disable-w-trackpointing: %s\n", dwtp_default(dev)); str = accel_profiles(dev); printf("Accel profiles: %s\n", str);
View file
_service:tar_scm:libinput-1.19.2.tar.xz/tools/libinput-record.c -> _service:tar_scm:libinput-1.22.1.tar.gz/tools/libinput-record.c
Changed
@@ -48,6 +48,7 @@ #include "libinput-git-version.h" #include "shared.h" #include "builddir.h" +#include "util-bits.h" #include "util-list.h" #include "util-time.h" #include "util-input-event.h" @@ -60,7 +61,7 @@ I_NONE = 0, I_TOPLEVEL = 0, I_LIBINPUT = 2, /* nodes inside libinput: */ - I_SYSTEM = 0, /* nodes inside system: */ + I_SYSTEM = 2, /* nodes inside system: */ I_DEVICE = 2, /* nodes inside devices: */ I_EVDEV = 4, /* nodes inside evdev: */ I_EVDEV_DATA = 6, /* nodes below evdev: */ @@ -391,9 +392,9 @@ assert(slot < sizeof(d->touch.slot_state) * 8); if (e.value != -1) - d->touch.slot_state |= 1 << slot; + d->touch.slot_state |= bit(slot); else - d->touch.slot_state &= ~(1 << slot); + d->touch.slot_state &= ~bit(slot); } if (e.type == EV_SYN && e.code == SYN_REPORT) @@ -1290,7 +1291,10 @@ if (!e) return false; - iprintf(d->fp, I_EVENTTYPE, "%slibinput:\n", start_frame ? "- " : ""); + if (start_frame) + iprintf(d->fp, I_EVENTTYPE, "- libinput:\n"); + else + iprintf(d->fp, I_EVENTTYPE, "libinput:\n"); do { struct libinput_device *device = libinput_event_get_device(e); @@ -1819,7 +1823,6 @@ {LIBINPUT_DEVICE_CAP_GESTURE, "gesture"}, {LIBINPUT_DEVICE_CAP_SWITCH, "switch"}, }; - struct cap *cap; const char *sep = ""; if (!device)
View file
_service:tar_scm:libinput-1.22.1.tar.gz/tools/libinput-test.c
Added
@@ -0,0 +1,76 @@ +/* + * Copyright © 2017 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include <getopt.h> +#include <stdio.h> + +#include "shared.h" + +static inline void +usage(void) +{ +#if HAVE_INSTALLED_TESTS + printf("Usage: libinput test --help <feature>\n"); +#else + fprintf(stderr, "libinput test was disabled in the build configuration\n"); +#endif +} + +int +main(int argc, char **argv) +{ + int option_index = 0; + + while (1) { + int c; + static struct option opts = { + { "help", no_argument, 0, 'h' }, + { 0, 0, 0, 0} + }; + + c = getopt_long(argc, argv, "+h", opts, &option_index); + if (c == -1) + break; + + switch(c) { + case 'h': + usage(); + return EXIT_SUCCESS; + default: + usage(); + return EXIT_FAILURE; + } + } + + if (optind >= argc) { + usage(); + return EXIT_FAILURE; + } + + argc--; + argv++; + + return tools_exec_command("libinput-test", argc, argv); +}
View file
_service:tar_scm:libinput-1.22.1.tar.gz/tools/libinput-test.man
Added
@@ -0,0 +1,36 @@ + +.TH libinput-test "1" "" "libinput @LIBINPUT_VERSION@" "libinput Manual" +.SH NAME +libinput\-test \- test various components of libinput itself +.SH SYNOPSIS +.B libinput test \-\-help \fI<feature> <args>\fR +.SH DESCRIPTION +.PP +The +.B "libinput test" +tool runs tests against libinput itself. There is usually no need for a user +to use this tool, it is provided for distribution vendors. +@HAVE_INSTALLED_TESTS@.B This tool was disabled at build time! +.PP +This is a testing tool only, its output may change at any time. Do not +rely on the output. +.PP +This tool may need to be run as root to have access to the +/dev/input/eventX nodes and/or create /dev/uinput devices. +.SH OPTIONS +.TP 8 +.B \-\-help +Print help +.SH FEATURES +Tests that can be run are +.TP 8 +.B libinput\-test\-suite(1) +Run the full test suite. This is the most complete set of tests to run in +libinput. +.TP 8 +.B libinput\-test\-utils +Run the test suite suite for internal utility functions. +.SH LIBINPUT +Part of the +.B libinput(1) +suite
View file
_service:tar_scm:libinput-1.19.2.tar.xz/tools/libinput-tool.c -> _service:tar_scm:libinput-1.22.1.tar.gz/tools/libinput-tool.c
Changed
@@ -46,9 +46,11 @@ " debug-events\n" " Print events to stdout\n" "\n" +#if HAVE_DEBUG_GUI " debug-gui\n" " Display a simple GUI to visualize libinput's events.\n" "\n" +#endif " measure <feature>\n" " Measure various device properties. See the man page for more info\n" "\n"
View file
_service:tar_scm:libinput-1.19.2.tar.xz/tools/libinput.man -> _service:tar_scm:libinput-1.22.1.tar.gz/tools/libinput.man
Changed
@@ -56,6 +56,9 @@ .TP 8 .B libinput\-analyze(1) Analyze events from a device +.TP 8 +.B libinput\-test(1) +Test libinput itself. .SH LIBINPUT Part of the .B libinput(1)
View file
_service:tar_scm:libinput-1.19.2.tar.xz/tools/shared.c -> _service:tar_scm:libinput-1.22.1.tar.gz/tools/shared.c
Changed
@@ -107,6 +107,7 @@ options->left_handed = -1; options->middlebutton = -1; options->dwt = -1; + options->dwtp = -1; options->click_method = -1; options->scroll_method = -1; options->scroll_button = -1; @@ -175,6 +176,12 @@ case OPT_DWT_DISABLE: options->dwt = LIBINPUT_CONFIG_DWT_DISABLED; break; + case OPT_DWTP_ENABLE: + options->dwtp = LIBINPUT_CONFIG_DWTP_ENABLED; + break; + case OPT_DWTP_DISABLE: + options->dwtp = LIBINPUT_CONFIG_DWTP_DISABLED; + break; case OPT_CLICK_METHOD: if (!optarg) return 1; @@ -437,6 +444,9 @@ if (options->dwt != -1) libinput_device_config_dwt_set_enabled(device, options->dwt); + if (options->dwtp != -1) + libinput_device_config_dwtp_set_enabled(device, options->dwtp); + if (options->click_method != (enum libinput_config_click_method)-1) libinput_device_config_click_set_method(device, options->click_method); @@ -693,6 +703,7 @@ uint32_t v; char *s; double d; + bool b; name = quirk_get_name(q); @@ -733,7 +744,8 @@ break; case QUIRK_ATTR_USE_VELOCITY_AVERAGING: case QUIRK_ATTR_TABLET_SMOOTHING: - snprintf(buf, sizeof(buf), "%s=1", name); + quirks_get_bool(quirks, q, &b); + snprintf(buf, sizeof(buf), "%s=%d", name, b); callback(userdata, buf); break; case QUIRK_ATTR_EVENT_CODE_DISABLE:
View file
_service:tar_scm:libinput-1.19.2.tar.xz/tools/shared.h -> _service:tar_scm:libinput-1.22.1.tar.gz/tools/shared.h
Changed
@@ -48,6 +48,8 @@ OPT_MIDDLEBUTTON_DISABLE, OPT_DWT_ENABLE, OPT_DWT_DISABLE, + OPT_DWTP_ENABLE, + OPT_DWTP_DISABLE, OPT_CLICK_METHOD, OPT_SCROLL_METHOD, OPT_SCROLL_BUTTON, @@ -75,6 +77,8 @@ { "disable-middlebutton", no_argument, 0, OPT_MIDDLEBUTTON_DISABLE }, \ { "enable-dwt", no_argument, 0, OPT_DWT_ENABLE }, \ { "disable-dwt", no_argument, 0, OPT_DWT_DISABLE }, \ + { "enable-dwtp", no_argument, 0, OPT_DWTP_ENABLE }, \ + { "disable-dwtp", no_argument, 0, OPT_DWTP_DISABLE }, \ { "enable-scroll-button-lock", no_argument, 0, OPT_SCROLL_BUTTON_LOCK_ENABLE }, \ { "disable-scroll-button-lock",no_argument, 0, OPT_SCROLL_BUTTON_LOCK_DISABLE }, \ { "set-click-method", required_argument, 0, OPT_CLICK_METHOD }, \ @@ -107,6 +111,7 @@ int scroll_button_lock; double speed; int dwt; + int dwtp; enum libinput_config_accel_profile profile; char disable_pattern64; };
View file
_service:tar_scm:libinput-1.19.2.tar.xz/tools/test_tool_option_parsing.py -> _service:tar_scm:libinput-1.22.1.tar.gz/tools/test_tool_option_parsing.py
Changed
@@ -210,6 +210,7 @@ "natural-scrolling", "left-handed", "dwt", + "dwtp", , # options with distinct values "enums": {
View file
_service:tar_scm:libinput-1.19.2.tar.xz/udev/libinput-device-group.c -> _service:tar_scm:libinput-1.22.1.tar.gz/udev/libinput-device-group.c
Changed
@@ -62,7 +62,6 @@ if (db) libwacom_database_destroy(db); } -#endif static int find_tree_distance(struct udev_device *a, struct udev_device *b) @@ -148,6 +147,7 @@ udev_enumerate_unref(e); } +#endif int main(int argc, char **argv) {
View file
_service:tar_scm:libinput-1.19.2.tar.xz/udev/libinput-fuzz-extract.c -> _service:tar_scm:libinput-1.22.1.tar.gz/udev/libinput-fuzz-extract.c
Changed
@@ -46,7 +46,6 @@ struct libevdev *evdev = NULL; int fd = -1; int rc; - unsigned int *code; unsigned int axes = {ABS_X, ABS_Y, ABS_MT_POSITION_X, @@ -88,7 +87,6 @@ static void handle_evdev_abs(struct udev_device *device) { - unsigned int *code; unsigned int axes = {ABS_X, ABS_Y, ABS_MT_POSITION_X,
View file
_service:tar_scm:libinput-1.19.2.tar.xz/udev/libinput-fuzz-to-zero.c -> _service:tar_scm:libinput-1.22.1.tar.gz/udev/libinput-fuzz-to-zero.c
Changed
@@ -39,7 +39,6 @@ struct libevdev *evdev = NULL; int fd = -1; int rc; - unsigned int *code; unsigned int axes = {ABS_X, ABS_Y, ABS_MT_POSITION_X,
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2