[译]输入系统如何工作——键盘输入

本文是 How input works – Keyboard input 的翻译。

上一篇博文中,我[作者]解释了KWin中,输入设备是如何打开和处理的。在这篇博文中,我们将仔细关注下键盘设备和键盘事件。

键盘并不总是键盘

在Linux中,键盘是一个非常奇特的设备。你不会只有一个键盘,你肯定会有很多个。很多设备宣称自己是键盘,但是只支持一个键。比如,电源按钮或者带静音按钮、音量加减按钮的外置耳机。从输入系统的角度来看,这些设备也是键盘。

对于KWin,发现真正支持的键盘是很重要的。如果没有一个“真的”键盘连接(或者说开启),我们的虚拟键盘应该自动激活。比如,如果你从平板PC二合一设备上拔了键盘,它应该转换为平板模式,即有虚拟键盘的模式。如果连接上了键盘,虚拟键盘就不是主要的输入设备了。libinput提供了函数来检测键盘支持哪些键。我们使用这个功能来区分不同的键盘类型。

键盘事件

在这里,键盘是最简单的输入设备。libinput仅仅触发一个LIBINPUT_EVENT_KEYBOARD_KEY事件,并包含了被按下或者释放的键。KWin有一个专用线程,用来从libinput读取事件。所以这些事件现在仅仅是放在处理队列中,主线程同时也得到新事件通知。一旦主线程处理事件,事件就被转换成我们的输入重定向类。不管事件是通过哪种源头抵达,所有输入事件都会通过输入重定向。KWin不仅仅支持来自libinput的事件,并且支持嵌套会话(即KWin运行在X11之上,或者在另一个Wayland服务器之上),还有在集成测试中使用的模拟事件。这意味着一旦事件到达输入重定向,我们基本上就丢失了事件来自哪个设备这些信息。最近,我们扩展了内部API,可以在事件处理函数中包含设备源,这是可选的。可以在调试终端中使用,来显示哪些设备产生了哪些事件。

xkbcommon

现在,一个键的按下、释放事件到达了中心分发方法KeyboardInputRedirection::processKey。第一件也是重要的一件事就是在xbkcommon中更新键盘状态。xkbcommon被用将物理键为事件,转换过程根据键盘布局、键盘状态(比如激活的修饰符)来进行。比如:如果我按下了“y”键(键码是21)并且“Shift”键是按下的状态,在德语键盘布局下,就会创建“Z”按下的事件;但是在英语键盘布局下,它会是“Y”。

在KWin中,我们将所有需要的xkbcommon功能都封装到Xkb类中。这个类追踪活跃的键盘布局、执行键盘布局切换(当布局变换的时候展示OSD)。它知道上一次按键的符号,当前活跃的修饰符和快捷键相关的修饰符。

当xkb的状态更新的时候,我们也检查很多键盘状态变更。用户是不是激活了数字锁定?如果是这样,我们需要让键盘上的LED做对应的变化,所以我们的libinput代码能够更新物理键盘上LED的状态。修饰副是不是变掉了?如果是这样,我们要将新的修饰符集合通知给Wayland窗口。尽管实际上从key到符号的翻译发生在Wayland客户端,但刚刚讲的翻译过程也在Wayland服务端进行了。为什么KWin也要做这一层翻译呢?这是因为KWin也需要在很多地方使用键盘符号,比如在当前窗口中过滤按键,来实现全局快捷键。

调试终端中的键盘状态

Xkb状态更新功能也能够处理哪些只需要修饰符键就能触发的快捷键。实际上,在这儿处理是不对的,但我们的输入过滤代码没法保证能捕获到所有的输入事件。对于快捷键中的修饰符,看多所有的事件是很基础的需求。所以,唯一的处理地方只能在Xkb中了。这不是最优雅的解决方案,但是能工作。这个功能也被X11使用,我在之前的博文中讲过。

KWin的过滤

现在KWin有足够的信息来处理键盘事件。对于此,它创建自定义的QKeyEvent并将其送到输入过滤链。KWin的输入处理使用了输入过滤器组成的链。每个过滤器都能够对事件做一系列操作,并决定这个事件是不是应该被继续处理,或结束处理。

比如,我们有锁屏过滤器。如果屏幕是锁屏状态,这个过滤器就会过滤事件处理,确保事件只会被送到屏幕锁定程序,不会被其他窗口处理。或者这儿有一个过滤器,确保ctrl+alt+f1在锁屏情况下仍然能够工作。另一个过滤器用来处理全局快捷键,一个将事件传递给特效系统,比如窗口轮转。

在调试终端中,一个输入事件过滤器显示被按下的键

最后一个过滤器是我们的转发过滤器。这个过滤器的任务是转发事件到窗口。它将事件从当前活动的Wayland平面,传递到KWayland::Server。

