weston input 概述

article/2025/10/11 1:48:50

weston input 概述

零、前言

本文描述了有关于 weston (基于 wayland 协议一种显示服务器的实现) 中有关于输入设备管理的部分;为了聚焦于此,本文不会对 weston 整体或 wayland 协议进行过多的阐述.

考虑到读者可能存在不同的需求,采用分层次的描述方式,主要面向以下两类人群:

  • 想了解通用显示服务器有关于输入设备管理
  • 想了解 weston 有关于输入设备管理

对于前者,将会站在一个较为抽象的层次,以感性的方式讲述一个通用显示服务器的设计; 对于后者,则更多地会参考 weston 的实现细节,结合一些代码示例,帮助读者更好地理解 weston, 为将来阅读 weston 源码做好一定的准备.

本文基于 weston 10.0.2 分支.

一、显示服务器与输入设备

不知道有没有人会与我一样疑惑,为什么 显示服务器 会与 输入设备 扯上关系呢?

有关于这点的答案实际上很多显示服务器官方都给出了自己的答案,目前主流的答案是: 现代 GUI 程序跟以往的(后台)程序不同,面向的是用户,强调的是交互;因此对于交互的反馈速度(50ms以内)十分看中,为此 GUI 程序一般采取的都是异步编程的方式进行,更为具体的描述是采用事件驱动的异步编程模式.

因此, GUI 程序的 UI 发生改变一定是受到了某些信号源驱动,信号驱动源从广义上可以分为硬件和软件两类:

  • 硬件 : 鼠标、 键盘、 触摸 、蓝牙等
  • 软件 : 定时器 、HTTP/IOT/WS 接口等

其中对于软件类的更多GUI设计者会更加熟悉,例如我们会使用一个定时器去实现一些动态效果(比如说 gif 的播放),利用 IOT 去操作设备以及可能暴露一些 HTTP 接口去进行接口测试.

显示服务器管理的是硬件相关的信号源,而非软件信号源, 理解这点是至关重要的.对于软件信号源,其针对的是 GUI 程序这个进程本身;对于硬件信号源,其针对的是整个系统;两者的影响范围或者说作用域是不同的.

而对于一个正常的 GUI 程序,肯定是不希望其在最小化或者被其他 GUI程序遮挡时仍然接收到诸如鼠标、触摸等事件,毫无疑问如果是这样的话,那将是一件相当奇怪的事情.

所以显示服务器才会代替 GUI 程序去接管系统设备的输入,并针对不同的 GUI 程序进行合适的滤波以及转换 (比如在 GUI 程序隐藏时就输入事件分发给它们),使得在 GUI 程序侧硬件输入的处理逻辑与软件输入没有差异.

二、输入设备种类

根据 weston 的实现,将 weston 的输入设备分为了三大类,具体如下图所示:

在这里插入图片描述

其中 seat 代表的是输入设备的抽象形式,而 pointertouchkeyboard 则代表的是不同种类的输入设备; 这么划分实际上很大程度上是由输入设备硬件本身的特性,几种不同输入设备的特性如下:

  • pointer : 常见的设备类型为鼠标,其特点是输入一般以相对坐标的方式给出,即给出是一个矢量
  • keyboard : 常见的设备类型为键盘,其特点是输入一般以键值给出,例如 ABCD
  • touch : 常见的设备类型为触摸屏,其特点是输入一般以绝对坐标的方式给出

上面各个输入设备的特性从日常使用角度理解起来应该是不难的; 值得一提的是 seat 这个作为其抽象的命名,其具体命名的意图我也不是特别理解,但 seat 并非是 weston 创造的名词,其命名依据来自于一个专门负责输入设备管理的库libinput.

三、显示服务器输入管理设备总体设计

在描述 weston 整体输入管理之前,有必要先停下来,捋一捋weston输入设备管理需要实现的目标:

  • 获取(linux)系统输入事件捕获,以及监听输入设备
  • GUI程序提供统一的输入事件逻辑
  • 按照GUI程序的需求派发不同的输入事件

