在游戏手柄上触摸打字

2020-08-06 08:38:17

在键盘上打字需要固定的坐姿或站姿,而游戏手柄则是手持的,结构紧凑。你可以在房间里走来走去,也可以躺在沙发上使用它们。

由于游戏手柄上的按键数量很少,人们还没有认真考虑将它们用于编程等繁重的打字活动。

然而,模拟杆(大多数游戏手柄都有两个)有可能提供无限数量的输入。这一切归根结底就是选择正确的手势,以获得最高的效率和最小的拇指劳损。

有许多现有的用于游戏手柄的文本输入方法。如果你玩过游戏机游戏,你肯定看过并用过其中的一款。

在“塞尔达传奇”中,您必须使用箭头按钮逐个选择字母,然后每次按确认按钮将字母添加到文本输入字段。

从那时起,人们开发了更高效的输入法。如果您对探索它们感兴趣,请查看Gamasuta撰写的这篇文章。

不幸的是,我发现的所有输入法都有两个主要缺陷,使它们不适合严肃的工作:

对速度的需求是显而易见的。依靠视觉反馈是不可接受的,因为它占用了宝贵的屏幕空间,并将你的注意力从工作转移到视觉输入辅助上,从而破坏了你的流,最终减缓了你的速度。

然而,没有反馈意味着所有手势都需要记忆和练习,直到它们能够足够准确地执行为止。虽然视频游戏很难要求用户花几周时间练习文本输入法,但对于可以应用于任何程序的通用文本输入法来说,这是可以接受的成本,实际上类似于学习触摸打字。

在这篇文章的其余部分,我将概述我为游戏板创建一个文本输入系统所采取的步骤,该系统适合作为键盘的替代品,用于繁重的打字活动。

首先,我使用python的pyGame包创建了一个可视化游戏手柄模拟操纵杆移动的工具。为了这篇文章的目的,我调整了工具,不仅显示了棍子的当前位置,而且还显示了过去的位置,增加了较浅的色调,以便你可以看到棍子所走的路径。

下图表示两个类比杆同时向内、向上、向外、向下、再次向内和回到中心的运动。

我做的第一个观察是,由于两根杆子都在中心,因此游戏盘处于中性状态,所以所有输入都必须从该中性状态到达,并且当两根杆子回到中心时,所有输入都必须完成。

考虑到这些限制,我发现最简单可能的输入是向任何方向移动其中一个操纵杆,然后回到中心。

几分钟的实验表明,与轴线对齐的方向很容易准确定位,而针对其他方向的输入就不那么精确了(如上图所示)。

考虑到到目前为止可能的手势,每根棍子有4+8+8=20个输入。

通过组合手势,总共有20*20+20+20=440个输入,我发现这已经足够了。

我把每根棍子的输入空间分成4个扇区,并给每个扇区分配了一个数字。

下一步,我在中心周围定义了一个阈值,它将帮助确定棒的位置是处于中性状态还是在其中一个扇区。

如你所见,阈值半径相当高。通过实验,我找到了犯错误最少的最佳半径。

每当其中一根棒越过阈值离开中心时,输入序列就开始了。一旦两根棍子回到阈值内的中心,序列就被认为是完成的,并转换成一对描述棍子运动的元组。

在这种情况下,操作只是键盘上的键。游戏板的肩部按钮可以映射到Shift、Ctrl、Alt和Super键,这会很方便,因为这些键都是用于组合的键(例如,Ctrl-C用于复制)。

为了确定从输入手势到按键的最佳映射,我使用键盘记录器记录了我系统上的所有按键数周,并分析了每个按键的频率。

最频繁键入的键应该映射到最简单(因此也是最快)的手势。我通过将每根棍子的输入长度相加来测量手势的难度。例如,上述输入((0,),(2,3))的难度为1+2=3。

假设在输入单杆输入时,两个杆之间的交替比同一杆上的多个单杆输入更快,那么经常一起键入的键最好映射到不同的杆上。

按照这个逻辑,我首先生成所有可能的单杆输入,并按难度对它们进行分组。对于每个难度,我对该组中的输入进行了计数,并从最频繁键的排序列表中提取了该数量的键。

现在的目标是将这些键分成两组,一组映射到左杆上的输入,另一组映射到右边。为了找到理想的组,我创建了一个图,其中节点是键,加权边表示键组合的频率。

我反复去掉权重最小的边,直到图形变成两部分。如果图不连通,我会递归地对连通组件应用划分算法,最后合并独立集合组。

请考虑以下示例。第一个困难组由所有难度为1的输入组成,它们是((0,),()),((1,),()),((2,),()),((3,),()),((),(0,)),((),(1,)),((),(2,)),((),(3,))。

该组中有8个输入,因此从排序列表中取出最频繁的8个键。这些键是';e';、';o';、';a';、';i';、';s';、';j';、';r';。创建一个以这些关键点为节点的图,并为这些节点之间的边指定与每个关键点组合的频率相对应的权重。

您可能会感到奇怪,为什么密钥j是8个最频繁的密钥之一,但与其他频繁密钥的连接却如此弱。原因是在使用vim pllusit的快捷方式在我的系统窗口之间切换时,会大量使用j。因此,它更多地用于隔离,而不是在文本中使用。

由于该图已断开连接,因此我继续对连接的组件应用该算法。仅由节点j组成的子图已经是二部图(j+空集)。i递归地将该算法应用于另一个组件。

现在,该组件可以成功拆分为2个组,组中的节点之间没有边。

正如您所看到的,最强的链接(最频繁的组合键)位于不同侧的节点之间,这正是我想要的。

我对其他难度组(只有单杆输入)重复了这个过程,然后我生成了所有可能的组合输入,再次按难度对它们进行分组,并将剩余的键分配给这些输入。由于组合输入需要使用两个手柄,因此将按键分成两组的问题在这里无关紧要。

我使用的触摸式打字训练器Ktouch,与我在近20年前学习键盘打字时使用的触摸式打字训练器Ktouch相同。为此,我创建了定制课程。

虽然运行此输入系统的python进程通常将CPU使用率保持在10%以下,但如果它要在后台持续运行,我更愿意使用低级语言重新实现和优化它,以便让CPU可用于更密集的前台任务。

在我把我的游戏手柄升级到DualShock4之后,我意识到我可以相对准确地进行对角线输入。集成对角线输入将减少所需的更复杂输入的数量,从而提高速度。

经过几周的练习,我在游戏板上打字的速度大约是在键盘上打字的一半。考虑到我在键盘上疯狂的打字速度一点也不差。为了获得额外的收益,我会使用剩余的可用输入,并将它们映射到自定义操作,如快捷键或依赖于程序的行为。

拨号动作似乎使拇指最劳累。用更长但更直截了当的输入来取代它们可能是值得一试的。

随着练习的增加,拇指上的劳损逐渐减轻。然而,在开始练习时,一次应该限制在几分钟之内。

在短短几天的时间里,我组装了一个高效的游戏手柄打字系统。有很多可能的改进,但这个设置可以作为概念的证明,它证明了在游戏手柄上可以实现高效的文本输入。这个项目的代码可以在GitHub上找到。