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

栏目: IOS · 发布时间: 5年前

内容简介:最近更新:10th 一月, 2019在两年前,我曾写过一篇名为《不过还好,到 macOS 10.14 Mojave,神奇的事情出现了,这个 bug 完全“反转”了,它并没有修复,但以另一种方式呈现——系统自带的中文输入法无法获取 VoiceOver 焦点,反而第三方输入法可以了!:laughing:

最近更新:10th 一月, 2019

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

落格输入法 macOS 2

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

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

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

判定

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

func NSIsVoiceOverRunning() -> Bool {
    
    if let flag = CFPreferencesCopyAppValue("voiceOverOnOffKey" as CFString, "com.apple.universalaccess" as CFString) {
        if let voiceOverOn = flag as? Bool {
            return voiceOverOn
        }
    }
    
    return false
}

设置 工具 方面

如果你都使用了系统提供的控件,那么设置项和 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,总之,我尝试重写这些方法,最终成功了:

override func accessibilityLabel() -> String? {
 
        return "候选1"
    }

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

override func accessibilityFrame() -> NSRect {
        if let r = self.superview?.window?.convertToScreen(self.frame) {
            return r
        }
        return self.frame
    }

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

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

override func accessibilityRole() -> NSAccessibility.Role? {
        return .button//设置为 button 角色,这样才能允许交互
    }
override func accessibilityPerformPress() -> Bool {
        
        return true//返回 true 表示接受了本次操作
    }

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

发送 NSAccessibility 通知

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

extension NSAccessibility.Notification {
    ……
    public static let applicationHidden: NSAccessibility.Notification
 
    public static let focusedUIElementChanged: NSAccessibility.Notification
 
    ……
}

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

用户体验

状态提示

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

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

w.setAccessibilityHidden(true)
w.setAccessibilityElement(false)
w.setAccessibilityEnabled(false)

无限候选栏

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

解字不读词

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

已知问题

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

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

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

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


以上所述就是小编给大家介绍的《落格输入法 macOS 2 是如何为 VoiceOver 进行优化的》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

设计原本

设计原本

Frederick P. Brooks, Jr. / InfoQ中文站、王海鹏、高博 / 机械工业出版社 / 2011-1-1 / 55.00元

无论是软件开发、工程还是建筑,有效的设计都是工作的核心。《设计原本:计算机科学巨匠Frederick P. Brooks的思考》将对设计过程进行深入分析,揭示进行有效和优雅设计的方法。 本书包含了多个行业设计者的特别领悟。Frederick P. Brooks, Jr.精确发现了所有设计项目中内在的不变因素,揭示 了进行优秀设计的过程和模式。通过与几十位优秀设计者的对话,以及他自己在几个设计......一起来看看 《设计原本》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试