其中一点是为了获取完整的来自系统的输入事件;
第二点则更多的是标准化的过程,例如虽然 keyboard 类型的输入设备虽然大多数都是键盘,但是像是红外遥控器、蓝牙遥控器等也算是 keyboard 中的一种,在 GUI程序看起来它们像是行为一致的,但是站在 linux 驱动层与应用层之间则不尽其然, weston 需要将各种输入设备进行分类(pointerkyeboardtouch),然后屏蔽各个输入设备之间具体的细节差异;
第三点而是需要根据应用的需求派发事件,例如有些应用只关注于触摸事件,而对键盘事件不敏感,那么 weston 就不应该将事件分发给它们,当程序不处于焦点状态(选中状态)时,也不应该将事件派发给它们.

基于以上描述, weston 给出的整体设计为:

在这里插入图片描述

其中 weston 处于第二级,向左对接 linux 系统, 向右则对接 wayland 显示服务器协议;然后 weston (display server) 和 GUI 程序 (display client) 通过 wayland (显示服务器)协议连接起来.

第二级中,对于捕获的输入事件 weston 首先将其进行标准化,然后对其进行简单的滤波,最后按照需求进行分发;同时监听系统本身的输入设备,管理输入设备的声明周期.

到此为止,一个较为通用的显示服务器关于输入设备的管理就已经讲解完了,剩下的都是一些比较细节的实现,比如说滤波究竟做了些什么,标准化又做了什么,其实对于大多数应用层开发者都已经是非常的遥远的事情了,所以就此收手也是不错的选择.

如果想要对 weston 有一个整体性的理解,推荐阅读 Wayland与Weston简介,而对于 wayland 协议的架构设计,则可以参考 wayland.

四、显示服务器细节设计

(1) 对接系统输入

在讲解之前,需要审视一下 weston 作为一个显示服务器的职责: 毫无疑问那将是渲染,而非输入.

基于此, weston 在对接系统输入这一块并没有做很多的事情,而是利用现在成熟的开源方案, libinput 以及 udev.

  • libinput : 获取输入事件以及设备状态
  • udev : 管理输入设备

weston 对于 libinput 的封装主要存在于 libweston/libinput-device.c, 而 udev 则是位于 libweston/libinput-seat.c.

对于输入设备的监听,主要是基于 Reactor 模式进行; 通俗地讲就是在每个循环的周期内查询有无设备的移除以及添加相关的事件,具体的细节实现如下:

// file : libweston/libinput-seat.c// 一次循环周期内调用
static int
udev_input_process_event(struct libinput_event *event)
{struct libinput *libinput = libinput_event_get_context(event);struct libinput_device *libinput_device =libinput_event_get_device(event);struct udev_input *input = libinput_get_user_data(libinput);int ret = 0;switch (libinput_event_get_type(event)) { // 获取输入事件类型类型 (libinput)case LIBINPUT_EVENT_DEVICE_ADDED: // 设备添加ret = device_added(input, libinput_device);break;case LIBINPUT_EVENT_DEVICE_REMOVED: // 设备移除ret = device_removed(input, libinput_device);break;default:evdev_device_process_event(event);break;}return ret;
}// 设备添加
static int
device_added(struct udev_input *input, struct libinput_device *libinput_device)
{// ...udev_seat = get_udev_seat(input, libinput_device); // udev, 获取 seatif (!udev_seat) {weston_log("Failed to get a seat\n");return 1;}seat = &udev_seat->base;device = evdev_device_create(libinput_device, seat); // udev, 创建设备节点if (device == NULL) {weston_log("Failed to create a device\n");return 1;}// ...return 0;
}

对于输入事件的监听,同样是位于上面代码片段 udev_input_process_event 中的 evdev_device_process_event,具体实现如下:

// file : libweston/libinput-device.c
int
evdev_device_process_event(struct libinput_event *event)
{struct libinput_device *libinput_device =libinput_event_get_device(event);struct evdev_device *device =libinput_device_get_user_data(libinput_device);int handled = 1;bool need_frame = false;if (!device)return 0;switch (libinput_event_get_type(event)) {case LIBINPUT_EVENT_KEYBOARD_KEY:handle_keyboard_key(libinput_device,libinput_event_get_keyboard_event(event));break;case LIBINPUT_EVENT_POINTER_MOTION:need_frame = handle_pointer_motion(libinput_device,libinput_event_get_pointer_event(event));break;case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:need_frame = handle_pointer_motion_absolute(libinput_device,libinput_event_get_pointer_event(event));break;case LIBINPUT_EVENT_POINTER_BUTTON:need_frame = handle_pointer_button(libinput_device,libinput_event_get_pointer_event(event));break;case LIBINPUT_EVENT_POINTER_AXIS:need_frame = handle_pointer_axis(libinput_device,libinput_event_get_pointer_event(event));break;case LIBINPUT_EVENT_TOUCH_DOWN:handle_touch_down(libinput_device,libinput_event_get_touch_event(event));break;case LIBINPUT_EVENT_TOUCH_MOTION:handle_touch_motion(libinput_device,libinput_event_get_touch_event(event));break;case LIBINPUT_EVENT_TOUCH_UP:handle_touch_up(libinput_device,libinput_event_get_touch_event(event));break;case LIBINPUT_EVENT_TOUCH_FRAME:handle_touch_frame(libinput_device,libinput_event_get_touch_event(event));break;default:handled = 0;weston_log("unknown libinput event %d\n",libinput_event_get_type(event));}if (need_frame)notify_pointer_frame(device->seat);return handled;
}

(2) 对接 wayland 协议

在阅读此之前,应当对 wayland 有足够的了解; 如果还不是很清楚, 可以参考 wayland.

wayland 定义了协议,那么 weston 对接 wayland 协议做的自然就是实现协议; 事实上, waylandfreedesktop 给出的标准规范, 而 weston 则是 freedesktop 给出的
参考实现.

那么回到代码上,又应该如何去做的;如果站在抽象语言的角度,wayland 是定义了一个接口类,而 weston 则是继承其并实现;在 C 语言的世界里,这通常使用函数指针来辅助完成,下面以 keyboard 作为一个示例进行描述:

// file : include/libweston/libweston.h
// 接口定义
struct weston_keyboard_grab;
struct weston_keyboard_grab_interface {void (*key)(struct weston_keyboard_grab *grab,const struct timespec *time, uint32_t key, uint32_t state);void (*modifiers)(struct weston_keyboard_grab *grab, uint32_t serial,uint32_t mods_depressed, uint32_t mods_latched,uint32_t mods_locked, uint32_t group);void (*cancel)(struct weston_keyboard_grab *grab);
};// file : libweston/input.c
// 接口实现
static const struct weston_keyboard_grab_interfacedefault_keyboard_grab_interface = {default_grab_keyboard_key,default_grab_keyboard_modifiers,default_grab_keyboard_cancel,
};// 接口绑定
// 以 default_grab_keyboard_key 为例
WL_EXPORT void
weston_keyboard_send_key(struct weston_keyboard *keyboard,const struct timespec *time, uint32_t key,enum wl_keyboard_key_state state)
{struct wl_resource *resource;struct wl_display *display = keyboard->seat->compositor->wl_display;uint32_t serial;struct wl_list *resource_list;uint32_t msecs;if (!weston_keyboard_has_focus_resource(keyboard))return;resource_list = &keyboard->focus_resource_list;serial = wl_display_next_serial(display);msecs = timespec_to_msec(time);wl_resource_for_each(resource, resource_list) {send_timestamps_for_input_resource(resource,&keyboard->timestamps_list,time);wl_keyboard_send_key(resource, serial, msecs, key, state); // 注意 wl 是 wayland 的缩写,这里已经完成了对 wayland 协议的对接了}
};static void
default_grab_keyboard_key(struct weston_keyboard_grab *grab,const struct timespec *time, uint32_t key,uint32_t state)
{weston_keyboard_send_key(grab->keyboard, time, key, state);
}

四、后续

在第三大点中显示服务器输入管理设备总体设计,整体设计上整体由四部分组成.除去 display client, 在第四大点中也仅仅只讲述了linux事件捕获和对接wayland,也就是第一节点以及第三节点;而对于第二节点weston自身的实现甚至于只字不提.

在第二节点中描述了 事件标准化事件滤波 以及 事件分发,实际上真实场景远复杂于此;第一部分 weston (libweston/libinput-seat.c 、libweston/libinput-device.c) 合起来也只用来 1300 行左右; 但是第二部分光是 libweston/input.c 都超过了 5000 行,都还没计算 libweston/compositor.c 与此相关的代码.

以上现象说明 weston 对于输入设备的处理本质上是业务代码,维护在大量的上下文状态,根据实际业务场景添加了初看来奇奇怪怪的功能. 对于业务代码,绝非去描述具体的业务逻辑,更多的则是应当于去剖析作者的代码习惯以及风格,帮助读者去阅读理解理解对应的代码,让读者具备独立理解其对应业务的能力.

可能的话,对这部分内容的描述,可能从三个方面去切入;

一方面将会跟随 weston 变更记录(git),描述 weston 在添加某些功能时的具体做法,比如说添加了一个屏幕校准功能的实现,以增量的方式去讲解业务实现;

另一方面则会描述 weston 有关于此最为关键的业务流程,比如说窗口聚焦的实现,以最基础全量的方式去描述其业务实现;

最后则会讲述一下此部分对应代码提交者的代码风格,其编程手法、编程习惯以及对应的编程技巧.

实际上最后一点对于理解代码是非常重要的,理解作者的思维模式,对于代码的理解是具有非常重要的意义,远超于前两点.


http://chatgpt.dhexx.cn/article/0FTiulS2.shtml

相关文章

weston 2: 登录后直接启动weston配置

本人Kubuntu版本是22.04 名词:SDDM(SDDM - Arch Linux 中文维基)显示管理器 配置流程如下: 1.修改配置文件 a.配置.bashrc vim ~/.bashrc //以下内容删除 #export WLD$HOME/install #export LD_LIBRARY_PATH$WLD/lib/x86_64-…

Weston介绍

Weston结构说明 Weston源码结构 clients:wayland显示客户端应用 compositor:合成器进程(服务端),窗体风 格样式处理 libweston:合成器以及客户端渲染处理以及驱动实现方式,以及wayland服务与客户…

Wayland/Weston 启动方式简介

前言 本文简单介绍 Weston 常用的几种 backend 启动方式。目前最新的 Weston 8.0.0 支持如下几种 backend: drm-backendfbdev-backendheadless-backendrdp-backendwayland-backendx11-backend 其中 headless-backend 不带任何 UI 界面,主要用于 westo…

weston设置

weston设置 屏幕旋转180度方法修改标题栏位置启动配置文件 屏幕旋转180度方法 编辑 /etc/xdg/weston/weston.ini文件,增加如下语句 [output] nameDSI-1 transform180其中name为你的显示屏名称,可以通过如下命令来查看显示屏名称: card0-DS…

Weston 窗口管理(2)

窗口管理(2) 本文基于 weston 分支 10.0.2 进行描述. 五、概述 本文为窗口管理(1)的续章,更多站在开发者角度,以 weston 的代码实现讲解窗口管理(1)中所实现的部分业务场景. 六、数据结构 在窗口管理(1)中曾经描述过 weston 具体的分层逻辑,如下: 再进一步可以把 WESTON_LAY…

01-weston 简介

参考​​​​​​weston wiki Weston - Gentoo Wiki weston (1): Linux man pages – code.tools Weston-1.12.0 非常详尽,多图慎入:Wayland与Weston简介 - 云社区 - 腾讯云 什么是weston? Wayland是一套display server(Wayland compos…

disunity的使用

1. 下载并安装好jdk: 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 安装教程:http://jingyan.baidu.com/article/6dad5075d1dc40a123e36ea3.html 2.下载disunity: https://…

T-digest

目录 算法算法原理空间消耗及错误界限 示例T-digest的建立T-digest的查询 相关链接 上一篇博客中讲述了使用 R a n d o m Random Random算法进行 q u a n t i l e quantile quantile估算,详情可见Random,本博客将讲诉另外一个 q u a n t i l e quantile …

[反编译U3D]Decompile Unity Resources 修正

反编译unity project的资源文件,包括ios,android,pc等,仅供学习使用! 1.disunity Examples 1.1disunityGUI 1.1.2DiunityGUI 使用方法 2.unity3d decompiler 3.UnityAssetsExplorer 反编译unity project的资源文件&…

edit distance 理解

一直没有理解到inert i delete j 的意思。看看图就可以明白了。 对于那道面试题:http://www.careercup.com/question?id6287528252407808 k-palindrome. 最精妙的地方在于只考虑 k 长度以内的改变,这样就可以判断出来了。速度是O(k*n) 1. Definition o…

Tiny-DSOD: Lightweight Object Detection for Resource-Restricted Usages

Y uxi Li1 lyxok1sjtu.edu.cn Jiuwei Li2 jiuwei.liintel.com Weiyao Lin1 wylinsjtu.edu.cn Jianguo Li2 jianguo.liintel.com 1Shanghai Jiao Tong University , China 2Intel Lab China Abstract 近年来,随着深度学习的发展,目标检测技术取得了长足…

android density

为什么要引入dip —The reason for dip to exist is simple enough. Take for instance the T-Mobile G1. It has a pixel resolution of 320x480 pixels. Now image another device, with the same physical screen size, but more pixels, for instance 640x480. This devic…

手游游戏资源提取 (破解、AssetStudio、VGMToolbox、disunity、Il2CppDumper、 .NET Reflector)...

参考: 公主连结 游戏资源提取(解包)简明教程 Unity3D研究院之mac上从.ipa中提取unity3D游戏资源 吾爱破解:记一次unity3d data修改 GitHub:Il2CppDumper 想拿点知名IP的手游素材做点demo,然后搜了下如何能拿到app的素材资源 一 下…

DISN:Deep Implicit Surface Network for High-quality Single-view 3D Reconstruction

时间:2019年 作者:Weiyue Wang ,University of Southern California etc. Abstract: 1.DISN 通过预测基本符号距离场来从二维图像中生成高质量的细节丰富的三维网格; 2.DISN 在二维图像上预测每一个三维点的投影位置&#xff…

Dist

这道题只要找到我们距离的规律就行了&#xff0c;我们可以发现&#xff0c;当行数小于列数时,列数(列数-1)/k,否则&#xff0c;行数(行数-1)/k&#xff0c;没记算一次我们的距离就会增加1&#xff0c;应为行数一减你就往下了一个&#xff0c;所以这个要加1. #include<bits/…

unity3D 如何提取游戏资源 (反编译)+代码反编译【P.M.出品】

转自&#xff1a;https://blog.csdn.net/LANGZI7758521/article/details/52291564 首先感谢 雨松MOMO 的一篇帖子 教我们怎么提取 .ipa 中的游戏资源。教我们初步的破解unity3d资源的基本方法 附上原帖的链接&#xff1a;http://www.xuanyusong.com/archives/2584 下面我会从头…

Unity游戏资源逆向工具

Unity游戏资源逆向工具 https://www.cnblogs.com/kekec/p/12175547.html disunity是一款Java编写&#xff08;需安装jdk1.8&#xff0c;即Java8&#xff09;的解析Unity asset和asset bundle文件&#xff08;流式加载&#xff0c;支持热更新&#xff09;的命令行工具&#xf…

Distillation

蒸馏&#xff0c;把有杂质的东西变成纯度高的 知识从教师网络集成到学生网络&#xff0c;这个过程叫迁移&#xff0c;这么做的原因是终端的算力有限&#xff0c;需要高效率 有关嵌入式开发也有教程&#xff01;&#xff01; 问题的引入&#xff1a;标签有问题&#xff0c;马更…

Unity 提取资源 Disunity、Unity Studio

提取Unity3d资源&#xff0c;用过2个工具 Disunity https://github.com/ata4/disunityUnity Studio https://github.com/RaduMC/UnityStudio 解压XXX.apk.&#xff0c;如果能在XXXX\assets\bin\Data\Managed路径下找到UnityEngine.dll&#xff0c;则表明该游戏由Unity3d打包。…