标签 键盘 下的文章

用 AutoKey 配置你的键盘,纠正常见的错别字,输入常用的短语等等。

 title=

AutoKey 是一个开源的 Linux 桌面自动化工具,一旦它成为你工作流程的一部分,你就会想,如何没有它,那该怎么办。它可以成为一种提高生产率的变革性工具,或者仅仅是减少与打字有关的身体压力的一种方式。

本文将研究如何安装和开始使用 AutoKey ,介绍一些可以立即在工作流程中使用的简单方法,并探讨 AutoKey 高级用户可能会感兴趣的一些高级功能。

安装并设置 AutoKey

AutoKey 在许多 Linux 发行版中都是现成的软件包。该项目的 安装指南 包含许多平台的说明,也包括了从源代码进行构建的指导。本文使用 Fedora 作为操作平台。

AutoKey 有两个变体:为像 GNOME 等基于 GTK 环境而设计的 autokey-gtk 和基于 QT 的 autokey-qt。

你可以从命令行安装任一变体:

sudo dnf install autokey-gtk

安装完成后,使用 autokey-gtk(或 autokey-qt)运行它。

探究界面

在将 AutoKey 设置为在后台运行并自动执行操作之前,你首先需要对其进行配置。调出用户界面(UI)配置:

autokey-gtk -c

AutoKey 提供了一些预设配置的示例。你可能希望在熟悉 UI 时将他们留作备用,但是可以根据需要删除它们。

 title=

左侧窗格包含一个文件夹式的短语和脚本的层次结构。“ 短语 Phrases ” 代表要让 AutoKey 输入的文本。“ 脚本 Scripts ” 是动态的、程序化的等效项,可以使用 Python 编写,并且获得与键盘击键发送到活动窗口基本相同的结果。

右侧窗格构建和配置短语和脚本。

对配置满意后,你可能希望在登录时自动运行 AutoKey,这样就不必每次都启动它。你可以通过在 “ 首选项 Preferences ”菜单(“ 编辑 -> 首选项 Edit -> Preferences” ”)中勾选 “ 登录时自动启动 AutoKey Automatically start AutoKey at login ”进行配置。

 title=

使用 AutoKey 纠正常见的打字排版错误

修复常见的打字排版错误对于 AutoKey 来说是一个容易解决的问题。例如,我始终键入 “gerp” 来代替 “grep”。这里是如何配置 AutoKey 为你解决这些类型问题。

创建一个新的子文件夹,可以在其中将所有“打字排版错误校正”配置分组。在左侧窗格中选择 “My Phrases” ,然后选择 “ 文件 -> 新建 -> 子文件夹 File -> New -> Subfolder ”。将子文件夹命名为 “Typos”。

在 “ 文件 -> 新建 -> 短语 File -> New -> Phrase ” 中创建一个新短语。并将其称为 “grep”。

通过高亮选择短语 “grep”,然后在 输入短语内容 Enter phrase contents 部分(替换默认的 “Enter phrase contents” 文本)中输入 “grep” ,配置 AutoKey 插入正确的关键词。

接下来,通过定义缩写来设置 AutoKey 如何触发此短语。点击用户界面底部紧邻 “ 缩写 Abbreviations ” 的 “ 设置 Set ”按钮。

在弹出的对话框中,单击 “ 添加 Add ” 按钮,然后将 “gerp” 添加为新的缩写。勾选 “ 删除键入的缩写 Remove typed abbreviation ”;此选项让 AutoKey 将任何键入 “gerp” 一词的替换为 “grep”。请不要勾选“ 在键入单词的一部分时触发 Trigger when typed as part of a word ”,这样,如果你键入包含 “grep”的单词(例如 “fingerprint”),就不会尝试将其转换为 “fingreprint”。仅当将 “grep” 作为独立的单词键入时,此功能才有效。

 title=

限制对特定应用程序的更正

你可能希望仅在某些应用程序(例如终端窗口)中打字排版错误时才应用校正。你可以通过设置 窗口过滤器 Window Filter 进行配置。单击 “ 设置 Set ” 按钮来定义。

设置 窗口过滤器 Window Filter 的最简单方法是让 AutoKey 为你检测窗口类型:

  1. 启动一个新的终端窗口。
  2. 返回 AutoKey,单击 “ 检测窗口属性 Detect Window Properties ”按钮。
  3. 单击终端窗口。

这将自动填充窗口过滤器,可能的窗口类值为 gnome-terminal-server.Gnome-terminal。这足够了,因此单击 “OK”。

 title=

保存并测试

对新配置满意后,请确保将其保存。 单击 “ 文件 File ” ,然后选择 “ 保存 Save ” 以使更改生效。

现在进行重要的测试!在你的终端窗口中,键入 “gerp” 紧跟一个空格,它将自动更正为 “grep”。要验证窗口过滤器是否正在运行,请尝试在浏览器 URL 栏或其他应用程序中键入单词 “gerp”。它并没有变化。

你可能会认为,使用 shell 别名 可以轻松解决此问题,我完全赞成!与别名不同,只要是面向命令行,无论你使用什么应用程序,AutoKey 都可以按规则纠正错误。

例如,我在浏览器,集成开发环境和终端中输入的另一个常见打字错误 “openshfit” 替代为 “openshift”。别名不能完全解决此问题,而 AutoKey 可以在任何情况下纠正它。

键入常用短语

你可以通过许多其他方法来调用 AutoKey 的短语来帮助你。例如,作为从事 OpenShift 的站点可靠性工程师(SRE),我经常在命令行上输入 Kubernetes 命名空间名称:

oc get pods -n openshift-managed-upgrade-operator

这些名称空间是静态的,因此它们是键入特定命令时 AutoKey 可以为我插入的理想短语。

为此,我创建了一个名为 “Namespaces” 的短语子文件夹,并为我经常键入的每个命名空间添加了一个短语条目。

分配热键

接下来,也是最关键的一点,我为子文件夹分配了一个 “ 热键 hotkey ”。每当我按下该热键时,它都会打开一个菜单,我可以在其中选择(要么使用 “方向键”+回车键要么使用数字)要插入的短语。这减少了我仅需几次击键就可以输入这些命令的击键次数。

