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.
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:
https://public.f123.org/F123Light-release-candidate-19.04.01.img.xz
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.
Advanced users can perform an update from the command line with the command:
update-f123light
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
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:
build-f123light
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.
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.
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
done
fi
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/preferences-manager.sh.
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.
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:
select-fenrir
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
Fenrir’s source code is organized in the git tree as follows:
fenrir-daemon-pypy spawns fenrir as daemon using the faster pypy python JIT compiler which gives better performance (also used for the “global” background service to read the TTYs).
These core classes define the heart of Fenrir, found in src/fenrirscreenreader/core.
applicationManager.py Currently unused. It was initially used to detect the currently running application to automatically load application profiles, but no reliable detection method was found for applications running inside of screen or tmux.
attributeManager.py This is currently the API to handle all kinds of attribute stuff. The hilight tracking is also analyzed here, i.e. attributeManager.getAttributeByXY(0,0)
gives the attributes for the first cell and row (starting at the upper left corner on the screen). An attribute set looks like the following list:
#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.
barrierManager.py Manages the barrier feature. It chains the current window down to the configured barriers.
brailleDriver.py Is the base class for all brailleDrivers.
byteManager.py Handles byte input used in terminal emulation mode. It’s the opposite of inputManager, which consumes key press/ release events.
commandData.py This is a container to hold command information. It will be deprecated in the future.
commandManager.py loa
cursorManager.py Holds all cursor related information and handles the review cursor.
debug.py Contains the debug states (Info, warning, error)
debugManager.py produces the debug output and writes it to a file or prints it on screen.
environment.py The environment contains almost everything fenrir is, and it’s passed to every object fenrir loads, to have information available everywhere. This makes it quite easy to create plugins, as the commands get the information as well. It’s a python dictionary. It’s mostly named self.env. The only place where it is named environment is the fenrirManager class (for historical reasons). The environment looks like this:
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/*Manager.py" 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))
eventData.py An enum with all event types
eventManager.py This is the queue for events. It has some methods to add events to the queue and dispatches the events to the right places. Most of them are passed to the fenrirManager.
fenrirManager.py This is used for startup. It ties all the event cases together where they are passed to the right managers. It also checks for shortcuts and consumes the input, i.e. input event -> eventManager -> fenrirManager -> inputManager screen change event -> eventManager -> fenrirManager -> screenManager
generalData.py This is a container to hold general information. It will be deprecated in the future.
helpManager.py Creates the tutorial information and controls the navigation in tutorial mode
i18n.py Loads the gettext and translation module.
inputData.py This is a container to hold input information. It will be deprecated in the future.
inputDriver.py This is the base class for all input drivers
inputManager.py Gets key input events like “key a pressed” and “key a released” and tracks the current pressed keys. event chain: input driver (PlugInputDevice) -> eventManager -> fenrirManager -> inputManager input driver (KeyboardInput) -> eventManager -> fenrirManager -> inputManager
memoryManager.py Exists to manage persistent memory like the clipboard.
outputData.py This is a container to hold output information. It will be deprecated in the future.
outputManager.py This contains methods for playing sound icons and speaking.
processManager.py This spawns the threads needed for the drivers to progress more quickly. Fenrir is multithreaded and multiprocessed. so it can split out drivers workers to own processes to get multi cpu core power.
punctuationData.py This is a container to hold punctuation information. It will be deprecated in the future.
punctuationManager.py Prepares the punctuation for output, replaces custom dicts and removes what will not be spoken.
quickMenuManager.py Manages the NVDA like arrow menu for speech rate, volume and pitch.
remoteDriver.py The base class for remote drivers.
remoteManager.py Loads the remote drivers. Accepts and proceeds all incomming commands. event chain: remote driver (RemoteIncomming) -> eventManager -> fenrirManager -> remoteManager
runtimeData.py This is just a placeholder an will be removed.
sayAllManager.py This is a WIP for the say all functionality
screenData.py This is a container to hold screen information. It will be deprecated in the future.
screenDriver.py This is the base class for all screen drivers.
screenManager.py Creates the diff and tracks the cursor. event chain: screen driver (ScreenUpdate) -> eventManager -> fenrirManager -> screenManager screen driver (ScreenChanged) -> eventManager -> fenrirManager -> screenManager
settingsData.py Holds the default settings.
settingsManager.py The settings manager contains all methods to load, save and querry settings.
soundDriver.py Base class for sound drivers.
speechDriver.py Base class for speech drivers.
tableManager.py WIP for a table cell based review. It should speak the cellname in review mode. Example ps PID TTY 123 TTY1
it should not navigate: PID, TTY, 123, TTY1 but PID: 123, TTY: TTY1 to keep track of the current cell
textManager.py Used to manipulate the output for speech, i.e. ########## is transformed to: 10 times #
vmenuManager.py Rebinds the vMenu keys, loads the vMenu, contains the navigation for vMenu, etc.
most of the *Data.py should be moved to the managers in future.
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.
switchTrigger_template.py These are the currently disabled application profiles.
commands The commands folder contains the “normal” commands like review or say time. Just copy the commands_template.py above into it and add your specific command code. To assign the command in this folder to a keyboard binding, just assign the keys to the command filename without .py. example: Assign add_word_to_spell_check.py to 2 times fenrir + S 2,KEY_FENRIR,KEY_S=add_word_to_spell_check
fenrir will read all python files in a command folder and match the filename to the shortcut without .py. The keybindings are found in config/keyboard/.
help Contains the automatically assigned navigation for tutorial mode.
onApplicationChange All commands in this folder are triggerd in order if the current foreground application changes - currently disabled
onByteInput All commands in this folder are triggerd in order if a byte input event was fired
onCursorChange All commands in this folder are triggerd in order if the cursor position changes
onHeartBeat All commands in this folder are triggerd in order on heartbeat (a timer defined in the Fenrir code).
onKeyInput All commands in this folder are triggerd in order if a key input event was fired.
onPlugInputDevice All commands in this folder are triggerd in order if a plug input device event was fired.
onScreenChanged All commands in this folder are triggerd in order if an on screen change event was fired (i.e. as you switch from TTY3 to TTY5).
onScreenUpdate All commands in this folder are triggerd in order if an on screen update event was fired (as new text appears on the current screen).
onSwitchApplicationProfile Contains the application profiles. It matches the application by name and calls the oldApplication.unload and newApplication.load functions, currently disabled.
quickMenu Contains the NVDA quick menu navigation.
sayAll Contains the callbacks for WIP say all.
vmenu-navigation Contains the automatically assigned navigation keys for the vMenu.
vmenu-profiles Contains the vMenu structure itself.
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. 00-do-something.py and 01-do-something-else.py.
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.
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:
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: <mumble.linux-a11y.org> or <irc.linux-a11y.org>.
getDescription() returns a text spoken in tutorial mode or is used as menu entry name.
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):
pass
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):
pass
def getDescription(self):
return "Save your work."
def run(self):
self.env['runtime']['outputManager'].presentText(
"Okay, you will now be asked to save your work.", interrupt=True)
if self.env['runtime']['inputManager'].getShortcutType() in ['KEY']:
self.env['runtime']['inputManager'].sendKeys(self.keyMakro)
elif self.env['runtime']['inputManager'].getShortcutType() in ['BYTE']:
self.env['runtime']['byteManager'].sendBytes(self.byteMakro)
def setCallback(self, callback):
pass
# End Code
The best places to find Fenrir contributors are:
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:
group:LXTerminal
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
endgroup
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.
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
/usr/bin/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.
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/change-mode.sh
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.
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.
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.
You will probably find helpful details in this log:
/var/log/update-f123light.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
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.
F123Light is based on Arch Linux, so the following address is only relevant for the customizations our team has made to that distribution:
https://gitlab.com/f123/
This document is version number: 19.04.02
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.