【项目】摩纳哥语音编辑器

摩纳哥语音编辑器(Monaco Speech Editor)是一款适用于视障人群的在线代码编辑器。它在开源编辑器 Monaco Editor 的基础上,开发了专为视障者设计的语音辅助功能,包括鼠标悬浮提示,快捷键操作和代码阅读。

其代码阅读功能尤其强大,用户可以用键盘精确定位指定内容进行阅读。针对同一段代码,它提供多种语音输出模式:字符模式、代码模式、音乐模式、全局模式。这些模式根据用户在不同编程阶段的不同需求,提供差异化的语音输出。比如,当用户对一个语句进行 debug 时,推荐使用字符模式进行语音播放。

如果你对它的功能感兴趣,点击下方链接尝试一下吧

GitHub 项目地址:monaco-speech-editor

项目背景

根据世界卫生组织2010年的数据,全盲者在全年龄段人口中所占比例为0.58%。在全盲人口中,大部分是中老年人口。从下图可以看出,致盲风险随着年龄快速升高。在0~14岁人群中,全盲比例仅有0.07%;在15~49岁人群中,全盲比例稍高一些,为0.16%;而在50岁以上人群中,全盲比例则达到了2.39%。

全盲人口的比例不大,但从绝对数值来看却是非常可观的。2010年,世界全盲人口比例为0.58%,但全盲人口数却达到了3936.5万。即使14岁以下人口的全盲比例仅有0.07%,但考虑绝对数值,也达到了142.1万人。

而且并非只有全盲者才需要语音辅助。有相当比例的视力障碍者,即使使用眼镜,也无法矫正到正常视力。这部分的视障者,也是需要语音辅助的。相比于全盲者,视力障碍者的人口则更为庞大,达到了惊人的2亿8538万。