“My Phrases” 文件夹中 AutoKey 的预配置示例使用 Ctrl+F7 热键进行配置。如果你将示例保留在 AutoKey 的默认配置中,请尝试一下。你应该在此处看到所有可用短语的菜单。使用数字或箭头键选择所需的项目。

高级自动键入

AutoKey 的 脚本引擎 允许用户运行可以通过相同的缩写和热键系统调用的 Python 脚本。这些脚本可以通过支持的 API 的函数来完成诸如切换窗口、发送按键或执行鼠标单击之类的操作。

AutoKey 用户非常欢迎这项功能,发布了自定义脚本供其他用户采用。例如,NumpadIME 脚本 将数字键盘转换为旧的手机样式的文本输入方法,Emojis-AutoKey 可以通过将诸如: :smile: 之类的短语转换为它们等价的表情符号来轻松插入。

这是我设置的一个小脚本,该脚本进入 Tmux 的复制模式,以将前一行中的第一个单词复制到粘贴缓冲区中:

from time import sleep

# 发送 Tmux 命令前缀(b 更改为 s)
keyboard.send_keys("<ctr>+s")
# Enter copy mode
keyboard.send_key("[")
sleep(0.01)
# Move cursor up one line
keyboard.send_keys("k")
sleep(0.01)
# Move cursor to start of line
keyboard.send_keys("0")
sleep(0.01)
# Start mark
keyboard.send_keys(" ")
sleep(0.01)
# Move cursor to end of word
keyboard.send_keys("e")
sleep(0.01)
# Add to copy buffer
keyboard.send_keys("<ctrl>+m")

之所以有 sleep 函数,是因为 Tmux 有时无法跟上 AutoKey 发送击键的速度,并且它们对整体执行时间的影响可忽略不计。

使用 AutoKey 自动化

我希望你喜欢这篇使用 AutoKey 进行键盘自动化的探索,它为你提供了有关如何改善工作流程的一些好主意。如果你在使用 AutoKey 时有什么有用的或新颖的方法,一定要在下面的评论中分享。


via: https://opensource.com/article/21/2/linux-autokey

作者:Matt Bargenquast 选题:lujun9972 译者:stevenzdg988 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

欢迎进入输入课程系列。在本系列,你将会学会如何使用键盘接收输入给树莓派。我们将会从揭示输入开始本课,然后转向更传统的文本提示符。

这是第一堂输入课,会教授一些关于驱动和链接的理论,同样也包含键盘的知识,最后以在屏幕上显示文本结束。

1、开始

希望你已经完成了 OK 系列课程,这会对你完成屏幕系列课程很有帮助。很多 OK 课程上的文件会被使用而不会做解释。如果你没有这些文件,或者希望使用一个正确的实现,可以从该堂课的下载页下载模板。如果你使用你自己的实现,请删除调用了 SetGraphicsAddress 之后全部的代码。

2、USB

如你所知,树莓派 B 型有两个 USB 接口,通常用来连接一个鼠标和一个键盘。这是一个非常好的设计决策,USB 是一个非常通用的接口,很多种设备都可以使用它。这就很容易为它设计新外设,很容易为它编写设备驱动,而且通过 USB 集线器可以非常容易扩展。还能更好吗?当然是不能,实际上对一个操作系统开发者来说,这就是我们的噩梦。USB 标准太大了。我是说真的,在你思考如何连接设备之前,它的文档将近 700 页。

USB 标准的设计目的是通过复杂的软件来简化硬件交互。

我和很多爱好操作系统的开发者谈过这些,而他们全部都说几句话:不要抱怨。“实现这个需要花费很久时间”,“你不可能写出关于 USB 的教程”,“收益太小了”。在很多方面,他们是对的,我不可能写出一个关于 USB 标准的教程,那得花费几周时间。我同样不能教授如何为全部所有的设备编写外设驱动,所以使用自己写的驱动是没什么用的。然而,即便不能做到最好,我仍然可以获取一个正常工作的 USB 驱动,拿一个键盘驱动,然后教授如何在操作系统中使用它们。我开始寻找可以运行在一个甚至不知道文件是什么的操作系统的自由驱动,但是我一个都找不到,它们都太高层了,所以我尝试写一个。大家说的都对,这耗费了我几周时间。然而我可以高兴的说我做的这些工作没有获取操作系统以外的帮助,并且可以和鼠标和键盘通信。这绝不是完整的、高效的,或者正确的,但是它能工作。驱动是以 C 编写的,而且有兴趣的可以在下载页找到全部源代码。

所以,这一个教程不会是 USB 标准的课程(一点也没有)。实际上我们将会看到如何使用其他人的代码。

3、链接

既然我们要引进外部代码到操作系统,我们就需要谈一谈 链接 linking 。链接是一种过程,可以在程序或者操作系统中链接函数。这意味着当一个程序生成之后,我们不必要编写每一个函数(几乎可以肯定,实际上并非如此)。链接就是我们做的用来把我们程序和别人代码中的函数连结在一起。这个实际上已经在我们的操作系统进行了,因为链接器把所有不同的文件链接在一起,每个都是分开编译的。

链接允许我们制作可重用的代码库,所有人都可以在他们的程序中使用。

有两种链接方式:静态和动态。静态链接就像我们在制作自己的操作系统时进行的。链接器找到全部函数的地址,然后在链接结束前,将这些地址都写入代码中。动态链接是在程序“完成”之后。当程序加载后,动态链接器检查程序,然后在操作系统的库找到所有不在程序里的函数。这就是我们的操作系统最终应该能够完成的一项工作,但是现在所有东西都将是静态链接的。

程序经常调用调用库,这些库会调用其它的库,直到最终调用了我们写的操作系统的库。

我编写的 USB 驱动程序适合静态编译。这意味着我给你的是每个文件的编译后的代码,然后链接器找到你的代码中的那些没有实现的函数,就将这些函数链接到我的代码。在本课的 下载页 是一个 makefile 和我的 USB 驱动,这是接下来需要的。下载并使用这个 makefile 替换你的代码中的 makefile, 同事将驱动放在和这个 makefile 相同的文件夹。