获得键盘输入焦点的Wayland表面

Wayland服务器需要获取了键盘焦点的平面。在获取了键盘焦点的情况下,KWin相比而言微不足道。KWin有一个叫活动窗口的概念。在转发事件之前,KWin会检查哪个是键盘焦点窗口。如果有一个活动窗口,则该窗口平面被标记为KWayland::Server中的键盘焦点平面。

我们的KWayland::Server库关注发送丢失键盘焦点和获取键盘焦点事件到窗口,所以KWin不需要关注这些。这是我们有一个KWayland::Server抽象层的优势——和混成器无关的一切都在库中被处理了。

Wayland中键盘事件的处理

之前提到的转发过滤器更新键盘平面,并且将当前键盘事件发送到Wayland客户端。对于所有在keysymbol中的处理,都不需要了。key code已经送到了客户端。

客户端从回调中得到键盘事件,现在也将其送到xkbcommon。在Wayland中,keymap从服务端送到客户端,以便服务端和客户端有同样的keymap。客户端现在将key code转换成key symbol,和之前KWin做的一样。

接下来的事件处理在客户端完成。比如在QT中,这一步会产生QKeyEvent,然后送到当前输入焦点的widget。

重复输入键

键盘输入也有一些特殊的模式:重复键。当一些键被按下,产生重复的键输入。KWin使用来自键盘模块的配置来决定什么时候、什么频率来产生重复的按键。一个重复的键不会被转发到KWayland客户端。而是KWin通过Wayland键盘协议告诉键重复的设定,而不是被客户端直接处理。

不幸的是,QT中这个是不能工作的,使用的是硬编码。所以当前在Plasma Wayland的会话中,根据使用的GUI库不同,对重复键的支持很破碎。如果运行在Wayland上的话,KWin支持是正常的,X11程序是对的,GTK程序是对的,QT程序是错的。


如果你想支持我们[作者]的工作,请考虑捐助

[译]输入系统如何工作——创建设备

本文是How input works – creating a Device的翻译。

最近,我[作者]在KWin/Wayland输入栈上做了一些工作,比如实现了鼠标手势和鼠标限制协议(pointer constraints protocol),并且想写一些系列博客来描述输入事件是如何从设备传递到应用的。在第一篇博文中,我将关注于创建和配置输入设备,以及与此相关的其他事情。

evdev

Linux内核通过evdev API来产生输入事件。如果你对evdev如何工作感兴趣,我推荐你读一读Peter Hutterer写的优秀的博文。对于我们关注的层面来说,输入事件API太底层了,我们仅仅想用对它的一个抽象。

libinput 和设备文件

对输入事件API的抽象叫做libinput。它允许我们得到通知,不论何时添加、删除输入设备、不论何时产生输入事件。但是别急,我们首先需要打开输入设备,这是我们的第一个挑战。

正常情况下,设备文件不能被用户读取。这有好的一面,否则每个程序都能够读取所有的键盘事件。这种情况下,键盘记录器太容易实现了。

但是如果KWin以普通用户的方式运行,普通用户又无法读取设备文件,那KWin如何获取输入?为了让KWin获取输入,我们需要特殊的支持。libinput就是为这种情况准备的,它自己不会尝试打开文件,它会使用用户提供的open_restricted函数。KWin就是这么干的,并将打开文件的任务交给了logind。logind允许一个进程控制当前登录会话。并且这个登录会话的控制进程可以打开一些设备文件。所以KWin和logind的dbus API交互,成为登录会话的控制进程,通过logind的API打开设备文件,并将其传递回libinput。

这也是为什么对于整个Wayland会话,KWin在运行时依赖logind的DBus接口。请注意,这并不意味着你需要使用logind或者sysemd。这仅仅意味着需要一个进程来同logind的DBus接口通讯。

KWin中的设备

现在libinput已经准备好打开设备文件,并且为每个设备触发了LIBINPUT_EVENT_DEVICE_ADDED事件。KWin为每一种设备类型创建了一个小的门面类,来应用设备的配置。KWin支持读取Plasma的鼠标配置模块中的配置选项。并且KWin打开了LED灯,如果设备支持LED灯的话,比如数字锁定灯和大写锁定灯,这也是设备配置过程的一部分。

所有的输入设备都被KWin创建,并且可以在调试终端显示(打开KRunner,输入“KWin”)。KWin从libinput中读取了很多关于设备的信息,并展示在调试终端中。在输入事件选项卡中,每种事件都包含了设备产生该事件的一些信息。

所有的设备也通过DBus暴露出来,和KWin的调试终端信息一样。这意味着可以通过DBus来动态修改配置。不过,KWin在成功应用配置后,会将其保存,以确保你在重启系统、或者重新插拔外部设备后,你的设置能够被恢复。这是一个很重要的特性,用来支持触摸板配置模块。