在提倡公平的原则下,我们希望视障者和视力正常的人一样,也能自由地选择职业。事实上现在已经有[部分视障工程师](http://www.xinhuanet.com/2018-01/04/c_1122206710.htm),出现在程序员岗位上,证明着他们的实力。本项目旨在为视障程序员编程无障碍化做一些贡献,[项目源代码](https://github.com/luochang212/monaco-speech-editor)现已在GitHub上以MIT许可证开源。

技术选择

本编辑器是用JavaScript编写的网络应用 (web application)。它只有两项功能需要外部依赖,一个是在线代码编辑器模块,一个是文字转语音模块。

(一)在线代码编辑器

开源的在线代码编辑器还是挺多的,比如:

它们对语法高亮、缩进、代码补全等基础功能都有比较好的支持,用起来大同小异。选择Monaco Editor是因为用惯了VSCode。毕竟Monaco Editor的源代码就是直接从VSCode贴过去的,两者的界面风格和操作方式都极其相似,对VSCode用户比较友好。但后来使用过程中发现打脸了,当然这是后话。

(二)文字转语音

文字转语音 (text to speech) 的应用就更多了,几乎各大公司都推出了自己的应用:

但鉴于这些应用都需要网络连接,才能获取语音。考虑到网络延迟和脱机使用的问题,本项目并未采用以上任何一种API,而是选择了Web Speech API。Web Speech API本身并不提供语音服务,它事实上起到资源连接的作用。它首先会搜索操作系统,然后将操作系统提供的语音支持集合成一个列表,提供给浏览器使用。所以Web Speech API提供的语音支持会随用户系统的语音支持项而发生变化。因此不排除一些较老的机型无法使用的可能。但本项目认为本地化语音支持比之于对老机型的支持更加重要,因此选择了Web Speech API。这也是一个取向问题。

综上,本项目主要依赖项只有两个:Monaco Editor 和 Web Speech API。事实上,本项目的名称 Monaco Speech Editor,也正是取自这两个依赖项。

需求分析

一名视障程序员或一位全盲者,在使用代码编辑器时,主要有以下信息需求:

  • 界面内容信息:这个按钮的名称是什么?这项设置的名称是什么?
  • 界面定位信息:编译器在哪?设置在哪?某项功能的按钮在哪?
  • 界面反馈信息:我刚刚按下的按钮打开了什么功能?
  • 编辑器内容信息:这行代码的内容是什么?光标前的字符是什么?
  • 编辑器定位信息:某个的变量在哪儿?我应该如何跳转到那儿?
  • 编辑器反馈信息:我刚刚输入了什么字符?我将要删除什么字符?
  • 光标位置信息:全文一共有多少行代码?我的光标现在停在第几行?
  • 控制台内容信息:控制台的输出是什么?

功能设计

本项目提供的功能大致可划分为三个类:编辑器的基础功能,语音支持和UI交互辅助。

功能分类 具体功能举例
基础功能 文件管理,代码高亮,控制台输出
语音支持 音调,音速,音源选择,输出模式,输出范围
UI交互辅助 全键盘操作的设置列表,全键盘操作的功能查找

(一)基础功能

一个为视障者提供的代码编辑器,首先必须是一个正常人也易于操作的编辑器,其次因为对视障人群提供了特殊支持,从而使视障人群也能方便的使用。

本编辑器提供三项基础功能,分别是:文件管理,代码高亮和控制台。

其中,文件管理系统提供六项功能:新增文件,删除文件,上传文件,保存文件,重命名文件,恢复已删除文件。

代码高亮允许用户选择编程语言,并以该语言的语法对代码进行着色。此外,对上传的文件,代码高亮功能会根据文件后缀名自动识别新上传的代码文件的语言类型,并以此语言语法对代码进行着色。

控制台目前只适用于HTML, CSS和JavaScript。控制台提供两种信息:页面渲染结果和console.log()函数的输出。具体用法是,新建一个HTML文件,按HTML的方法写好页面内容,可包括CSS和JavaScript。然后点击“RUN”键,控制台的左侧窗口将输出页面的渲染结果。如果在<script>标签内含有console.log()语句,则控制台右侧窗口将输出console.log()的函数输出。 

(二)语音支持

语音输出采用Web Speech API,因此语言选项根据系统的不同会有所不同。此外,本应用允许用户调节语速和音调。

针对编辑器内的文本,本应用设计了四种语音输出模式,分别是Character Mode, Code Mode, Music Mode, Overview Mode. 下表解释了这些模式的区别。

语音模式 输出内容
Character Mode 逐字阅读每个字母和符号,甚至包括空格
Code Mode 阅读单词而非字母,不朗读对代码影响不大的符号
Music Mode 将部分符号替换成乐器的声音
Overview Mode 朗读全局信息,比如文件名,文件总字符数等

Character Mode 被设计成最精细的模式,不但逐字母朗读,而且不省略任何字符。Code Mode 被设计成最普通的模式,适用于最一般情况下的代码朗读。Music Mode 是为了避免尴尬的符号语音设计的。如果一段代码朗读起来充斥着诸如“左括号”,“左中括号”这样的语音,听起来是会引起不适的。因此本程序尝试将这些符号语音,替换成乐器的声音,使用户能更直观地获取符号信息。Overview Mode 被设计成全局信息解释系统,本来这个系统应该更加强大,但由于一些来不及完成的工作,目前只提供该功能的弱化版本。

(三)交互辅助

光有语音辅助功能还不够,还需要提供一个类似游戏中新手村这样的地方,让用户可以学习和探索本应用的功能。因此就有了UI交互辅助功能。

UI交互辅助,其实就是辅助功能的辅助功能。本应用提供两个UI交互辅助功能,分别是:Spotlight 和 Linear Index。

Spotlight 的存在是为了让视障人群甚至不需要观看屏幕,也能打开或关闭某个设置选项。它本质上是一个可以操作的列表。按上下键可以滚动列表,改变选中的设置项。然后按左键或右键,改变该设置项的状态,比如打开变关闭,或者关闭变打开。下图展示了Spotlight的界面及操作方法。

Linear Index 是快捷键的列表。通过按上下键选中不同的功能,然后按左键或者右键朗读该功能的名称及快捷键。本功能相当于是一个功能索引,并且能够为用户提供相关功能的快捷键键位信息。下图展示了Linear Index的操作方法。

部件详解

文件系统

文件系统是纯手撸的,没有采用任何框架。UI技术来自W3C的范例 to do list(中国大陆无法访问),交互设计借鉴了 fausteditorweb 的文件系统。

文件列表中的每个文件都以面向对象的方式存储。下面这段代码初始化了文件对象Files,以及用于存储该对象的数组fileArray

    // 用面向对象的方法控制页面切换
    // 初始化变量
    var Files = {
        fileId: "",
        fileName: "",
        isDelete: "false",
        isActive: "",
        editor: null,
        editorContent: "",
        editorLanguage: ""
    };

    var fileArray = [];

Files的成员有:

  • FileId - String(数值),用于唯一标记该文件
  • fileName - String,用于记录该文件的文件名
  • isDelete - Boolean,删除标志
  • isActive - Boolean,当前打开文件的标志
  • editorContent - String,用于记录文件内容
  • editorLanguage - String,用于记录该文件的编程语言类型

因为没有采用任何框架,所以文件系统还是蛮复杂的。因为本应用编写了很多基于Editor的功能,因此每当打开一个文件或者新建一个新文件时,都需要为这个文件注册所有功能。这些注册功能就会使文件系统的代码看起来很冗长。

而且,文件系统还需要处理一些边界情况。比如,所有文件均被删除,一个文件也不剩时,应该如何处理;当前打开文件被删除时,应该如何处理,如果需要跳转到另一个文件并打开它,因为本应用采用软删除法,那么应该如何确保打开的文件不是已删除文件,以及如何确保至少有一个文件能够接受跳转……这些细节都需要考虑在内,才能不出bug。

工具栏

工具栏也是本应用的一个特色,它采用类音乐软件的设计。它假设每一行代码是一首歌曲,一个代码编辑器里的多行代码,就组成了一个歌单。基于这样的想象,工具栏的交互界面也提供了4个功能,分别是:播放下一行代码,播放上一行代码,播放当前行代码,暂停播放当前行代码。

一个小秘密是,用快捷键调用工具栏的播放上一行和播放下一行会比用鼠标点击图标的效果更好,因为我对快捷键触发的功能做了一些优化。相当于图标点击触发的是基础版,快捷键触发的是改进版。

其他三个功能:语法高亮、全屏,比较容易理解,那么就略过不表。跳转到行也很容易理解,但值得一提的是本应用允许用户用快捷键Ctro + option + J将光标聚焦到跳转到行功能的文本框里,在文本框里输入行数以后,按回车键即可将光标移动到该行的最左端。加了快捷键以后,跳转到行功能就可以完全依靠键盘实现,而不需要动用鼠标了。

控制台

控制台目前功能很弱,因为只有前端,所以只支持了HTML, CSS, JavaScript。要想实现Golang, Python, Java的编译,据我的理解,都必须要有后端。

控制台长这样:

控制台有两个区域,左边输出的是渲染好的页面,右边输出的是console.log()函数的信息,可以用来打印各种类型的变量。控制台的设计有一个细节,按钮在控制台打开状态下会变大,在缩回状态下会变小。此外,还提供了隐藏右侧区域和隐藏右侧区域的功能。

前端路由

前端路由是为了弥补没有后端的缺陷设计的一个功能。利用前端路由可以加载默认设置。比如在原地址后加上#dark,在打开这个网页时,即可获得一个已打开夜间模式的Monaco Speech Editor。

完整的路由列表如下:

Router Setting
#load-demo Load demo
#dark Turn on night mode
#full-screen Full screen
#run Open console bar
#tutorial Play audio tutorial
#spotlight Turn on spotlight
#linear-index Turn on linear index
#character-mode Turn on character mode
#code-mode Turn on code mode
#overview-mode Turn on overview mode
#voice-feedback Turn on voice feedback
#voice-cue Turn on voice cue
#mute Disable any autoplay event
#dark&run Turn on night mode and console bar
#dark&mute Turn on night mode and disable any autoplay event

桌面应用

本应用亦针对MacOS开发了桌面版。生成桌面应用的技术是Electron,它是一个基于 JavaScript, HTML, CSS 的框架,此外它还集成了Chromium, Node.js 和 Native API. 利用Electron,只需简单几行代码,程序员就能用它生成已有网络应用的桌面版本。

如果你对本项目感兴趣,以下链接可能对你有帮助:

GitHub: luochang212/monaco-speech-editor

Demo: Monaco Speech Editor