4、键盘

为了将输入传给我们的操作系统,我们需要在某种程度上理解键盘是如何实际工作的。键盘有两种按键:普通键和修饰键。普通按键是字母、数字、功能键,等等。它们构成了键盘上几乎全部按键。修饰键是多达 8 个的特殊键。它们是左 shift、右 shift、左 ctrl、右 ctrl、左 alt、右 alt、左 GUI 和右 GUI。键盘可以检测出所有的组合中那个修饰键被按下了,以及最多 6 个普通键。每次一个按钮变化了(例如,是按下了还是释放了),键盘就会报告给电脑。通常,键盘也会有 3 个 LED 灯,分别指示大写锁定,数字键锁定,和滚动锁定,这些都是由电脑控制的,而不是键盘自己。键盘也可能有更多的灯,比如电源、静音,等等。

对于标准 USB 键盘,有一个按键值的表,每个键盘按键都一个唯一的数字,每个可能的 LED 也类似。下面的表格列出了前 126 个值。

表 4.1 USB 键盘值

序号描述序号描述序号描述序号描述
4aA5bB6cC7dD
8eE9fF10gG11hH
12iI13jJ14kK15lL
16mM17nN18oO19pP
20qQ21rR22sS23tT
24uU25vV26wW27xX
28yY29zZ301!312@
323#334$345%356^
367&378*389(390)
40ReturnEnter41Escape42DeleteBackspace43Tab
44Spacebar45-_46=+47[{
48]}49\ 和 ``50#~51;:
52'"53`~54,<55.>
56/?57Caps Lock58F159F2
60F361F462F563F6
64F765F866F967F10
68F1169F1270Print Screen71Scroll Lock
72Pause73Insert74Home75Page Up
76Delete forward77End78Page Down79Right Arrow
80Left Arrow81Down Arrow82Up Arrow83Num Lock
84小键盘 /85小键盘 *86小键盘 -87小键盘 +
88小键盘 Enter89小键盘 1End90小键盘 2Down Arrow91小键盘 3Page Down
92小键盘 4Left Arrow93小键盘 594小键盘 6Right Arrow95小键盘 7Home
96小键盘 8Up Arrow97小键盘 9Page Up98小键盘 0Insert99小键盘 .Delete
100\ 和 ``101Application102Power103小键盘 =
104F13105F14106F15107F16
108F17109F18110F19111F20
112F21113F22114F23115F24
116Execute117Help118Menu119Select
120Stop121Again122Undo123Cut
124Copy125Paste126Find127Mute
128Volume Up129Volume Down

完全列表可以在HID 页表 1.12的 53 页,第 10 节找到。

5、车轮后的螺母

通常,当你使用其他人的代码,他们会提供一份自己代码的总结,描述代码都做了什么,粗略介绍了是如何工作的,以及什么情况下会出错。下面是一个使用我的 USB 驱动的相关步骤要求。

这些总结和代码的描述组成了一个 API - 应用程序产品接口。

表 5.1 CSUD 中和键盘相关的函数

函数参数返回值描述
UsbInitialiser0 是结果码这个方法是一个集多种功能于一身的方法,它加载 USB 驱动程序,枚举所有设备并尝试与它们通信。这种方法通常需要大约一秒钟的时间来执行,但是如果插入几个 USB 集线器,执行时间会明显更长。在此方法完成之后,键盘驱动程序中的方法就可用了,不管是否确实插入了键盘。返回代码如下解释。
UsbCheckForChange本质上提供与 UsbInitialise 相同的效果,但不提供相同的一次初始化。该方法递归地检查每个连接的集线器上的每个端口,如果已经添加了新设备,则添加它们。如果没有更改,这应该是非常快的,但是如果连接了多个设备的集线器,则可能需要几秒钟的时间。
KeyboardCountr0 是计数返回当前连接并检测到的键盘数量。UsbCheckForChange 可能会对此进行更新。默认情况下最多支持 4 个键盘。可以通过这个驱动程序访问多达这么多的键盘。
KeyboardGetAddressr0 是索引r0 是地址检索给定键盘的地址。所有其他函数都需要一个键盘地址,以便知道要访问哪个键盘。因此,要与键盘通信,首先要检查计数,然后检索地址,然后使用其他方法。注意,在调用 UsbCheckForChange 之后,此方法返回的键盘顺序可能会改变。
KeyboardPollr0 是地址r0 是结果码从键盘读取当前键状态。这是通过直接轮询设备来操作的,与最佳实践相反。这意味着,如果没有频繁地调用此方法,可能会错过一个按键。所有读取方法只返回上次轮询时的值。
KeyboardGetModifiersr0 是地址r0 是修饰键状态检索上次轮询时修饰键的状态。这是两边的 shift 键、alt 键和 GUI 键。这回作为一个位字段返回,这样,位 0 中的 1 表示左控件被保留,位 1 表示左 shift,位 2 表示左 alt ,位 3 表示左 GUI,位 4 到 7 表示前面几个键的右版本。如果有问题,r0 包含 0。
KeyboardGetKeyDownCountr0 是地址r0 是计数检索当前按下键盘的键数。这排除了修饰键。这通常不能超过 6。如果有错误,这个方法返回 0。
KeyboardGetKeyDownr0 是地址,r1 键号r0 是扫描码检索特定按下键的扫描码(见表 4.1)。通常,要计算出哪些键是按下的,可以调用 KeyboardGetKeyDownCount,然后多次调用 KeyboardGetKeyDown ,将 r1 的值递增,以确定哪些键是按下的。如果有问题,返回 0。可以(但不建议这样做)在不调用 KeyboardGetKeyDownCount 的情况下调用此方法将 0 解释为没有按下的键。注意,顺序或扫描代码可以随机更改(有些键盘按数字排序,有些键盘按时间排序,没有任何保证)。
KeyboardGetKeyIsDownr0 是地址,r1 扫描码r0 是状态除了 KeyboardGetKeyDown 之外,还可以检查按下的键中是否有特定的扫描码。如果没有,返回 0;如果有,返回一个非零值。当检测特定的扫描码(例如寻找 ctrl+c)时更快。出错时,返回 0。
KeyboardGetLedSupportr0 是地址r0 是 LED检查特定键盘支持哪些 LED。第 0 位代表数字锁定,第 1 位代表大写锁定,第 2 位代表滚动锁定,第 3 位代表合成,第 4 位代表假名,第 5 位代表电源,第 6 位代表 Shift ,第 7 位代表静音。根据 USB 标准,这些 LED 都不是自动更新的(例如,当检测到大写锁定扫描代码时,必须手动设置大写锁定 LED)。
KeyboardSetLedsr0 是地址, r1 是 LEDr0 是结果码试图打开/关闭键盘上指定的 LED 灯。查看下面的结果代码值。参见 KeyboardGetLedSupport 获取 LED 的值。