如果你想支持作者的工作,考虑捐赠给作者,让世界变得更美好!——KDE 2016年年终募款

[译]什么是HiDPI?以及它为什么这么重要。

本文是What is HiDPI的翻译。

我是一名web开发者和用户体验设计师,使用System 76电脑、Ubuntu系统;也是elementary OS的联合创始人。elementary OS是一个开源的桌面操作系统。我和桌面、web、硬件开发者一起工作,来实现HiDPI支持。我注意到很多人很难理解HiDPI,因为对此没有一个全面的介绍。这是我尝试介绍HiDPI和去除一些常见误解的博文。

HiDPI显示器在计算机上变得越来越流行:苹果最新的MacBook、MacBook Pro和iMac;微软的Surface,Surface Book,和新的Surface Studio;戴尔,联想,惠普和其他厂商将HiDPI作为笔记本电脑的可选配置;LG,戴尔和飞利浦等的HiDPI桌面显示器;和System76(我的雇主)刚刚发布的旗舰Oryx Pro和Bonobo WS笔记本电脑也支持了HiDPI。

由于价格,图形性能需求和功耗的增加,HiDPI不是默认配置,但我们肯定会朝这个方向发展的。那么,HiDPI解决了什么问题呢?

像素数翻倍

HiDPI的核心是像素数量加倍:每个维度中的物理像素数量是所需的虚拟像素数的两倍。

例如,图标或图像的高度是64虚拟像素,但是在HiDPI显示器上,它用128个物理像素绘制(总共是4倍的像素——在每个方向上是原来的两倍)。这使得图标在任何角度都变得两倍清晰,或者说容纳了了两倍的细节。

普通显示和HiDPI。4倍的像素数量。HiDPI允许更精细的形状和更好的抗锯齿。

对于用户界面,这意味着它们比原来的一大堆像素集更加清晰、完美。对于照片,HiDPI使它们看起来更像一张打印的照片,而不仅仅是数字图像。对于文本,HiDPi使它看起来更像一个实体的杂志,而不仅仅是电脑屏幕。对于视频,HiDPI允许更多的细节和沉浸体验:屏幕渐渐消失,成为电影故事的一个窗口。

半个像素是不存在的

那为什么是像素数加倍,而不仅仅是增加15寸显示器的像素密度呢?比如,1080p提升到2880×1620?为了让用户界面的元素具有同样的物理尺寸,在1080p的显示器上,你必须把显示内容缩放到1.5倍。这意味着一个虚拟像素点需要1.5个物理像素点来绘制。

半个像素是不存在的,所以软件必须抵消锯齿。锯齿=模糊。所以随着高分辨率的显示器,你会得到一个模糊的UI。和1倍的显示比率相比,在1.5倍的显示比率下,字体有对应的处理机制,所以显示比率不是一个大问题,但是UI元素,比如图标和按钮周围的描边看起来会非常糟糕。

1像素点的1,2,1.5倍缩放。在1倍和2倍缩放下,点看起来是一样的。在1.5倍缩放下,软件必须处理锯齿,创建一个模糊的边界。

有人认为像素足够小,以至于锯齿/模糊不是很明显。对于某些大小/分辨率的组合来说,这是可能的。但如果是这种情况,在同样的物理尺寸下,1.5倍并不比1倍好,你只是通过处理更多的像素来浪费性能和电量。

* 有些人(比如Linus Torvalds)认为这是“疯狂的”,4倍的分辨率就是4倍的价格,却只带来了微小,不可读的字体和图标。软件开发者有自己的意见,但对于大多数消费者来说,这会使设备完全无法使用。仅仅有少数的技术人员可以通过手动设置缩放因子来解决这个问题。

4K?Quad HD?5K?UHD?Retina?HiDPI?

HiDPI是一个好主意,但很难和客户解释清楚(一些制造商甚至没有从中获得好处,见下一节)。因此,工业上已经提出了几个不同的流行语,努力向客户解释这些,这些解释获得了不同程度的成功。

Retina

可以说,最有效的解释来自苹果和他们的Retina品牌。他们将Retina描述为,在正常观看距离处,该像素密度使人类视网膜不能辨别出来单个像素。这是对的,但也有点市场营销的意思。 对于苹果,Retina似乎只是意味着像素倍增。

当他们发布第一个Retina显示器,它有4倍像素(每个维度2倍)。这避免了旧软件在新显示器上的模糊(它们在新显示器上看起来和原来相同,不会更好但也不会更糟),并且这使得设计者/开发者更加容易设计新的图形界面。

苹果的每个Retina品牌的显示器都遵循这个约定;它们都只是旧显示器的像素翻倍,并在软件中设置为2倍缩放。

