This guide is intended for those who are more experienced (or are not very experienced but want to learn more technically advanced things), about the F123Light operating system. Should you need information about the overall strategy of the project, our motivations, or other non-technical matters, please read our general project guide.

Should you have suggestions, corrections, new content, new code, or other contributions to this project, please join one of our e-mail lists and let us know about it.

1 Downloading, Updating, and Building Images

1.1 Downloading the Latest Release Candidate Image

Experienced users may wish to assist us in testing new features and updates. One way to do this is by downloading and trying the latest release candidate image.

You may find our latest release candidate here:

To verify file integrity after download, you may use the sha1sum signature for the above image.

Please be aware that this is a test image and there may be bugs, some of which could be severe. Please do not use test installations as your primary machine or in production environments.

If you are not an experienced computer user, we recommend that you use instead our latest stable version of F123Light, as it has been tested more thoroughly than the above version.

1.2 Updating F123Light on the Command Line

Advanced users can perform an update from the command line with the command:


If such a user is helping us test recent changes to the code, he or she can use a special parameter to update from the development branch. To specify the development branch, the correct command would be:

update-f123light -b dev

1.3 Building Your Own F123Light Image

Experienced users have the option of generating or building their own image. Every copy of F123Light includes the command “build-f123light”, which automatically generates the image file, which can then be burned or flashed to a MicroSD card for use.

To build a new image, you will need to make sure you have at least 8GB of free space. You may need aditional space for the work directory. If you try to build an image with out enough free space the script will alert you to the issue and stop.

To build an image with all default parameters, go to the command line and enter the following:


1.4 Burning/Flashing Your New Image Using the Command Line

Experienced or ambitious users can burn the image they have just built on their own Raspberry Pi by using the “sudo fdisk -l” command to identify which device or drive name to use, after plugging-in the USB adapter containing the target MicroSD card.

Warning: This is a risky procedure, so it should not be attempted by inexperienced users or those with valuable information on their computers, or who do not have an up-to-date backup of same.

Once the user has identified what device holds his or her operating system, and which device will be used to burn the image, the user can type something like the following to actually flash the image which was just created:

sudo dd if=filename of=device-path bs=2M

The “sudo” string is used for important commands which require admin powers. The “dd” command is also called disk-dump, and it is used to make exact copies of disks or to burn images on same. The “if” and “of” parameters, stand for input file and output file, and the “bs” parameter stands for block size. Specifying block size is optional, but we have found that using “2M” speeds-up the process. Do note that the “M” in this parameter must be capitalized.

1.5 Build a Custom Image

To build a new image, you will need to make sure you have at least 8GB of free space. You may need aditional space for the work directory. If you try to build an image with out enough free space the script will alert you to the issue and stop.

You can customize your image by passing special parameters to it. Here is a list of things you can customize about your image:

Here are a couple of examples of building an image with some parameters given on the command line:

build-f123light --output-file custom.img

This will make an image called custom.img.

build-f123light -n wifi-network-name -w 'your-password'

This example creates an image which already contains your Wifi login, so you will not have to re-enter your WiFi password at boot time. Just like the two examples above, you can enter all the parameters listed above and the image will be built with all that information already included.

1.6 Important locations and File Structure

With the exceptions of update-f123light, build-f123light, and first-boot, the scripts that power F123Light reside in the /usr/lib/F123-wrappers and /usr/lib/F123-includes directories.

Each file is named according to what it does, and there is a brief description at the top of the file with the copyright notice. The files in /usr/lib/F123-wrappers are the end product that present information to the user. The files in /usr/lib/F123-includes are functions and code that gets reused almost everywhere to make things easier to extend.

So, to have menus and input boxes, etc, similar to what we use, you can include something like the following in your scripts:

# Load F123 includes
if [[ -d /usr/lib/F123-includes/ ]]; then
for i in /usr/lib/F123-includes/*.sh ; do
        source $i

If you need to interact with the preferences, which include such things as tip display options, preferred browser, email client, etc, you can get access to it by sourcing the ~/.preferences file like so:

source ~/.preferences

Preferences are stored in an associative array. In order to keep the preferences file well formatted and readable, when writing new preferences please use the write_preferences function defined in /usr/lib/F123-includes/

F123Light specific overwrites for applications are in /etc/F123-Config/. This allows different behavior for applications such as irssi when called from the help menu as apposed to when it is called by the user specifically. Users will be able to customize their day to day copy of irssi as much as they want, and the chat support option from the menu will still work as designed when needed.

Also in /etc/F123-Config/ is a subdirectory called backup. This contains a copy of speechd.conf and any other files that may be necessary to reset something vital to a working state.

2 Fenrir - A Modern Console Screen Reader

2.1 Selecting Fenrir Screen Reader Branches

Sometimes you may want to try a new feature in Fenrir that has not made it to the stable release. For this, you can exit to the command line, then run the following command:


You will be presented with a list of branches in the git repository. Simply select the branch you want a and press enter. The current version of Fenrir will shut down and the version from the selected branch will start.

There are safeguards in place to make sure you do not end up with a broken Fenrir. If you hear Fenrir speaking, you can press enter to use the selected version. If you do not press enter with in 30 seconds, the computer will restart and you will be using the stable, installed version.

You can get back to your installed copy of Fenrir by selecting “stable” from the list of branches or by restarting your computer. Also, if you already know the branch you want, you can specify it on the command line and skip the menu system altogether. For example, type the following to launch Fenrir from the master branch:

select-fenrir master

2.2 Fenrir’s Source Code

2.2.1 Folder Structure

Fenrir’s source code is organized in the git tree as follows:

2.2.2 Core Classes

These core classes define the heart of Fenrir, found in src/fenrirscreenreader/core.

#start attribute [ 'default', # fg 'default', # bg False, # bold False, # italics False, # underscore False, # strikethrough False, # reverse False, # blink 'default', # fontsize 'default' # fontfamily ] #end attribute

Attribute[2] indicates whether or not the cell is bold.

environment = { 'screen': screenData, # contains the screen information, better access it using the API in cursorManager and screenManager. This will be deprecated. 'runtime': runtimeData, # contains all in "core/*" classes. its the point to communicate with the fenrir core. its very important example below. 'general': generalData, # contains the general information, better access it using the API in fenrirManager will eventually be deprecated 'settings': settingsData, # contains the settings information, better access it using the API in settingsManager. this is not going to be deprecated 'commandInfo': commandData.commandInfo, # contains global command info like last execution times, itwill be removed, as it was not used. 'commandBuffer': commandData.commandBuffer, # contains information that is needed to sored persistent, like the begin and end mark. for this we have the memoryManager now. this is going to be deprecated in fenrir 3 'input': inputData, # contains the input information, better access it using the API in inputManager. This will be deprecated. 'punctuation': punctuationData, # contains the punctuation information, better access it using the API in punctuationManager This will be deprecated. 'output': outputData, # contains the output information, better access it using the API in outputManager This will be deprecated. 'soundIcons': {}, # contains the soundicons 'bindings': {}, # contains the key bindings 'commands':{} # contains all the commands loaded by the commandManager }

example of environ usage: self.env['runtime']['outputManager'].presentText('hello world' , soundIcon='', interrupt=True) runtime contains all managers (without the .py) as dict entries, so the functions could be used there. The output manager has the method “presentText” that is called here

Get the setting dateFormat in section general using the settings manager: dateFormat = self.env['runtime']['settingsManager'].getSetting('general', 'dateFormat')

getSetting returns text. There are others to cast as bool or int. Here is an exemple for bool: isAutoReadIncomming = self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'autoReadIncoming')

Settings can also be set here. The following disables “autoReadIncomming”: self.env['runtime']['settingsManager'].setSetting('speech', 'autoReadIncoming', str(False))

most of the * should be moved to the managers in future.

2.2.3 Commands

This is the commands class used to build and work with Fenrir commands, i.e. what happens when the user presses a Fenrir key shortcut. The folder structure for building various types of commands is also found here in src/fenrirscreenreader/commands. basic functions:

  1. initialize is called on command creation. It’s an own function rather than in custructure.
  2. shutdown is called if the command is reloaded or fenrir gets shutdown (thought to clean up things)
  3. getDescription: gives a description for tutorial mode, or in case of vMenu, it’s the entry name
  4. run() is executed if the command is invoked
  5. the callback function is currently unused. It’s thought for special cases like in “sayAll,” to notify that the current word is spoken and invoke the next one, so custom usage.

It is only necessary to place a command in the folder that corresponds to the event where it should be executed. Fenrir will read all commands in the event folder and execute them in numerical order. If it is desirable to execute commands within an event folder in a specific order, place numbers at the beginning of their filenames, i.e. and

2.3 Fenrir Virtual Menus

Fenrir has a new feature that will perform key presses for you. This feature is very powerful, because it can provide easy to use shortcuts and menus that work the same across applications.

For example, if you have two editors, Nano and Vim, they save files in different ways. In F123Light, to save a file in Nano, you press control+s. In Vim, however, you must make sure you are in command mode by pressing the escape key, then enter the command :w. If Fenrir has a menu defined for both text editors, you could simply activate the menu by pressing Fenrir+F10 or Fenrir+Alt, then press f for files, and s for save.

You can also use the arrow keys and enter to select menu choices. If you open the menu and change your mind, simply press escape to close it. If you type a letter that does not exist as a menu option, Fenrir will make an error sound.

You can already try virtual menus on the Nano text editor.

2.4 Creating a Virtual menu in Fenrir

Since F123Light uses many console applications with non-standard keybindings, the virtual menu is a Fenrir add on which will translate more conventional key combinations into those unusual ones, so the end-user does not have to worry about learning entirely new keyboard shortcuts.

Fenrir is a flexible framework to create screenreaders for the commandline. It is entirely plugin driven. The virtual menu is no different, as it uses the same simple structure. Its a class named command() with 3 funktions:

  1. initialize(environment) Is invoked by fenrir while loading. The Parameter „environment“ is the complete fenrir runtime, drivers, managers, settings and all kinds of data. Its like the engine in an car. This is the most complex part. Anybody interested in additional details in this area should ask about it in: <> or <>.

  2. getDescription() returns a text spoken in tutorial mode or is used as menu entry name.

  3. run, this is fired on activation. It can access all kind of information and functionality with environment.

Especially for virtual menu, we have created a key sequencer that uses evdev key names with states. A special sequence name with the name sleep gives a small break.

The menu by itself is structured by folders. With KEY (for key devices) and BYTE for terminal emulation (using escape sequences). Above those folders is a folder per application, as shown below. The user can be locked in those applications menus using the remote manager so they will not get confused by wrong entrys)

For F123Light, the code for virtual menus resides in: /usr/share/fenrirscreenreader/menus/KEY/

Inside this directory is the actual macro structure. The Directories directly under KEY are application names that contain the menu for the application.

% ls
vim/  nano/  mutt/  mc/

Inside those directories are the actual virtual menu directories, so “file”, “Tools”, etc.

Here, from the File directory for Nano, is the save command. This activates control+S which is the Fenrir command for Nano. Description is the help text for it if you are trying to learn the keys.

# Code

#!/usr/bin/env python
# -*- encoding: utf-8
from fenrirscreenreader.core import debug

class command():
    def __init__(self):

    def initialize(self, environment):
        self.env = environment
        self.keyMakro = [[1, 'KEY_LEFTCTRL'],
                         [1, 'KEY_S'],
                         [0.05, 'SLEEP'],
                         [0, 'KEY_S'],
                         [0, 'KEY_LEFTCTRL']]

    def shutdown(self):

    def getDescription(self):
        return "Save your work."

    def run(self):
            "Okay, you will now be asked to save your work.", interrupt=True)
        if self.env['runtime']['inputManager'].getShortcutType() in ['KEY']:
        elif self.env['runtime']['inputManager'].getShortcutType() in ['BYTE']:

    def setCallback(self, callback):

# End Code

2.5 Fenrir Resources and Contacting Developers

The best places to find Fenrir contributors are:

3 Customizing the F123Light Menus

You may want to add your favorite application to the menu system for easy launching. To do this, create a file called menu under ~/.config/F123 like this:

mkdir -p ~/.config/F123
nano ~/.config/F123/menu

The process for adding a command line based application is pretty straight forward. This, for example, will add vim:

exec:Vim Text Editor::vim

Some applications require special directives to pdmenu, those that do not stay open for example, may need the pause flag. For more information, please read:

man pdmenurc 

Adding graphical applications, such as chromium takes a bit more work. To do this, we have to suspend Fenrir so that it and Orca aren’t trying to read at the same time. We then have to call the graphical application with a special script that loads all the X session components and starts the Orca screen reader. Here is an example to add lxterminal to your personal menu:

exec:::python /usr/share/fenrirscreenreader/tools/fenrir-ignore-screen &> /dev/null
exec:::echo -n "setting set screen#suspendingScreen=$(</tmp/fenrirSuspend)" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
exec:::startx /usr/lib/F123-wrappers/xlauncher lxterminal
exec:::python /usr/share/fenrirscreenreader/tools/fenrir-unignore-screen &> /dev/null
exec:::echo -n "setting set screen#suspendingScreen=$(</tmp/fenrirSuspend)" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock

Notice that there are some execs even after the lxterminal application is called. This is to restore Fenrir so it will begin reading again after the X session closes.

3.0.1 Finding Binary Application Files

You will usually find binary application files at: /usr/bin

If you are ever unsure though, the following command will show you where it is, assuming it is in your executable path:

command -v application-name

For example:

% command -v firefox

Please note that the “$” symbol is usually used to indicate the command line prompt. In F123Light, we use the “%” symbol, but this can be easily changed.

4 F123Light Modes

in order to help keep clutter down, and to make things more efficient, F123Light offers modes that change the way it presents information. For now, this mostly means different menus, but as this service grows, it could potentially change nearly every aspect of the system.

Only someone with administrative access can change modes, and only by running a command from the command line. To change modes, run the following command:

sudo /usr/lib/F123-wrappers/

You will be presented with a menu of all available modes. Just arrow to the one you want and press enter to activate it. If you already know the mode you want, simply specify it at the end of the command above.

The idea behind modes is to have a “default” mode, which only shows the most user-friendly software; a “test” mode, which might be used to administer tests in schools; and “admin” or “advanced” mode, which will give full access for those who are sophisticated users of technology; and other modes such as games, will certainly be suggested by our users.

5 Translating with GetText

To create a translation for a project, the first step is to create a .pot file.

xgettext -o name.pot -L sourceCodeLanguage file(s)

Source language can be one of C, C++, ObjectiveC, PO, Shell, Python, Lisp, EmacsLisp, librep, Scheme, Smalltalk, Java, JavaProperties, C#, awk, YCP, Tcl, Perl, PHP, GCC-source, NXStringTable, RST, Glade, Lua, JavaScript, Vala, or Desktop according to the man page. There used to be a python specific translation script called pygettext3 but it is now deprecated. After the .pot file is created, the next step is to create a .po file that contains the translation. The .po must be specified with the full language code including .UTF-8 or appropriate encoding string.

msginit -i name.pot -l pt_BR.UTF-8

The package name and copyright information should be set in the .po file. The .po file is the locale name without the .UTF-8, so in the example above, pt_BR.po.

To finally generate the .mo file, which is what actually provides the translation usable by the software, `run the following:

msgfmt -o pt_BR.po

For the .mo file to actually be used, it must be placed in the correct directory to be available to gettext. Move the .mo file as in:

mv /usr/share/locale/pt_BR/LC_MESSAGES/

6 Troubleshooting Problems

In this section we have suggestions regarding how you may investigate problems with your software. The idea is to help you figure things out on your own, or at the very least, help you find information which might allow others to help you more rapidly.

6.1 Troubleshooting update-f123light

6.1.1 Update Problems with Version 19.02.04 of F123Light

For some users, it was necessary to run the update option under the ‘Settings’ menu, twice, and then their version got correctly updated. If that does not solve your problem, you might want to research further.

6.1.2 Logs and More

You will probably find helpful details in this log:


You might also want to try this command for more potentially useful information:

pacman -Qi update-f123light-git

Finally, this command might help with updates, and if there are none, then that is good to know as well:

yay -Syu

6.2 WiFi Issues

The Raspberry Pi 3B+ works with WiFi channels 1 through 11, but some networks are configured to use channels 12 or 13. Please check if this is the case with the network giving you problems. The solution would be changing the configuration of the WiFi router so it can operate with channels 1 through 11.

Another potential problem is the frequency being used by your WiFi network. If your WiFi router uses the 5GHz band only, older Raspberry Pi models will not see it. Only the Raspberry Pi 3B Plus, is capable of handling both 2.4GHz and 5GHz. Although our software is developed and supported for the Model 3B+, sometimes people use it on older Raspberry Pis, which in this case, prevents them from accessing 5GHz WiFi networks.

7 Source Code for F123Light

F123Light is based on Arch Linux, so the following address is only relevant for the customizations our team has made to that distribution:

This document is version number: 19.05.22

This work by F123 Consulting is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. We also have another way for you to freely use our content, if this license does not meet your needs. Contact us for alternative licensing options.