有几种方法返回“返回值”。这些都是 C 代码的老生常谈了,就是用数字代表函数调用发生了什么。通常情况, 0 总是代表操作成功。下面的是驱动用到的返回值。

返回值是一种处理错误的简单方法,但是通常更优雅的解决途径会出现于更高层次的代码。

表 5.2 - CSUD 返回值

代码描述
0方法成功完成。
-2参数:函数调用了无效参数。
-4设备:设备没有正确响应请求。
-5不匹配:驱动不适用于这个请求或者设备。
-6编译器:驱动没有正确编译,或者被破坏了。
-7内存:驱动用尽了内存。
-8超时:设备没有在预期的时间内响应请求。
-9断开连接:被请求的设备断开连接,或者不能使用。

驱动的通常用法如下:

  1. 调用 UsbInitialise
  2. 调用 UsbCheckForChange
  3. 调用 KeyboardCount
  4. 如果返回 0,重复步骤 2。
  5. 针对你支持的每个键盘:

    1. 调用 KeyboardGetAddress
    2. 调用 KeybordGetKeyDownCount
    3. 针对每个按下的按键:

      1. 检查它是否已经被按下了
      2. 保存按下的按键
    4. 针对每个保存的按键:

      1. 检查按键是否被释放了
      2. 如果释放了就删除
  6. 根据按下/释放的案件执行操作
  7. 重复步骤 2

最后,你可以对键盘做所有你想做的任何事了,而这些方法应该允许你访问键盘的全部功能。在接下来的两节课,我们将会着眼于完成文本终端的输入部分,类似于大部分的命令行电脑,以及命令的解释。为了做这些,我们将需要在更有用的形式下得到一个键盘输入。你可能注意到我的驱动是(故意的)没有太大帮助,因为它并没有方法来判断是否一个按键刚刚按下或释放了,它只有方法来判断当前那个按键是按下的。这就意味着我们需要自己编写这些方法。

6、可用更新

首先,让我们实现一个 KeyboardUpdate 方法,检查第一个键盘,并使用轮询方法来获取当前的输入,以及保存最后一个输入来对比。然后我们可以使用这个数据和其它方法来将扫描码转换成按键。这个方法应该按照下面的说明准确操作:

重复检查更新被称为“轮询”。这是针对驱动 IO 中断而言的,这种情况下设备在准备好后会发一个信号。
  1. 提取一个保存好的键盘地址(初始值为 0)。
  2. 如果不是 0 ,进入步骤 9.
  3. 调用 UsbCheckForChange 检测新键盘。
  4. 调用 KeyboardCount 检测有几个键盘在线。
  5. 如果返回 0,意味着没有键盘可以让我们操作,只能退出了。
  6. 调用 KeyboardGetAddress 参数是 0,获取第一个键盘的地址。
  7. 保存这个地址。
  8. 如果这个值是 0,那么退出,这里应该有些问题。
  9. 调用 KeyboardGetKeyDown 6 次,获取每次按键按下的值并保存。
  10. 调用 KeyboardPoll
  11. 如果返回值非 0,进入步骤 3。这里应该有些问题(比如键盘断开连接)。

要保存上面提到的值,我们将需要下面 .data 段的值。

.section .data
.align 2
KeyboardAddress:
.int 0
KeyboardOldDown:
.rept 6
.hword 0
.endr
.hword num 直接将半字的常数插入文件。
.rept num [commands] .endr 复制 `commands` 命令到输出 num 次。

试着自己实现这个方法。对此,我的实现如下:

1、我们加载键盘的地址。

.section .text
.globl KeyboardUpdate
KeyboardUpdate:
push {r4,r5,lr}

kbd .req r4
ldr r0,=KeyboardAddress
ldr kbd,[r0]

2、如果地址非 0,就说明我们有一个键盘。调用 UsbCheckForChanges 慢,所以如果一切正常,我们要避免调用这个函数。

teq kbd,#0
bne haveKeyboard$

3、如果我们一个键盘都没有,我们就必须检查新设备。

getKeyboard$:
bl UsbCheckForChange

4、如果有新键盘添加,我们就会看到这个。

bl KeyboardCount

5、如果没有键盘,我们就没有键盘地址。

teq r0,#0
ldreq r1,=KeyboardAddress
streq r0,[r1]
beq return$

6、让我们获取第一个键盘的地址。你可能想要支持更多键盘。

mov r0,#0
bl KeyboardGetAddress

7、保存键盘地址。

ldr r1,=KeyboardAddress
str r0,[r1]

8、如果我们没有键盘地址,这里就没有其它活要做了。

teq r0,#0
beq return$
mov kbd,r0

9、循环查询全部按键,在 KeyboardOldDown 保存下来。如果我们询问的太多了,返回 0 也是正确的。

saveKeys$:
  mov r0,kbd
  mov r1,r5
  bl KeyboardGetKeyDown
  
  ldr r1,=KeyboardOldDown
  add r1,r5,lsl #1
  strh r0,[r1]
  add r5,#1
  cmp r5,#6
  blt saveKeys$

10、现在我们得到了新的按键。

mov r0,kbd
bl KeyboardPoll

11、最后我们要检查 KeyboardOldDown 是否工作了。如果没工作,那么我们可能是断开连接了。

teq r0,#0
bne getKeyboard$

return$:
pop {r4,r5,pc}
.unreq kbd