4K,Quad HD,5K和UHD

从技术来讲,4K、Quad HD、5K和UHD与像素密度和HiDPI完全没有关系。然而,由于它们是用于销售投影机和电视的术语,计算机制造商喜欢使用这些术语来对它们的普通显示器进行加售。

不要过多关注这些营销术语;相反,看看分辨率在显示器上是否有意义。如果分辨率将每个维度缩放到两倍,那就足够高。如果这个分辨率没法达到这个比率,那就没有意义,不要买。因为制造商做出了一个糟糕的决定:设备需要一半或分数个像素才可以开箱即用。

一般来说:Quad HD或者1440p(2560×1440)在两倍缩放下和720p是一样的大小;4K(3840×2160)在两倍缩放下和1080p是一样的;5K(5120×2880)在两倍缩放下和1440p是一样的;UHD没法通过这种像素除以2来对应到现有的尺寸。和物理尺寸一起来看的话,14到24寸显示器的分辨率一般是1080p,所以4K是同样尺寸下的HiDPI版本。24到30寸的显示器的分辨率是1440p,所以5K是其HiDPI版本。在更小的显示器上(11到13寸),1600×900是原生的分辨率,所以HiDPI版本是3200×1800(联想和戴尔的13寸HiDPI显示器就是这个分辨率)。

HiDPI

在桌面Linux世界(在Windows世界也是如此),HiDPI表示像素倍增或者“Retina”,HiDPI是一个厂商无关的术语。很多设备生产商避免使用这些术语(System76使用这些术语!),但是软件开发者倾向于了解并使用它。如果使用得当的话,我希望HiDPI成为一个工业标准。

一些厂商在分辨率上作出了错误的选择

分辨率不是越高越好。事实上,一些厂商为了能够从低分辨率的显示器上拿到加售,他们采用了4K的变种,而没有考虑到物理尺寸和像素倍增怎么工作。

在15寸的显示器上,1080p(1920×1080)在1倍缩放的情况下,显示效果不错,也没有字体或者图标变得太小的情况。1080p经过像素倍增后是4K(3840×2160),所以4K在这个物理尺寸上的显示也不错:所有的元素经过缩放,都和原来一样大。但是,在更小的显示器上,比如12寸或者13寸,1080p在1倍缩放下就太密了(这意味着UI看起来太小了)。所以4K在12寸或者13寸的物理尺寸上比3200×1800(1600×900像素倍增后的结果)差。

有人问elementary OS是否会支持非整数的缩放因子,来帮助那些买了不好的大小/分辨率组合的显示器的用户。但是因为半个像素是不存在的,我们没法设置非整数的缩放。设备生产商作出了错误的决策、销售了差的产品。对此,我们做不了太多。

总结

  • HiDPI 就是每个维度上的像素增加了一倍。
  • 半个像素是不存在的
  • 4K 不一定是 HiDPI,并且它不一定是最好的分辨率
  • 一些生产商在分辨率上作出了错误的选择

如果这篇文章帮到了你,或者你有自己的想法,请给我发twitter或者在这儿评论。

Fedora上完美的使用QQ

目前看下来,Linux使用QQ还是Deepin比较好。

CrossOver上的QQ目前不能记住密码,其他还好,比如聊天啥的也是可以的。

Deepin的QQ是目前最好的解决方案。

安装如下:

  • 首先,从百度网盘下载crossover-15_15.0.3-1_all-free.deb 。解压其中的opt/cxoffice/ 到/opt/cxoffice/
  • 其次,从镜像站点下载Deepin的QQ,apps.com.qq.im_8.1.17255deepin11_i386.deb
  • 解压apps.com.qq.im_8.1.17255deepin11_i386.deb 中的opt/cxoffice/support/apps.com.qq.im 到/opt/cxoffice/support/apps.com.qq.im
  • 然后执行/opt/cxoffice/bin/crossover
  • 在CrossOver点击QQ启动即可。

Continue reading Fedora上完美的使用QQ

Fedora KDE 25下安装fcitx输入法

首先,安装fcitx之后,只要是接受了GTK_IM_MODULE 、QT_IM_MODULE 、XMODIFIERS 环境变量的程序,都可以使用fcitx输入法了。

但是,即使我在~/.xprofile 里面写了这三个export语句,程序也没法读到这三个环境变量。

后来发现,这里面有两个坑:

  1. Fedora KDE的display manager换成了SDDM,而在SDDM的配置文件中,默认不会执行~/.xprofile 里面的语句。
  2. SDDM问题解决后,发现fcitx依赖的imsettings,会设置这三个变量,所以在~/.xprofile 里面export的变量,其实会被imsettings覆盖。

Continue reading Fedora KDE 25下安装fcitx输入法