Categories
Mac OS Swift

落格输入法 macOS 2 是如何为 VoiceOver 进行优化的

在两年前,我曾写过一篇名为《ios 为视障用户支持 VoiceOver》的文章,里边主要介绍了 iOS 端该如何为 VoiceOver 进行必要的支持,后来我又开发了 macOS 端的落格输入法,但很遗憾由于 macOS 自身系统 bug,第三方输入法根本无法获得 VoiceOver 焦点(主要是 10.13 及以下版本),所以我也就没有过多关注——甚至直到这款输入法整个生命周期结束也没能实现 VoiceOver 的支持,实在是让人遗憾。

落格输入法 macOS 2

不过还好,到 macOS 10.14 Mojave,神奇的事情出现了,这个 bug 完全“反转”了,它并没有修复,但以另一种方式呈现——系统自带的中文输入法无法获取 VoiceOver 焦点,反而第三方输入法可以了!😆

总之,这次我也得以能够为 VoiceOver 用户提供支持 :)

直到现在,落格输入法 macOS 2 也已经正式上架销售了一段时间,产品也相对第一个版本完善了许多,我觉得是时候写一篇文章来粗略总结一下 macOS 平台对 VoiceOver 支持的重点。

判定

要支持 VoiceOver,你就必须能够判断系统当前是否正在运行 VoiceOver,不同于 iOS,macOS 并不直接给出 VoiceOver 是否在运行的判断 API,也就是说,从官方的态度来看,还是希望视障用户能和明眼用户得到尽可能一致的用户体验的。但总之,针对视障用户做特定的额外优化还是必要的,我们可以通过读取系统的偏好设置来判断 VoiceOver 是否打开——但这也有缺点,比如用户打开了 VoiceOver,但不经过系统偏好设置直接关闭了 VoiceOver,那此时我们依旧得到的是“开启”的状态(对 VoiceOver 状态特别敏感的开发者需要注意):

 

设置工具方面

如果你都使用了系统提供的控件,那么设置项和 iOS 没什么区别,值得一提的就是系统自带的圆圈问号按钮,也就是在一些 app 里常见的 help 按钮,它默认的名称叫“help”,而 storyboard 中修改的地方叫做“Description”,这让人多少觉得有些混淆,作为对比,iOS 则对应的输入框,名称叫 “title”。

候选栏

对于输入法来说,候选栏可能是最常用的一个界面了,这也是它主要的 UI 部分。为了提供更完善的自定义和更优秀的显示性能,实际上我并没有使用 macOS

InputMethodKit 中自带的那个候选栏,那个候选栏除了能简单“显示候选”这一个功能外,其他所有自定义选项都是无效的,更别提这些选项之外的自定义功能了,更是不可能。为此我自己实现了一个候选栏,但是在 VoiceOver 下,读取的时候是这样的顺序:

1→第一个候选内容→候选的背景→2→第二个候选的内容→3→……

这并不是一个很好的体验,尤其是当选中的内容是123这些数字的时候,用户甚至不知道上屏的是什么——实际上你的输入法也不知道要选中什么。

NSAccessibilityGroup 协议

这个问题主要是 VoiceOver 把你 View 都给遍历了,它无法区分哪些有用哪些没用,这时候我们用一个 View 包裹这些元素(实际上你本来也应该这么做,毕竟这是一个“候选”对象,对吧?),然后让你的 View 遵循  NSAccessibilityGroup 这个协议,这时对 VoiceOver 来说,它就是一个唯一的元素了,VoiceOver 不会继续遍历改 View 下的 SubView。

不过,这时候新的问题产生了,这些 Group 没了内容,因为是自定义的 Group,我们需要手动来为这个 Group 赋值。

要给 Group 赋值,不同于 iOS,macOS 下你还是需要用方法来实现而不是直接给属性赋值,比如 self.setAccessibilityTitle("候选1") 但事实上这样赋值也不会生效,我不知道这是对于输入法的特殊需求,还是说其实是个系统的 bug,总之,我尝试重写这些方法,最终成功了:

这样,当用户移动 VoiceOver 焦点到对应的候选上时,VoiceOver 就会读出候选的内容了(这里就是“候选1”)。当然,这还不够,你会发现视觉上 VoiceOver 的方框是跑偏的,所以你还需要设置它的位置,尽管也许视障用户并不介意这些小细节:

这里我们尝试获取当前候选栏的 window,并将候选的位置信息转换到全局屏幕坐标并返回(VoiceOver 要的坐标必须是屏幕级别),这样,VoiceOver 的焦点方框也就对正了。

最后是 Group 的身份问题,如果我们不设置,那么用户即使把 VoiceOver 焦点移动到了对应的候选上,按下空格后可能上屏的依旧是第一个,因为 VoiceOver 有一套它自己的控制快捷键,所以,这里也要支持一下:

这样候选栏部分基本就完成了。

发送 NSAccessibility 通知

如同 iOS 一样,有时候我们需要给 VoiceOver 发送通知以触发刷新,macOS 也支持你这么做:

与 iOS 不同的是,桌面级别的通知多了很多,这里我只用到了上面列举的两个,前者用来通知候选栏已经隐藏,后者用来触发 VoiceOver 刷新。

用户体验

状态提示

不同于系统自带中文输入法,落格输入法和其他第三方输入法一样,是支持中英文模式切换的,这其实对视障用户带来了不小的困惑,因为他们不知道当前的状态是什么,并且视觉上的小方块提示也无法通知到他们,在与视障用户交流之后,我做了一个简单的状态提示音,在切换到中文或者英文时,发出不同的提示音用以通知。

另外,由于中英切换的那个提示小方块实际上也是一个 window,那就存在一个问题,如果你切换中英文模式或者繁简功能,那么这个小方块的出现会抢夺 VoiceOver 焦点,这时候就需要让它对 VoiceOver 不可见:

无限候选栏

通常,候选栏是翻页设计的,为了方便视障用户(其实有时候明眼用户也用得到)选字,落格输入法 macOS 2 支持自动翻页,比如当前有 16 个候选,候选栏默认显示了 6 个(第一页),那么你移动高亮到第六个的时候继续移动,会自动翻页并定位到第二页的第一个。

解字不读词

如同明眼人一样,视障用户也会追求输入的效率,VoiceOver 在读候选词的时候会先把整个候选完整读一遍,然后再逐字解释,这对整句输入用户来说可能就很方便,一次输入好几个字,然后听一遍发现没大问题,就发送了,根本不用等后边的逐字解释,方便的很——但这样有个弊端就是中文字符同音太多了,经常会导致一些错字在里面,就是明眼人都在所难免,何况是靠听(比如:帮我占个座尾巴)。对于喜欢打单或是打词的用户,其实只解释字要更高效,在 空山新雨 的建议下我添加了落格输入法 macOS 2 特有的“只解字不读词”模式,不论是落格解释库还是经典解释库,都可以直接支持,方便的很。

已知问题

当然,最终还是少不了一些遗留问题:

候选栏的名称改不了,兴许是因为输入法是个后台应用导致的?不论为 window 设置什么名字,VoiceOver 下永远读的是“application”。

另一个是输入完会触发全文朗读的问题,虽然聊天发言估计问题严重性不大,但如果你是在写一篇长篇的文章,那就有点让人崩溃了……但遗憾的是,我没有任何办法能够打断这个过程,目前唯一的解是用户输入完自己手动移动一下光标……

还有一个记不太清的问题,在 macOS 上,主动发通知让 VoiceOver 朗读内容似乎是无法生效的。

 

本文由 落格博客 原创撰写:落格博客 » 落格输入法 macOS 2 是如何为 VoiceOver 进行优化的

转载请保留出处和原文链接:https://www.logcg.com/archives/3153.html

By 落格博客

如非声明,本人所著文章均为原创手打,转载请注明本页面链接和我的名字。

发表评论

电子邮件地址不会被公开。 必填项已用*标注