有了我们新的 KeyboardUpdate 方法,检查输入变得简单,固定周期调用这个方法就行,而它甚至可以检查键盘是否断开连接,等等。这是一个有用的方法,因为我们实际的按键处理会根据条件不同而有所差别,所以能够用一个函数调以它的原始方式获取当前的输入是可行的。下一个方法我们希望它是 KeyboardGetChar,简单的返回下一个按下的按钮的 ASCII 字符,或者如果没有按键按下就返回 0。这可以扩展到支持如果它按下一个特定时间当做多次按下按键,也支持锁定键和修饰键。

如果我们有一个 KeyWasDown 方法可以使这个方法有用起来,如果给定的扫描代码不在 KeyboardOldDown 值中,它只返回 0,否则返回一个非零值。你可以自己尝试一下。与往常一样,可以在下载页面找到解决方案。

7、查找表

KeyboardGetChar 方法如果写得不好,可能会非常复杂。有 100 多种扫描码,每种代码都有不同的效果,这取决于 shift 键或其他修饰符的存在与否。并不是所有的键都可以转换成一个字符。对于一些字符,多个键可以生成相同的字符。在有如此多可能性的情况下,一个有用的技巧是查找表。查找表与物理意义上的查找表非常相似,它是一个值及其结果的表。对于一些有限的函数,推导出答案的最简单方法就是预先计算每个答案,然后通过检索返回正确的答案。在这种情况下,我们可以在内存中建立一个序列的值,序列中第 n 个值就是扫描代码 n 的 ASCII 字符代码。这意味着如果一个键被按下,我们的方法只需要检测到,然后从表中检索它的值。此外,我们可以为当按住 shift 键时的值单独创建一个表,这样按下 shift 键就可以简单地换个我们用的表。

在编程的许多领域,程序越大,速度越快。查找表很大,但是速度很快。有些问题可以通过查找表和普通函数的组合来解决。

.section .data 命令之后,复制下面的表:

.align 3
KeysNormal:
    .byte 0x0, 0x0, 0x0, 0x0, 'a', 'b', 'c', 'd'
    .byte 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'
    .byte 'm', 'n', 'o', 'p', 'q', 'r', 's', 't'
    .byte 'u', 'v', 'w', 'x', 'y', 'z', '1', '2'
    .byte '3', '4', '5', '6', '7', '8', '9', '0'
    .byte '\n', 0x0, '\b', '\t', ' ', '-', '=', '['
    .byte ']', '\\\', '#', ';', '\'', '`', ',', '.'
    .byte '/', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, '/', '*', '-', '+'
    .byte '\n', '1', '2', '3', '4', '5', '6', '7'
    .byte '8', '9', '0', '.', '\\\', 0x0, 0x0, '='

.align 3
KeysShift:
    .byte 0x0, 0x0, 0x0, 0x0, 'A', 'B', 'C', 'D'
    .byte 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L'
    .byte 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'
    .byte 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '"'
    .byte '£', '$', '%', '^', '&', '*', '(', ')'
    .byte '\n', 0x0, '\b', '\t', ' ', '_', '+', '{'
    .byte '}', '|', '~', ':', '@', '¬', '<', '>'
    .byte '?', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, '/', '*', '-', '+'
    .byte '\n', '1', '2', '3', '4', '5', '6', '7'
    .byte '8', '9', '0', '.', '|', 0x0, 0x0, '='

这些表直接将前 104 个扫描码映射到 ASCII 字符作为一个字节表。我们还有一个单独的表来描述 shift 键对这些扫描码的影响。我使用 ASCII null 字符(0)表示所有没有直接映射的 ASCII 键(例如功能键)。退格映射到 ASCII 退格字符(8 表示 \b),enter 映射到 ASCII 新行字符(10 表示 \n), tab 映射到 ASCII 水平制表符(9 表示 \t)。

.byte num 直接插入字节常量 num 到文件。

.

大部分的汇编器和编译器识别转义序列;如 \t 这样的字符序列会插入该特殊字符。

KeyboardGetChar 方法需要做以下工作:

  1. 检查 KeyboardAddress 是否返回 0。如果是,则返回 0。
  2. 调用 KeyboardGetKeyDown 最多 6 次。每次:

    1. 如果按键是 0,跳出循环。
    2. 调用 KeyWasDown。 如果返回是,处理下一个按键。
    3. 如果扫描码超过 103,进入下一个按键。
    4. 调用 KeyboardGetModifiers
    5. 如果 shift 是被按着的,就加载 KeysShift 的地址,否则加载 KeysNormal 的地址。
    6. 从表中读出 ASCII 码值。
    7. 如果是 0,进行下一个按键,否则返回 ASCII 码值并退出。
  3. 返回 0。

试着自己实现。我的实现展示在下面:

1、简单的检查我们是否有键盘。

.globl KeyboardGetChar
KeyboardGetChar:
ldr r0,=KeyboardAddress
ldr r1,[r0]
teq r1,#0
moveq r0,#0
moveq pc,lr

2、r5 将会保存按键的索引,r4 保存键盘的地址。

push {r4,r5,r6,lr}
kbd .req r4
key .req r6
mov r4,r1
mov r5,#0
keyLoop$:
  mov r0,kbd
  mov r1,r5
  bl KeyboardGetKeyDown

2.1、 如果扫描码是 0,它要么意味着有错,要么说明没有更多按键了。

teq r0,#0
beq keyLoopBreak$

2.2、如果按键已经按下了,那么他就没意义了,我们只想知道按下的按键。

mov key,r0
bl KeyWasDown
teq r0,#0
bne keyLoopContinue$

2.3、如果一个按键有个超过 104 的扫描码,它将会超出我们的表,所以它是无关的按键。

cmp key,#104
bge keyLoopContinue$

2.4、我们需要知道修饰键来推断字符。

mov r0,kbd
bl KeyboardGetModifiers

2.5、当将字符更改为其 shift 变体时,我们要同时检测左 shift 键和右 shift 键。记住,tst 指令计算的是逻辑和,然后将其与 0 进行比较,所以当且仅当移位位都为 0 时,它才等于 0。

tst r0,#0b00100010
ldreq r0,=KeysNormal
ldrne r0,=KeysShift

2.6、现在我们可以从查找表加载按键了。

ldrb r0,[r0,key]

2.7、如果查找码包含一个 0,我们必须继续。为了继续,我们要增加索引,并检查是否到 6 次了。

teq r0,#0
bne keyboardGetCharReturn$
keyLoopContinue$:
add r5,#1
cmp r5,#6
blt keyLoop$

3、在这里我们返回我们的按键,如果我们到达 keyLoopBreak$ ,然后我们就知道这里没有按键被握住,所以返回 0。

keyLoopBreak$:
mov r0,#0
keyboardGetCharReturn$:
pop {r4,r5,r6,pc}
.unreq kbd
.unreq key

8、记事本操作系统

现在我们有了 KeyboardGetChar 方法,可以创建一个操作系统,只打印出用户对着屏幕所写的内容。为了简单起见,我们将忽略所有非常规的键。在 main.s,删除 bl SetGraphicsAddress 之后的所有代码。调用 UsbInitialise,将 r4r5 设置为 0,然后循环执行以下命令:

  1. 调用 KeyboardUpdate
  2. 调用 KeyboardGetChar
  3. 如果返回 0,跳转到步骤 1
  4. 复制 r4r5r1r2 ,然后调用 DrawCharacter
  5. r0 加到 r4
  6. 如果 r4 是 1024,将 r1 加到 r5,然后设置 r4 为 0。
  7. 如果 r5 是 768,设置 r5 为0
  8. 跳转到步骤 1

现在编译,然后在树莓派上测试。你几乎可以立即开始在屏幕上输入文本。如果没有工作,请参阅我们的故障排除页面。

当它工作时,祝贺你,你已经实现了与计算机的接口。现在你应该开始意识到,你几乎已经拥有了一个原始的操作系统。现在,你可以与计算机交互、发出命令,并在屏幕上接收反馈。在下一篇教程输入02中,我们将研究如何生成一个全文本终端,用户在其中输入命令,然后计算机执行这些命令。


via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/input01.html

作者:Alex Chadwick 选题:lujun9972 译者:ezio 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Linux 桌面环境使你可以根据需要轻松设置键盘。下面来演示如何去做。

对于许多使用计算机很多年的用户来说,自从第一批 PC 键盘从生产线上下线后不久,Ctrl 和大写锁定键就已经在错误的位置上了。对我来说,这张 1995 年 Sun 工作站的老式键盘照片上的两个键的位置才是正确的。(原谅我放了一张模糊的图片,它是在昏暗的光线下使用 Minox 间谍相机拍摄的。)

感兴趣的话,可以读一下维基百科上对于 Ctrl 键位置的历史 的介绍。我不打算讨论将 Ctrl 键放在“a”旁边而不是 Shift 键下方的各种理由,也不评论大写锁定键的无用性,也没有打算与那些主张使用手掌根来触发 Ctrl 键的人争论,即使在一些笔记本电脑键盘上不可能这样做到,因为有的键会位于腕托以下。

相反,我将假设我不是唯一喜欢把 Ctrl 键放在“a”旁边的人,并说明如何使用 Linux 自带的灵活性在各种桌面环境中交换 Ctrl 和大写锁定键的位置。请注意,下面的演示可能只有有限的有效期,因为调整桌面设置的方法经常发生变化,但我希望这为你开了一个好头。

GNOME 3

GNOME 3 桌面环境用户可以使用 Tweaks 工具交换大写锁定和 Ctrl 键,如下所示。

具体步骤如下:

  1. 从你的 Linux 发行版的软件仓库安装 Tweaks 工具。
  2. 启动 Tweaks 程序。
  3. 从左侧菜单中选择 “Keyboard & Mouse”。
  4. 单击 “Additional Layout Options”。
  5. 在打开的窗口中单击 “Ctrl position”,然后选择 “Swap Ctrl and Caps Lock”。

完成!顺便说一句,你可以使用 Tweaks 工具做很多很酷的事情。例如,我将我的右 Ctrl 键设置为 Compose 键,这让我可以使用键盘快捷键打出各种字符,例如通过 Compose+c+,Compose+e+'Compose+o+^ 以及 Compose+n+~ 分别键入 ç、é、ô 和 ñ。(LCTT 译注:可参考 Special characters listed by extended compose sequence

KDE

我不使用 KDE,但我的同事 Seth Kenlon 写的 将改变你的生命的 KDE tweaks 这篇文章的第 5 项演示了如何重新映射按键。

Xfce

据我所知,Xfce 桌面环境没有一个方便的工具来管理这些(指交换按键)设置。 但是,setxkbmap 命令的 ctrl:swapcaps 选项可以帮助你完成交换按键的修改。这个修改包含两部分:

  1. 弄清楚命令的用法;
  2. 找出调用命令的位置,以便在桌面启动时激活它。

第一部分非常简单,命令是:

/usr/bin/setxkbmap -option "ctrl:nocaps"

在终端窗口中执行此命令,以确保结果符合你的预期。

假设上述命令有效,应该在哪里调用此命令呢?这需要一些实验。一种可能是在用户主目录的 .profile 文件中;另一个可能是将命令添加到 Xfce 的自启动配置(在设置管理器中查找 “Session and Startup”)里。

还有一种可能性是在文件 /etc/default/keyboard 中使用相同的选项,最终可能看起来像这样:

# KEYBOARD CONFIGURATION FILE

# Consult the keyboard(5) manual page.

XKBMODEL="pc105"
XKBLAYOUT="us"
XKBVARIANT=""
XKBOPTIONS="ctrl:swapcaps"

BACKSPACE="guess"

注意,这个更改将影响所有用户,因此如果你和其他人共享计算机,请准备好进行一些说明。此外,系统更新可能会覆盖此文件,因此如果你的设置失效了,就需要再次编辑它。将相同的信息放在用户主目录中的 .keyboard 文件内,可以为每个用户进行设置。

最后请注意,这些更改需要重新启动 Xfce(除非在终端窗口中的命令行上运行,但这在会话结束之后便会失效)。

LXQt 和其他桌面环境

我没有用过 LXQt,但根据我使用 LXDE 的经验,我会尝试上面用于 Xfce 的方法。我也希望适用于 Xfce 的方法可以用于其他 Linux 桌面环境。当然了,在其他桌面环境上遇到问题的时候,可以通过你最喜欢的搜索引擎来查找解决办法。

控制台

我没有在控制台上进行过尝试,因为我很少有机会与控制台(你在服务器上看到的或你的窗口系统没有正确显示时出现的界面)进行交互。上面给出的方法以人们希望的方式(即与其他应用程序一致)调整终端窗口。

但是,如果像上面一样已经编辑了 /etc/default/keyboard 文件或 〜/.keyboard,则实用程序 setupcon 可以用于更改控制台的键盘设置,以便实现相同的功能。链接 1链接 2链接 3 给出了一些关于如何从这两个文件实现这些更改的想法。第三个链接还讨论了使用 dumpkeysloadkeys 来实现想要的效果。setupcon 的手册 简短而重要,值得阅读,再结合上面 StackExchange 问题的一些评论,应该足以得到一个解决办法。

其他环境

最后,上面 StackExchange 的链接中提到的这一点值得强调 —— 配置控制台与配置终端窗口不同;如前所述,后者是通过桌面管理器进行配置的。

setxkbmapxkeyboard-configkeyboardconsole-setupsetupcon 命令的手册都是有用的参考资料。或者,如果你不喜欢阅读手册,可以看一下 这篇极好的文章


via: https://opensource.com/article/18/11/how-swap-ctrl-and-caps-lock-your-keyboard

作者:Chris Hermansen 选题:lujun9972 译者:jlztan 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

屏幕键盘可以作为实体键盘输入的替代方案。在某些时候,屏幕键盘显得非常需要。 比如, 你的键盘刚好坏了;你的机器太多,没有足够的键盘;你的机器没有多余的接口来连接键盘;你是个残疾人,打字有困难;或者你正在组建基于触摸屏的信息服务站。

屏幕键盘也可以作为一种防范实体键盘记录器的保护手段,键盘记录器会悄悄记录按键来获取密码等敏感信息。一些网上银行页面实际上会强制你使用屏幕键盘来增强交易的安全性。

在 linux 中有几个可用的开源键盘软件, 比如 GOK (Gnome 的屏幕键盘)kvkbdonboardFlorence

我会在这个教程中集中讲解 Florence, 告诉你如何用 Florence 设置一个屏幕键盘。 Florence 有着布局方案灵活、输入法多样、自动隐藏等特性。作为教程的一部分,我也将会示范如何只使用鼠标来操作 Ubuntu 桌面

在 Linux 中安装 Florence 屏幕键盘

幸运的是,Florence 存在于大多数 Linux 发行版的基础仓库中。

在 Debian,Ubuntu 或者 Linux Mint 中:

$ sudo apt-get install florence 

在 Fedora,CentOS 或者 RHEL (CentOS/RHEL 需要EPEL 仓库) 中:

$ sudo yum install florence

在 Mandriva 或者 Mageia 中:

$ sudo urpmi florence 

对于 Archlinux 用户,Florence 存在于 AUR 中。

配置和加载屏幕键盘

当你安装好 Florence 之后,你只需要简单的输入以下命令就能加载屏幕键盘:

$ florence

默认情况下,屏幕键盘总是在其他窗口的顶部,让你能够在任意活动的窗口上进行输入。

在键盘的左侧点击工具按键来改变 Florence 的默认配置。

在 Florence 的 "样式 (style)" 菜单中,你能够自定义键盘样式,启用/取消声音效果。

在“窗口 (window)”菜单中,你能够调整键盘背景透明度、按键不透明度,以及控制键盘比例、工具栏、尺寸和总是置顶等特性。如果你的桌面分辨率不是非常高,透明度调整就显得非常有用,因为屏幕键盘会挡住其他窗口。在这个例子中,我切换到透明键盘,并且设置不透明度为 50%。

在“行为 (behaviour)”菜单中,你能够改变输入方法。Florence 支持几种不同的输入法: 鼠标 (mouse)、触摸屏 (touch screen)、计时器 (timer) 和漫步 (ramble)。鼠标输入是默认输入法。最后的两种输入法不需要按鼠标键。 计时器输入通过将指针滞留在按键上一定时间来触发按键。漫步输入的原理跟计时器输入差不多,但是经过训练和灵巧使用,能够比计时器输入更加迅速。

在“布局 (layout)”菜单中,你能够改变键盘布局。比如,你能够扩展键盘布局来增加导航键,数字键和功能键。

只使用鼠标来操作 Ubuntu 桌面

我将示范如何将 Florence 集成到 Ubuntu 桌面中,然后我们不需要实体键盘就能够进入桌面。这个教程使用 LightDM (Ubuntu 的默认显示管理器) 来进入 Ubuntu,其他桌面环境也能设置类似的环境。

初始设置时需要实体键盘,但是一旦设置完成,你只需要一个鼠标,而不是键盘。

当你启动 Ubuntu 桌面时,启动程序最后会停在显示管理器 (或者登录管理器) 的欢迎界面。在这个界面上你需要输入你的登录信息。默认的情况下,Ubuntu 桌面会使用 LightDM 显示管理器和 Unity 欢迎界面。如果没有实体键盘, 你就不能在登录界面输入用户名和密码。

为了能够在登录界面加载屏幕键盘,安装配备了屏幕键盘支持的 GTK+ 欢迎界面。

 $ sudo apt-get install lightdm-gtk-greeter 

然后用编辑器打开欢迎界面配置文件 (/etc/lightdm/lightdm-gtk-greeter.conf),指定 Florence 作为屏幕键盘来使用。如果你愿意,你也能够使用 Ubuntu 的默认屏幕键盘 onboard 来代替 Florence。

 $ sudo vi /etc/lightdm/lightdm-gtk-greeter.conf 

[greeter]
keyboard=florence --no-gnome --focus &

重启 Ubuntu 桌面,然后看看你是否能够在登录界面使用屏幕键盘。

启动之后当你看到 GTK+ 欢迎界面时, 点击右上角的人形符号。你会看到“使用屏幕键盘 (On Screen Keyboard)”菜单选项,如下:

点击这个选项,屏幕键盘就会在登录界面弹出。现在你应该能够用屏幕键盘来登录了。

对于 GDM2/GDM3 用户怎么在 GDM2/GDM3 界面上使用屏幕键盘,Florence 官方网页提供了 文档 (documentation)

Ubuntu 桌面完全无键盘化的最后一步是让屏幕键盘在登录后自动启动,这样我们在登录后能够不使用实体键盘就操作桌面,为了做到这一点,创建以下桌面文件:

$ mkdir -p ~/.config/autostart
$ vi ~/.config/autostart/florence.desktop 

[Desktop Entry]
Type=Application
Name=Virtual Keyboard
Comment=Auto-start virtual keyboard
Exec=florence --no-gnome

这样可以让你在登录到桌面的时候就看到屏幕键盘。

希望这个教程对你有用。与你所看到的一样,Florence 是非常强大的屏幕键盘,可以用于不同目的。请和我分享你使用屏幕键盘的经验。


via: http://xmodulo.com/2014/08/onscreen-virtual-keyboard-linux.html

作者:Dan Nanni 译者:forsil 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

`  
你是否曾经拥有一个梦
    ——你的计算机
         可以自动为你干活?
或许,并非因为
    你刚看了终结者。
然而,除此之外
    脚本和任务自动化
        是每个高级用户追寻的梦
如果今天
    有许多的解决方案
        可以满足这个目标
那么
    有时候
       就难以从那众多之中采撷那
       简洁、聪明而又高效的一个
我
    不能假装
       是我自己发现了它
而与此同时
    却偏爱着那个
       整洁的软体——xdotool
其方法是如此直观
    正如它作为X11自动化工具的表露
转换思想
    xdotool可以通过读取文本文件
       模拟击键的旋律
           以及鼠标的曼舞  
`

让Xdotool在Linux定居

对于Ubuntu,Debian或者Linux Mint,你能够只做:

$ sudo apt-get install xdotool 

对于Fedora,请使用yum命令:

$ sudo yum install xdotool 

对于CentOS用户,可以在EPEL repo中找到该包。在启用EPEL仓库后,只要使用上面的yum命令就可以达成你的愿望。

对于Arch用户,可在Community仓库中找到该包:

$ sudo pacman -S xdotool 

如果你还是找不到你的发行版的对应xdotool,你可以从它的官方站点下载。

Xdotool基本功

虽然xdotool是那样的直观,但它仍然是个脚本程序。因此,为了要正确地使用它,你还是得了解它的语法。不过敬请放心,相对于程序的功能而言,语法还是比较简单易学的。

首先,模拟击键是很容易的。你可以从终端敲入下面的命令:

$ xdotool key [name of the key] 

如果你想要连接两个键,可以在它们之间使用“+”操作符。它看起来像这样:

$ xdotool key alt+Tab 

这两个组合键可以为你切换窗口。

要想让xdotool帮你输入,可以使用以下命令:

$ xdotool type '' 

这些对于基本的击键而言已经足够了。但是,xdotool的众多长处之一,就是它可以获取特定窗口的焦点。它可以获取右边的窗口,然后在里面输入,所有你记录下的按键都不会人间蒸发,而是老老实实的如你所愿的出现在那里。要获得该功能,一个简单的命令可以搞定:

$ xdotool search --name [name of the window] key [keys to press]

该命令将在打开的窗口中搜索对应名称的窗口,并聚焦于该窗口,然后模拟击键。

来点更高级的,但很有用哦,xdotool可以模拟鼠标移动和点击,看这命令:

$ xdotool mousemove x y 

你可以将光标定位到屏幕坐标(x,y)(像素)。你也可以使用“click”参数来组合:

$ xdotool mousemove x y click 1 

这会让鼠标移动到(x,y),然后点击鼠标左键。“1”代表鼠标左键,“2”则是滚轮,“3”则是右键。

最后,一旦你这些命令根植于你脑海,你也许想要实际转储于文件来编辑并试着玩玩。鉴于此,就会有超过一个语句以上的内容了。你需要的就是写一个bash脚本了:

#!/bin/bash

xdotool [command 1]
xdotool [command 2]
etc

或者你可以使用:

$ xdotool [filename] 

这里你将命令写入到一个独立的文件中,然后通过将文件名作为xdotool命令的参数。

意外收获

作为本文的一个意外收获,这里是xdotool的一个具体实例。你可能听说过,也可能没听说过Bing —— 微软的搜索引擎。在后面的实例中,你会看到你可能从没听过Bing奖励:一个程序,可以让你用Bing积分兑取亚马逊的礼物卡和其它的一些礼物卡(LCTT 译注:我是从来没听说过~)。要赚取这些积分,你可以每天在Bing上搜索累计达30次,每次搜索你都会获得0.5个积分。换句话说,你必须把Bing设为默认搜索引擎,并每天使用它。

或者,你可以使用xdotool脚本,在这个脚本中,会自动聚焦到Firefox(你可以用你喜欢的浏览器来取代它),并使用fortune命令生成一些随机单词来实施搜索。大约30秒之内,你的日常搜索任务就完成了。

#!/bin/bash

for i in {1..30}
do
  WID=`xdotool search --title "Mozilla Firefox" | head -1`
  xdotool windowfocus $WID
  xdotool key ctrl+l
  xdotool key Tab
  SENTENCE="$(fortune | cut -d' ' -f1-3 | head -1)"
  xdotool type $SENTENCE
  xdotool key "Return"
  sleep 4
done

下面来个小结吧:我真的很喜欢xdotool,即便它的完整功能超越了本文涵盖的范围。这对于脚本和任务自动化而言,确实是种平易的方式。负面的问题是,它可能不是最有效率的一个。但我要再说一遍,它忠于职守了,而且学习起来也不是那么麻烦。

你对xdotool怎么看呢?你是否更喜欢另外一个自动化工具,而不是它呢?为什么呢?请在评论中告诉我们吧。


via: http://xmodulo.com/2014/07/simulate-key-press-mouse-movement-linux.html

译者:GOLinux 校对: wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出