Merge branch 'event'
- use eventLoop - add watchdogs - add list in tutorial mode - rewrite command detection - cleanups - autoencoding - a lot of other stuff i forgott
This commit is contained in:
commit
8fdcbdde78
@ -6,13 +6,14 @@ This software is licensed under the LGPL v3 .
|
|||||||
# Requirements (core)
|
# Requirements (core)
|
||||||
- linux (currently only screen and input drivers available for that)
|
- linux (currently only screen and input drivers available for that)
|
||||||
- python3 >= 3.3
|
- python3 >= 3.3
|
||||||
- python-configargparse
|
- python-configargparse
|
||||||
- screen, input, speech, sound or braille drivers see "Features, Drivers, Extras".
|
- screen, input, speech, sound or braille drivers see "Features, Drivers, Extras".
|
||||||
|
|
||||||
# Features, Drivers, Extras, Dependencys
|
# Features, Drivers, Extras, Dependencys
|
||||||
# Input Drivers:
|
# Input Drivers:
|
||||||
1. "evdevDriver" input driver for linux evdev
|
1. "evdevDriver" input driver for linux evdev
|
||||||
- python-evdev >=0.6.3
|
- python-evdev >=0.6.3
|
||||||
|
- python-pyudev
|
||||||
- This is commonly referred to as python3-evdev by your distribution
|
- This is commonly referred to as python3-evdev by your distribution
|
||||||
- loaded uinput kernel module
|
- loaded uinput kernel module
|
||||||
- ReadWrite permission
|
- ReadWrite permission
|
||||||
|
94
TODO v1.5
Normal file
94
TODO v1.5
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
ToDo list for Fenrir Version 1.5
|
||||||
|
Things with not so deep knowledge needed are marekd wiht "(Easy for contribution)". so just start with that :).
|
||||||
|
|
||||||
|
General:
|
||||||
|
- Migrate *Data.py to classes and use getter/setter (Easy for contribution)
|
||||||
|
commandsData.py
|
||||||
|
eventData.py
|
||||||
|
generalData.py
|
||||||
|
inputData.py
|
||||||
|
outputData.py
|
||||||
|
punctuationData.py
|
||||||
|
runtimeData.py
|
||||||
|
screenData.py
|
||||||
|
settingsData -> defaultSettings.py
|
||||||
|
|
||||||
|
Fix Bugs:
|
||||||
|
- device detection is broken
|
||||||
|
- arrow up/down announcement is broken
|
||||||
|
- let drivers choos between threads and process
|
||||||
|
- HilightTracking is broken for autoencoding
|
||||||
|
|
||||||
|
-----------DONE----------------
|
||||||
|
- Doku: Write a user wiki
|
||||||
|
https://wiki.linux-a11y.org/doku.php?id=fenrir_user_manual&s[]=fenrir
|
||||||
|
|
||||||
|
- initial working setup.py
|
||||||
|
|
||||||
|
- leave review on typing
|
||||||
|
|
||||||
|
- add dependency check (check-dependencys.py)
|
||||||
|
|
||||||
|
- Add nice dummy drivers as template or for debugging
|
||||||
|
|
||||||
|
- reimplement detection code for X11
|
||||||
|
|
||||||
|
- initial translate structure (manuelcortez Thanks!)
|
||||||
|
http://www.supernifty.org/blog/2011/09/16/python-localization-made-easy/
|
||||||
|
|
||||||
|
- add a configurable place where you can place own commands or overwrite existing commands without need to change default code
|
||||||
|
|
||||||
|
- implement autodetection of plugged and unplugged input devices (python-pyudev) for evdev driver
|
||||||
|
http://stackoverflow.com/questions/22678686/python-script-to-detect-hot-plug-event
|
||||||
|
http://askubuntu.com/questions/508236/how-can-i-run-code-whenever-a-usb-device-is-unplugged-without-requiring-root
|
||||||
|
https://www.mattfischer.com/blog/?p=182
|
||||||
|
|
||||||
|
- implement speechdriver generic (Easy for contribution)
|
||||||
|
|
||||||
|
- try to autodetect encoding (Easy for contribution) (Prototype "charmapTTY" in play zone)
|
||||||
|
https://stackoverflow.com/questions/6396659/how-do-you-get-the-encoding-of-the-terminal-from-within-a-python-script
|
||||||
|
|
||||||
|
Braille Support (WIP):
|
||||||
|
initial BrlTTY driver
|
||||||
|
detect device size via driver
|
||||||
|
output to braille device
|
||||||
|
make flushMode configurable
|
||||||
|
make flushTimeout configurable
|
||||||
|
flush message after X seconds and show current line (review over text)
|
||||||
|
tweak current commands and output
|
||||||
|
command flush_braille
|
||||||
|
command for scroll left
|
||||||
|
command for scroll right
|
||||||
|
create offset for scrolling
|
||||||
|
respect scrolling
|
||||||
|
make cursor following configurable (brailleCursorTrackingMode)
|
||||||
|
- cell
|
||||||
|
- page
|
||||||
|
follow cursor while typing
|
||||||
|
brailleFocusMode:
|
||||||
|
- review = priority to review
|
||||||
|
|
||||||
|
- initial try to make it more asynchronus with multpible threads
|
||||||
|
|
||||||
|
- be more event based (vcsa sets POLLPRI)
|
||||||
|
http://scotdoyle.com/python-epoll-howto.html
|
||||||
|
Needed events:
|
||||||
|
screen update (vcsa sets POLLPRI)
|
||||||
|
plug input device (udev event)
|
||||||
|
screen changed (logind event, collides with screen update)
|
||||||
|
keyboard input (select, wait forever)
|
||||||
|
braille input (brlapi_readKey)
|
||||||
|
braille flush (timer, sleep)
|
||||||
|
Each event is watched in an own thread. This improves performance and reduce the load.
|
||||||
|
The event loop is to be done as "queue" since those are thread safe.
|
||||||
|
The threads are reading incomming data and add the events and data to the queue
|
||||||
|
the mainloop just reads the queue in an blocking way and executes the needed codepath with the data.
|
||||||
|
clean up the code for the events so that just the correct codepath is used:
|
||||||
|
- screen
|
||||||
|
- input
|
||||||
|
- new device
|
||||||
|
|
||||||
|
Settings:
|
||||||
|
- configuration should be overwritable with parameter and alternative paths (Easy for contribution)
|
||||||
|
Tutorial Mode:
|
||||||
|
- navigate through a list of bound commands. speak binding and description.
|
65
TODO v2.0
65
TODO v2.0
@ -4,27 +4,12 @@ Things with not so deep knowledge needed are marekd wiht "(Easy for contribution
|
|||||||
General:
|
General:
|
||||||
- implement onScreenUpdate commands
|
- implement onScreenUpdate commands
|
||||||
read highlighted text mode
|
read highlighted text mode
|
||||||
- try to make it more asynchronus with multpible threads
|
|
||||||
- be more event based (vcsa sets POLLPRI)
|
|
||||||
http://scotdoyle.com/python-epoll-howto.html
|
|
||||||
Needed events:
|
|
||||||
screen update (vcsa sets POLLPRI)
|
|
||||||
plug input device (udev event)
|
|
||||||
screen changed (logind event, collides with screen update)
|
|
||||||
keyboard input (select, wait forever)
|
|
||||||
braille input (brlapi_readKey)
|
|
||||||
braille flush (timer, sleep)
|
|
||||||
Each event is watched in an own thread. This improves performance and reduce the load.
|
|
||||||
The event loop is to be done as "queue" since those are thread safe.
|
|
||||||
The threads are reading incomming data and add the events and data to the queue
|
|
||||||
the mainloop just reads the queue in an blocking way and executes the needed codepath with the data.
|
|
||||||
- leave review on typing
|
|
||||||
|
|
||||||
- implement commands
|
- implement commands
|
||||||
Tutorial Mode: navigate through a list of bound commands. speak binding and description.
|
|
||||||
attributes_curr_char (Easy for contribution)
|
attributes_curr_char (Easy for contribution)
|
||||||
https://github.com/jwilk/vcsapeek/blob/master/linuxvt.py
|
https://github.com/jwilk/vcsapeek/blob/master/linuxvt.py
|
||||||
- generic list (convert clipboard management) (Easy for contribution)
|
|
||||||
|
- generic list or see Tutorial mode list (convert clipboard management) (Easy for contribution)
|
||||||
next item
|
next item
|
||||||
pref item
|
pref item
|
||||||
curr item
|
curr item
|
||||||
@ -54,19 +39,21 @@ Driver:
|
|||||||
https://docs.python.org/3.2/library/pty.html
|
https://docs.python.org/3.2/library/pty.html
|
||||||
http://sqizit.bartletts.id.au/2011/02/14/pseudo-terminals-in-python/
|
http://sqizit.bartletts.id.au/2011/02/14/pseudo-terminals-in-python/
|
||||||
https://blog.konpat.me/pythons-pseudo-terminal-pty-examples/
|
https://blog.konpat.me/pythons-pseudo-terminal-pty-examples/
|
||||||
|
|
||||||
- implement PTY Input driver
|
- implement PTY Input driver
|
||||||
|
|
||||||
- ATK input driver (don't grab on graphical interface)
|
- ATK input driver (don't grab on graphical interface)
|
||||||
https://git.linux-a11y.org/AIT/pyatspi2/src/master/examples/keypress.py
|
https://git.linux-a11y.org/AIT/pyatspi2/src/master/examples/keypress.py
|
||||||
- try to autodetect encoding (Easy for contribution) (Prototype "charmapTTY" in play zone)
|
|
||||||
https://stackoverflow.com/questions/6396659/how-do-you-get-the-encoding-of-the-terminal-from-within-a-python-script
|
- Dectalk SpeechDriver (Easy for contribution, device needed - i dont own one)
|
||||||
- Dectalk SpeechDriver
|
|
||||||
https://github.com/tvraman/emacspeak/blob/master/servers/obsolete/python/dectalk.py
|
https://github.com/tvraman/emacspeak/blob/master/servers/obsolete/python/dectalk.py
|
||||||
|
|
||||||
Settings:
|
Settings:
|
||||||
- write settings (Easy for contribution)
|
- write settings (Easy for contribution)
|
||||||
|
|
||||||
- menue for settings configuration (Easy for contribution)
|
- menue for settings configuration (Easy for contribution)
|
||||||
|
|
||||||
Application Profiles
|
Application Profiles (low priority):
|
||||||
- reimplement process detection without subprocessing // this is started by chrys
|
- reimplement process detection without subprocessing // this is started by chrys
|
||||||
- fenrir is not able to detect the current application inside of screen.
|
- fenrir is not able to detect the current application inside of screen.
|
||||||
ps -e -H -o pid,pgrp,ppid,tty,cmd
|
ps -e -H -o pid,pgrp,ppid,tty,cmd
|
||||||
@ -80,38 +67,8 @@ Application Profiles
|
|||||||
- per application shortcuts
|
- per application shortcuts
|
||||||
|
|
||||||
-----------DONE----------------
|
-----------DONE----------------
|
||||||
- initial working setup.py
|
General:
|
||||||
- add dependency check (check-dependencys.py)
|
|
||||||
- Add nice dummy drivers as template or for debugging
|
|
||||||
- reimplement detection code for X11
|
|
||||||
- initial translate structure (manuelcortez Thanks!)
|
|
||||||
http://www.supernifty.org/blog/2011/09/16/python-localization-made-easy/
|
|
||||||
- add a configurable place where you can place own commands or overwrite existing commands without need to change default code
|
|
||||||
- implement autodetection of plugged and unplugged input devices (python-pyudev) for evdev driver
|
|
||||||
http://stackoverflow.com/questions/22678686/python-script-to-detect-hot-plug-event
|
|
||||||
http://askubuntu.com/questions/508236/how-can-i-run-code-whenever-a-usb-device-is-unplugged-without-requiring-root
|
|
||||||
https://www.mattfischer.com/blog/?p=182
|
|
||||||
- implement speechdriver generic (Easy for contribution)
|
|
||||||
|
|
||||||
Braille Support:
|
Braille Support:
|
||||||
initial BrlTTY driver
|
Driver:
|
||||||
detect device size via driver
|
|
||||||
output to braille device
|
|
||||||
make flushMode configurable
|
|
||||||
make flushTimeout configurable
|
|
||||||
flush message after X seconds and show current line (review over text)
|
|
||||||
tweak current commands and output
|
|
||||||
command flush_braille
|
|
||||||
command for scroll left
|
|
||||||
command for scroll right
|
|
||||||
create offset for scrolling
|
|
||||||
respect scrolling
|
|
||||||
make cursor following configurable (brailleCursorTrackingMode)
|
|
||||||
- cell
|
|
||||||
- page
|
|
||||||
follow cursor while typing
|
|
||||||
brailleFocusMode:
|
|
||||||
- review = priority to review
|
|
||||||
|
|
||||||
Settings:
|
Settings:
|
||||||
- configuration should be overwritable with parameter and alternative paths (Easy for contribution)
|
Application Profiles:
|
||||||
|
@ -79,6 +79,12 @@ try:
|
|||||||
except:
|
except:
|
||||||
print('python3-evdev: FAIL')
|
print('python3-evdev: FAIL')
|
||||||
available = available and False
|
available = available and False
|
||||||
|
try:
|
||||||
|
import pyudev
|
||||||
|
print('python3-pyudev: OK')
|
||||||
|
except:
|
||||||
|
print('python3-pyudev: FAIL')
|
||||||
|
available = available and False
|
||||||
if available:
|
if available:
|
||||||
currentInstallation.append('evdevDriver')
|
currentInstallation.append('evdevDriver')
|
||||||
# SOUND
|
# SOUND
|
||||||
|
@ -117,7 +117,7 @@ panSizeHorizontal=0
|
|||||||
|
|
||||||
[screen]
|
[screen]
|
||||||
driver=vcsaDriver
|
driver=vcsaDriver
|
||||||
encoding=UTF-8
|
encoding=auto
|
||||||
screenUpdateDelay=0.05
|
screenUpdateDelay=0.05
|
||||||
suspendingScreen=
|
suspendingScreen=
|
||||||
autodetectSuspendingScreen=True
|
autodetectSuspendingScreen=True
|
||||||
@ -163,7 +163,7 @@ dateFormat=%A, %B %d, %Y
|
|||||||
autoSpellCheck=True
|
autoSpellCheck=True
|
||||||
spellCheckLanguage=en_US
|
spellCheckLanguage=en_US
|
||||||
scriptPath=/usr/share/fenrir/scripts
|
scriptPath=/usr/share/fenrir/scripts
|
||||||
commandPath=/usr/share/fenrir/commands
|
commandPath=
|
||||||
|
|
||||||
[focus]
|
[focus]
|
||||||
cursor=True
|
cursor=True
|
||||||
@ -173,7 +173,7 @@ highlight=False
|
|||||||
lineBreak=True
|
lineBreak=True
|
||||||
endOfScreen=True
|
endOfScreen=True
|
||||||
# leave the review when pressing a key
|
# leave the review when pressing a key
|
||||||
leaveReviewOnKeypress=False
|
leaveReviewOnCursorChange=True
|
||||||
# leave the review when changing the screen
|
# leave the review when changing the screen
|
||||||
leaveReviewOnScreenChange=True
|
leaveReviewOnScreenChange=True
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ panSizeHorizontal=0
|
|||||||
|
|
||||||
[screen]
|
[screen]
|
||||||
driver=vcsaDriver
|
driver=vcsaDriver
|
||||||
encoding=cp850
|
encoding=auto
|
||||||
screenUpdateDelay=0.05
|
screenUpdateDelay=0.05
|
||||||
suspendingScreen=
|
suspendingScreen=
|
||||||
autodetectSuspendingScreen=True
|
autodetectSuspendingScreen=True
|
||||||
@ -147,7 +147,7 @@ interruptOnKeyPressFilter=
|
|||||||
doubleTapTimeout=0.2
|
doubleTapTimeout=0.2
|
||||||
|
|
||||||
[general]
|
[general]
|
||||||
debugLevel=1
|
debugLevel=0
|
||||||
punctuationProfile=default
|
punctuationProfile=default
|
||||||
punctuationLevel=some
|
punctuationLevel=some
|
||||||
respectPunctuationPause=True
|
respectPunctuationPause=True
|
||||||
@ -168,7 +168,7 @@ spellCheckLanguage=en_US
|
|||||||
# path for your scripts "scriptKey" functionality
|
# path for your scripts "scriptKey" functionality
|
||||||
scriptPath=/usr/share/fenrir/scripts
|
scriptPath=/usr/share/fenrir/scripts
|
||||||
# overload commands, and create new one without changing Fenrir default
|
# overload commands, and create new one without changing Fenrir default
|
||||||
commandPath=/usr/share/fenrir/commands
|
commandPath=
|
||||||
|
|
||||||
[focus]
|
[focus]
|
||||||
#follow the text cursor
|
#follow the text cursor
|
||||||
@ -180,7 +180,7 @@ highlight=False
|
|||||||
lineBreak=True
|
lineBreak=True
|
||||||
endOfScreen=True
|
endOfScreen=True
|
||||||
# leave the review when pressing a key
|
# leave the review when pressing a key
|
||||||
leaveReviewOnKeypress=False
|
leaveReviewOnCursorChange=True
|
||||||
# leave the review when changing the screen
|
# leave the review when changing the screen
|
||||||
leaveReviewOnScreenChange=True
|
leaveReviewOnScreenChange=True
|
||||||
|
|
||||||
|
@ -76,10 +76,10 @@ panSizeHorizontal=0
|
|||||||
|
|
||||||
[screen]
|
[screen]
|
||||||
driver=vcsaDriver
|
driver=vcsaDriver
|
||||||
encoding=cp850
|
encoding=auto
|
||||||
screenUpdateDelay=0.05
|
screenUpdateDelay=0.05
|
||||||
suspendingScreen=7
|
suspendingScreen=
|
||||||
autodetectSuspendingScreen=False
|
autodetectSuspendingScreen=True
|
||||||
|
|
||||||
[keyboard]
|
[keyboard]
|
||||||
driver=evdevDriver
|
driver=evdevDriver
|
||||||
@ -116,7 +116,7 @@ autoSpellCheck=True
|
|||||||
spellCheckLanguage=en_US
|
spellCheckLanguage=en_US
|
||||||
scriptPath=/usr/share/fenrir/scripts
|
scriptPath=/usr/share/fenrir/scripts
|
||||||
# overload commands, and create new one without changing Fenrir default
|
# overload commands, and create new one without changing Fenrir default
|
||||||
commandPath=/usr/share/fenrir/commands
|
commandPath=
|
||||||
|
|
||||||
[focus]
|
[focus]
|
||||||
#follow the text cursor
|
#follow the text cursor
|
||||||
@ -128,7 +128,7 @@ highlight=False
|
|||||||
lineBreak=True
|
lineBreak=True
|
||||||
endOfScreen=True
|
endOfScreen=True
|
||||||
# leave the review when pressing a key
|
# leave the review when pressing a key
|
||||||
leaveReviewOnKeypress=False
|
leaveReviewOnCursorChange=True
|
||||||
# leave the review when changing the screen
|
# leave the review when changing the screen
|
||||||
leaveReviewOnScreenChange=True
|
leaveReviewOnScreenChange=True
|
||||||
|
|
||||||
|
244
docu/user.txt
244
docu/user.txt
@ -13,7 +13,7 @@ Fenrir requires several drivers to interact with the operating system.
|
|||||||
|
|
||||||
===== Speech Drivers =====
|
===== Speech Drivers =====
|
||||||
|
|
||||||
A speech driver is for communication with the text to speech system like [[speech-dispatcher|Speech-dispatcher]] or [[espeak|Espeak]]. \\
|
A speech driver is for communication with the text to speech system like [[#SpeechDispatcher|Speech-Dispatcher]] or [[http://espeak.sourceforge.net|Espeak]]. \\
|
||||||
See section [[#Speech|Speech]] in ''settings.conf'' for more information.
|
See section [[#Speech|Speech]] in ''settings.conf'' for more information.
|
||||||
|
|
||||||
|
|
||||||
@ -26,10 +26,18 @@ Dependency's:
|
|||||||
|
|
||||||
* speech-dispatcher (installed and configured, [[https://devel.freebsoft.org/speechd#sec2|Documentation]])
|
* speech-dispatcher (installed and configured, [[https://devel.freebsoft.org/speechd#sec2|Documentation]])
|
||||||
* python-speechd
|
* python-speechd
|
||||||
|
|
||||||
|
==== Espeak ====
|
||||||
|
|
||||||
|
Uses espeak via python bindings.
|
||||||
|
|
||||||
|
Dependency's:
|
||||||
|
* Espeak or Espeak-ng
|
||||||
|
* [[https://launchpad.net/python-espeak|python-espeak]]
|
||||||
|
|
||||||
==== Generic ====
|
==== Generic ====
|
||||||
|
|
||||||
This invokes speech via a sub-process. This is almost the same as entering the command by commandline. The performance depends on the overhead of the speech syntheses application but it is really flexible.
|
This invokes speech via a sub-process. This is almost the same as entering the command by commandline. The performance depends on the overhead of the speech synthesis application but it is really flexible.
|
||||||
|
|
||||||
Dependency's:
|
Dependency's:
|
||||||
* Espeak or Espeak-ng
|
* Espeak or Espeak-ng
|
||||||
@ -132,7 +140,7 @@ Fenrir can run without installation. It just requires the dependencies to be ins
|
|||||||
We recommend to try it out before installation to be sure everything works and prevent yourself from experiencing a non-talking environment.
|
We recommend to try it out before installation to be sure everything works and prevent yourself from experiencing a non-talking environment.
|
||||||
|
|
||||||
===== Try Out =====
|
===== Try Out =====
|
||||||
Fenrir does not require installation. You can try out if everything works before you want to install. In this way you can be sure that your system doesnt break or does not talking.
|
Fenrir does not require installation. You can try it and make sure everything works before you decide to install. In this way you can be sure that your system doesnt break or stop talking.
|
||||||
for that you can just grab the code and run as root ''src/fenrir/fenrir'' (in foreground) or ''src/fenrir/fenrir-daemon'' (in background, that one is used by systemd for autostart)
|
for that you can just grab the code and run as root ''src/fenrir/fenrir'' (in foreground) or ''src/fenrir/fenrir-daemon'' (in background, that one is used by systemd for autostart)
|
||||||
|
|
||||||
===== Install it =====
|
===== Install it =====
|
||||||
@ -149,7 +157,8 @@ For Arch there are PKGBUILDs in the AUR:
|
|||||||
|
|
||||||
- Download the latest stable version from the [[https://linux-a11y.org/index.php?page=fenrir-screenreader|Fenrir-Project]] site.
|
- Download the latest stable version from the [[https://linux-a11y.org/index.php?page=fenrir-screenreader|Fenrir-Project]] site.
|
||||||
- Unpack the archive
|
- Unpack the archive
|
||||||
- install the needed Dependencys an standard installation requires the following.
|
- Check the needed Dependencys by running [[https://github.com/chrys87/fenrir/blob/master/check-dependencys.py|check-dependencys.py]] script
|
||||||
|
- install the needed missing dependencys an standard installation requires the following:
|
||||||
* python3 >= 3.3 (and all the following is needed for python3 )
|
* python3 >= 3.3 (and all the following is needed for python3 )
|
||||||
* python3-speechd (screen)
|
* python3-speechd (screen)
|
||||||
* python3-dbus (screen)
|
* python3-dbus (screen)
|
||||||
@ -159,7 +168,7 @@ For Arch there are PKGBUILDs in the AUR:
|
|||||||
* python3-pyenchant (spellchecker)
|
* python3-pyenchant (spellchecker)
|
||||||
* your language for aspell (aspell-<lang>) (spellchecker)
|
* your language for aspell (aspell-<lang>) (spellchecker)
|
||||||
* sox (sound)
|
* sox (sound)
|
||||||
* For an individual installation see [[#Support and Requirements|Support and Requirements]] or cunsult the [[https://github.com/chrys87/fenrir/blob/master/README.md|Readme]])
|
* For an individual installation see [[#Support and Requirements|Support and Requirements]] or consult the [[https://github.com/chrys87/fenrir/blob/master/README.md|Readme]])
|
||||||
- run "install.sh" as root
|
- run "install.sh" as root
|
||||||
|
|
||||||
this installs fenrir as the following
|
this installs fenrir as the following
|
||||||
@ -186,21 +195,22 @@ To enable auto start on system boot:
|
|||||||
====== First Steps ======
|
====== First Steps ======
|
||||||
|
|
||||||
If you are using Fenrir for the first time you may want to take a look at these resources:
|
If you are using Fenrir for the first time you may want to take a look at these resources:
|
||||||
* [[#Keyindings|Keyindings]]
|
* [[#Keybindings|Keybindings]]
|
||||||
* [[#Tutorial Mode|Tutorial Mode]]
|
* [[#Tutorial Mode|Tutorial Mode]]
|
||||||
|
|
||||||
====== Features ======
|
====== Features ======
|
||||||
|
|
||||||
===== Commands =====
|
===== Commands =====
|
||||||
|
|
||||||
==== Keyindings ====
|
==== Keybindings ====
|
||||||
|
|
||||||
Normal commands can invoked in to ways:
|
Normal commands can be invoked in two ways:
|
||||||
- Using a Metakey ([[#Fenrir Key|FenrirKey]])
|
- Using a Metakey ([[#Fenrir Key|FenrirKey]])
|
||||||
- Shortcuts with an single key
|
- Shortcuts with a single key
|
||||||
|
|
||||||
|
See section [[#Keyboard|Keyboard]] in ''settings.conf'' for more information.
|
||||||
=== Fenrir Key ===
|
=== Fenrir Key ===
|
||||||
The Fenrir Key is for invoking screen reader commands. Fenrir can handle more than one Key as FenrirKey at the same time.
|
The Fenrir Key is for invoking screen reader commands. Fenrir can utilize more than one FenrirKey at the same time.
|
||||||
By default the following keys are used:
|
By default the following keys are used:
|
||||||
- Insert
|
- Insert
|
||||||
- KeyPad Insert
|
- KeyPad Insert
|
||||||
@ -208,7 +218,7 @@ By default the following keys are used:
|
|||||||
|
|
||||||
=== Script Key ===
|
=== Script Key ===
|
||||||
To invoke "Scripts" the Script Key is mandatory. The shortcut is encoded in the filename of the script. See [[#Scripting|Scripting]]
|
To invoke "Scripts" the Script Key is mandatory. The shortcut is encoded in the filename of the script. See [[#Scripting|Scripting]]
|
||||||
===Desktop Layout===
|
=== Desktop Layout ===
|
||||||
^Shortcut ^Command ^
|
^Shortcut ^Command ^
|
||||||
|FenrirKey + H|[[#Tutorial Mode|toggle tutorial mode]]|
|
|FenrirKey + H|[[#Tutorial Mode|toggle tutorial mode]]|
|
||||||
|CTRL|[[#shut up|shut up (interrupts speech)]]|
|
|CTRL|[[#shut up|shut up (interrupts speech)]]|
|
||||||
@ -317,6 +327,8 @@ To invoke "Scripts" the Script Key is mandatory. The shortcut is encoded in the
|
|||||||
|FenrirKey + Shift + C|[[#read current clipboard|current clipboard]]|
|
|FenrirKey + Shift + C|[[#read current clipboard|current clipboard]]|
|
||||||
|FenrirKey + C|[[#copy marked to clipboard|copy marked text to clipboard]]|
|
|FenrirKey + C|[[#copy marked to clipboard|copy marked text to clipboard]]|
|
||||||
|FenrirKey + V|[[#paste clipboard|paste clipboard contents]]|
|
|FenrirKey + V|[[#paste clipboard|paste clipboard contents]]|
|
||||||
|
|FenrirKey + P|[[#import clipboard from file|import clipboard from file]]|
|
||||||
|
|FenrirKey + Alt + Shift +C|[[#export clipboard to file|export clipboard to file]]|
|
||||||
|FenrirKey + CTRL + Shift + X|[[#Remove Marks|remove marks]]|
|
|FenrirKey + CTRL + Shift + X|[[#Remove Marks|remove marks]]|
|
||||||
|FenrirKey + X|[[#Set mark|set mark]]|
|
|FenrirKey + X|[[#Set mark|set mark]]|
|
||||||
|FenrirKey + Shift + X|[[#Get text between marks|announce marked text]]|
|
|FenrirKey + Shift + X|[[#Get text between marks|announce marked text]]|
|
||||||
@ -324,8 +336,8 @@ To invoke "Scripts" the Script Key is mandatory. The shortcut is encoded in the
|
|||||||
|<Unbound>|export clipboard to X|
|
|<Unbound>|export clipboard to X|
|
||||||
|FenrirKey + CTRL + Up|include Alsa volume|
|
|FenrirKey + CTRL + Up|include Alsa volume|
|
||||||
|FenrirKey + CTRL + Down|decrease Alsa volume|
|
|FenrirKey + CTRL + Down|decrease Alsa volume|
|
||||||
|
|
||||||
===Laptop Layout===
|
=== Laptop Layout ===
|
||||||
^Shortcut ^Command ^
|
^Shortcut ^Command ^
|
||||||
|FenrirKey + H|[[#Tutorial Mode|toggle tutorial mode]]|
|
|FenrirKey + H|[[#Tutorial Mode|toggle tutorial mode]]|
|
||||||
|CTRL|[[#shut up|shut up (interrupts speech)]]|
|
|CTRL|[[#shut up|shut up (interrupts speech)]]|
|
||||||
@ -335,7 +347,7 @@ To invoke "Scripts" the Script Key is mandatory. The shortcut is encoded in the
|
|||||||
|FenrirKey + U|[[#review previous line|reviews previous line]]|
|
|FenrirKey + U|[[#review previous line|reviews previous line]]|
|
||||||
|FenrirKey + O|[[#review next line|reviews next line]]|
|
|FenrirKey + O|[[#review next line|reviews next line]]|
|
||||||
|FenrirKey + Shift + J|[[#review line beginning|reviews line beginning]]|
|
|FenrirKey + Shift + J|[[#review line beginning|reviews line beginning]]|
|
||||||
|FenrirKey + SHFIT + L|[[#review line ending|reviews line ending]]|
|
|FenrirKey + Shift + L|[[#review line ending|reviews line ending]]|
|
||||||
|FenrirKey + CTRL + J|[[#review line first character|reviews line first character]]|
|
|FenrirKey + CTRL + J|[[#review line first character|reviews line first character]]|
|
||||||
|FenrirKey + CTRL + L|[[#review line last character|reviews line last character]]|
|
|FenrirKey + CTRL + L|[[#review line last character|reviews line last character]]|
|
||||||
|FenrirKey + Alt + 1|[[#present first line|presents first line]]|
|
|FenrirKey + Alt + 1|[[#present first line|presents first line]]|
|
||||||
@ -343,15 +355,15 @@ To invoke "Scripts" the Script Key is mandatory. The shortcut is encoded in the
|
|||||||
|FenrirKey + K|[[#review current word|reviews current word]]|
|
|FenrirKey + K|[[#review current word|reviews current word]]|
|
||||||
|FenrirKey + J|[[#review previous word|reviews previous word]]|
|
|FenrirKey + J|[[#review previous word|reviews previous word]]|
|
||||||
|FenrirKey + L|[[#review next word|reviews next word]]|
|
|FenrirKey + L|[[#review next word|reviews next word]]|
|
||||||
|2 * FenrirKey + K|[[#review current word phonetic|reviews current word phonetic]]|
|
|FenrirKey + CTRL + ALT + K|[[#review current word phonetic|reviews current word phonetic]]|
|
||||||
|2 * FenrirKey + J|[[#review previous word phonetic|reviews previous word phonetic]]|
|
|FenrirKey + CTRL + ALT + J|[[#review previous word phonetic|reviews previous word phonetic]]|
|
||||||
|2 * FenrirKey + L|[[#review next word phonetic|reviews next word phonetic]]|
|
|FenrirKey + CTRL + ALT + L|[[#review next word phonetic|reviews next word phonetic]]|
|
||||||
|FenrirKey + comma|[[#review current character|reviews current char]]|
|
|FenrirKey + comma|[[#review current character|reviews current character]]|
|
||||||
|FenrirKey + M|[[#review previous character|reviews previous char]]|
|
|FenrirKey + M|[[#review previous character|reviews previous character]]|
|
||||||
|FenrirKey + dot|[[#review next character|reviews next char]]|
|
|FenrirKey + dot|[[#review next character|reviews next character]]|
|
||||||
|2 * FenrirKey + comma|[[#review current character phonetic|reviews current character phonetic]]|
|
|FenrirKey + CTRL + ALT + comma|[[#review current character phonetic|reviews current character phonetic]]|
|
||||||
|2 * FenrirKey + M|[[#review previous character phonetic|reviews previous character phonetic]]|
|
|FenrirKey + CTRL + ALT + M|[[#review previous character phonetic|reviews previous character phonetic]]|
|
||||||
|2 * FenrirKey + dot|[[#review next character phonetic|reviews next character phonetic]]|
|
|FenrirKey + CTRL + ALT + dot|[[#review next character phonetic|reviews next character phonetic]]|
|
||||||
|FenrirKey + CTRL + I|[[#review up|reviews up]]|
|
|FenrirKey + CTRL + I|[[#review up|reviews up]]|
|
||||||
|FenrirKey + CTRL + comma|[[#review down|reviews down]]|
|
|FenrirKey + CTRL + comma|[[#review down|reviews down]]|
|
||||||
|FenrirKey + Slash|[[#exit review|exit review]]|
|
|FenrirKey + Slash|[[#exit review|exit review]]|
|
||||||
@ -434,6 +446,8 @@ To invoke "Scripts" the Script Key is mandatory. The shortcut is encoded in the
|
|||||||
|FenrirKey + Shift + C|[[#read current clipboard|current clipboard]]|
|
|FenrirKey + Shift + C|[[#read current clipboard|current clipboard]]|
|
||||||
|FenrirKey + C|[[#copy marked to clipboard|copy marked text to clipboard]]|
|
|FenrirKey + C|[[#copy marked to clipboard|copy marked text to clipboard]]|
|
||||||
|FenrirKey + V|[[#paste clipboard|paste clipboard contents]]|
|
|FenrirKey + V|[[#paste clipboard|paste clipboard contents]]|
|
||||||
|
|FenrirKey + F5|[[#import clipboard from file|import clipboard from file]]|
|
||||||
|
|FenrirKey + Alt + Shift +C|[[#export clipboard to file|export clipboard to file]]|
|
||||||
|FenrirKey + CTRL + Shift + X|[[#Remove Marks|remove marks]]|
|
|FenrirKey + CTRL + Shift + X|[[#Remove Marks|remove marks]]|
|
||||||
|FenrirKey + X|[[#Set mark|set mark]]|
|
|FenrirKey + X|[[#Set mark|set mark]]|
|
||||||
|FenrirKey + Shift + X|[[#Get text between marks|announce marked text]]|
|
|FenrirKey + Shift + X|[[#Get text between marks|announce marked text]]|
|
||||||
@ -544,6 +558,10 @@ Read the content of the current element of the clipboard list
|
|||||||
== paste clipboard ==
|
== paste clipboard ==
|
||||||
Past whatever element is currently selected by first, last, prev or next clipboard commands.
|
Past whatever element is currently selected by first, last, prev or next clipboard commands.
|
||||||
if no special clipboard is selected the first one (last copied) is used.
|
if no special clipboard is selected the first one (last copied) is used.
|
||||||
|
== export clipboard to file ==
|
||||||
|
This allows you to export the current clipboard to an configurable filepath. This is useful to share the clipboard with a graphical desktop.
|
||||||
|
== import clipboard from file ==
|
||||||
|
Import a clipboard from an configurable file. This is useful to share the clipboard with a graphical desktop.
|
||||||
==== Quick Settings ====
|
==== Quick Settings ====
|
||||||
Fenrir provides some shortcuts to change settings temporarily and on the fly without need to permanently change the ''settings.conf'' file.
|
Fenrir provides some shortcuts to change settings temporarily and on the fly without need to permanently change the ''settings.conf'' file.
|
||||||
=== toggle braille ===
|
=== toggle braille ===
|
||||||
@ -768,29 +786,43 @@ speaks an _ as "line".
|
|||||||
speaks an _ as underscore.
|
speaks an _ as underscore.
|
||||||
for question mark an ? is appended to the word that the TTS system can announce the question correctly.
|
for question mark an ? is appended to the word that the TTS system can announce the question correctly.
|
||||||
==== Custom ====
|
==== Custom ====
|
||||||
The dict "[customDict]" is just for your own use. it does just replace the key by the value without any special functionality. This might be used to correct phonetic wrongly spoken words,make words more common or just shorter. Or even just for fun :).
|
The dict "[customDict]" is just for your own use, it just replace the key with the value without any special functionality. This might be used to fix incorrectly spoken words, make words more common, shorter or just for fun. :)
|
||||||
==== Emoticons ====
|
==== Emoticons ====
|
||||||
The Emoticons dict "[emoticonDict]" contains by default some emoticons. it replaces ":)" by "smile" or "XD" by "loool". So chatting is a little more colorful.
|
The Emoticons dictionary "[emoticonDict]" by default contains some emoticons. it can replace ":)" with "smile" or "XD" with "loool" Making chat more colorful.
|
||||||
The special on that dict is that you can toggle the substitution it on or off during run time or in settings.conf. This is useful because while doing programming or other serious work you want here colons and parans not smiles.
|
A nice feature with this dictionary is that you can toggle the substitution on or off during run time or in settings.conf. This is useful because while doing programming or other serious work you want to hear colons and parans not smiles.
|
||||||
====== Configuration ======
|
====== Configuration ======
|
||||||
===== Prepare =====
|
|
||||||
===== Settings =====
|
|
||||||
You can configure Fenrir in the following places (ordered by priority):
|
You can configure Fenrir in the following places (ordered by priority):
|
||||||
- /etc/fenrir/settings/settings.conf
|
- Commandline Parameters ''-o'' see [[#Set settings coption|Set settings coption]]
|
||||||
- <sourceTree>/config/settings/settings.conf
|
- /etc/fenrir/settings/settings.conf see [[#Settings|Settigns]]
|
||||||
- run with hard coded defaults.
|
- <sourceTree>/config/settings/settings.conf see [[#Settings|Settigns]]
|
||||||
|
- hard coded defaults
|
||||||
|
===== Commandline Arguments =====
|
||||||
|
==== Set settings coption ====
|
||||||
|
You can specify options that overwrites the setting.conf.
|
||||||
|
This is done with ''-o <list of options>'' parameter.
|
||||||
|
The list of options has the following syntax
|
||||||
|
fenrir -o "section#setting=value;section#setting=value"
|
||||||
|
|
||||||
|
For example change the sound driver to gstreamer and disable braille
|
||||||
|
fenrir -o "sound#driver=gstreamerDriver;braille#enabled=False=False"
|
||||||
|
or change debug level to verbose
|
||||||
|
fenrir -o "general#debugLevel=3"
|
||||||
|
You can find the available sections and variables here [[#Settings]]
|
||||||
|
See Syntax [[#settings.conf syntax]]
|
||||||
==== settings.conf syntax ====
|
==== settings.conf syntax ====
|
||||||
the syntax of the "settings.conf" is really simple and is similar to a "*.ini" file, there are 3 different elements.
|
the syntax of the [[#Settings|settings.conf]] is really simple and is similar to a "*.ini" file, there are 4 different elements.
|
||||||
- Sections
|
- Sections
|
||||||
- Settings
|
- Settings
|
||||||
|
- Values
|
||||||
- Comments
|
- Comments
|
||||||
|
|
||||||
|
A comment starts with an # and is ignored by fenrir.
|
||||||
|
# this is a comment
|
||||||
|
To group settings we have sections.
|
||||||
A section can look like this:
|
A section can look like this:
|
||||||
[Section]
|
[Section]
|
||||||
A setting looks like this:
|
A setting looks like this:
|
||||||
settingName=Value
|
settingName=Value
|
||||||
A comment starts with an #.
|
|
||||||
# this is a comment
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
[sound]
|
[sound]
|
||||||
@ -800,7 +832,7 @@ Example:
|
|||||||
# Sox is default.
|
# Sox is default.
|
||||||
driver=genericDriver
|
driver=genericDriver
|
||||||
|
|
||||||
|
===== Settings =====
|
||||||
==== Sound ====
|
==== Sound ====
|
||||||
The sound is configured in section ''[sound]''.
|
The sound is configured in section ''[sound]''.
|
||||||
|
|
||||||
@ -836,7 +868,7 @@ The generic sound driver uses shell commands for play sound and frequencies.
|
|||||||
''genericFrequencyCommand'' defines the command that is used playing frequencies.
|
''genericFrequencyCommand'' defines the command that is used playing frequencies.
|
||||||
genericFrequencyCommand=<your command for playing a frequence>
|
genericFrequencyCommand=<your command for playing a frequence>
|
||||||
|
|
||||||
The following variable are substituted in ''genericPlayFileCommand'' and ''genericFrequencyCommand'':
|
The following variables are substituted in ''genericPlayFileCommand'' and ''genericFrequencyCommand'':
|
||||||
* ''fenrirVolume'' = the current volume setting
|
* ''fenrirVolume'' = the current volume setting
|
||||||
* ''fenrirSoundFile'' = the sound file for an sound icon
|
* ''fenrirSoundFile'' = the sound file for an sound icon
|
||||||
* ''fenrirFrequence'' = the frequency to play
|
* ''fenrirFrequence'' = the frequency to play
|
||||||
@ -987,9 +1019,9 @@ Values: Integer,
|
|||||||
* ''0'' = display size
|
* ''0'' = display size
|
||||||
* ''>0'' number of cells
|
* ''>0'' number of cells
|
||||||
==== Screen ====
|
==== Screen ====
|
||||||
The settings for screens, (TTY, PTY) is done in the ''[screen]'' section.
|
The settings for screens, (TTY, PTY) are configured in the ''[screen]'' section.
|
||||||
|
|
||||||
The driver that gets the information from a screen:
|
The driver to get the information from the screen:
|
||||||
driver=vcsaDriver
|
driver=vcsaDriver
|
||||||
Available Drivers:
|
Available Drivers:
|
||||||
* ''vcsaDriver'' using the VCSA driver (for TTYs), for Fenrir <1.5 just use ''vcsa''
|
* ''vcsaDriver'' using the VCSA driver (for TTYs), for Fenrir <1.5 just use ''vcsa''
|
||||||
@ -1001,21 +1033,21 @@ The driver updates Fenrir with changes upon the screen.
|
|||||||
screenUpdateDelay=0.05
|
screenUpdateDelay=0.05
|
||||||
Values: in Seconds
|
Values: in Seconds
|
||||||
|
|
||||||
If you want Fenrir to not be active on any screen. That can have different reasons. Maybe an X server or Wayland is running on that screen. You can make Fenrir ignore it or multiple screens seperated by '','' with:
|
If you want Fenrir to not be active on any screen for various reasons. Maybe an X server or Wayland is running on that screen. You can make Fenrir ignore it or multiple screens seperated by '','' with:
|
||||||
suspendingScreen=
|
suspendingScreen=
|
||||||
Values: Depends on driver:
|
Values: Depends on driver:
|
||||||
* VCSA: the number of the TTY. TTY6 is ''6''.
|
* VCSA: the number of the TTY. TTY6 is ''6''.
|
||||||
Example ignore TTY1 and TTY2:
|
Example ignore TTY1 and TTY2:
|
||||||
suspendingScreen=1,2
|
suspendingScreen=1,2
|
||||||
|
|
||||||
There is also the ability to let Fenrir auto detect screens that running an X. So Screens running an GUI are ignored.
|
There is also the ability to let Fenrir auto detect screens that are running an X server. So Screens running an GUI are ignored.
|
||||||
autodetectSuspendingScreen=True
|
autodetectSuspendingScreen=True
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
==== Keyboard ====
|
==== Keyboard ====
|
||||||
The settings for keyboard and input related configuration is located in the section ''[keyboard]'' of the ''settings.conf'' file.
|
The settings for keyboard and input related configuration is located in the section ''[keyboard]'' of the ''settings.conf'' file.
|
||||||
|
|
||||||
Select the driver used to for grabbing the keybord and recieve shortcuts.
|
Select the driver used for grabbing keybord input and for recieving shortcuts.
|
||||||
driver=evdevDriver
|
driver=evdevDriver
|
||||||
Values: Text, available Driver
|
Values: Text, available Driver
|
||||||
Available Drivers:
|
Available Drivers:
|
||||||
@ -1028,23 +1060,23 @@ Values:
|
|||||||
* ''NOMICE'' Exclude mices from handling.
|
* ''NOMICE'' Exclude mices from handling.
|
||||||
* ''<Device Name>'' just use the device with the given name.
|
* ''<Device Name>'' just use the device with the given name.
|
||||||
|
|
||||||
Gives Fenrir exclusive access to the keyboard and lets it control keystrokes. This is needed to consume the Fenrir related shortcuts.
|
Gives Fenrir exclusive access to the keyboard and lets it control keystrokes. This is needed to intercept Fenrir related shortcuts.
|
||||||
grabDevices=True
|
grabDevices=True
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
The following just make sense if you are using an second screenreader and just wanna have some hooked events. Fenrir ignores all shortcuts then.
|
The following just make sense if you are using a second screenreader and just wanna have some hooked events. Fenrir ignores all shortcuts then.
|
||||||
ignoreShortcuts=False
|
ignoreShortcuts=False
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
The current keyboard layout used for shortcuts.
|
The current keyboard layout used for shortcuts.
|
||||||
keyboardLayout=desktop
|
keyboardLayout=desktop
|
||||||
Values: A absolute Path to an Keyboard definition file or a Filename without extension located in ''/etc/fenrir/keyboard''
|
Values: An absolute Path to a Keyboard definition file or a Filename without extension located in ''/etc/fenrir/keyboard''
|
||||||
|
|
||||||
Announce chars while typing.
|
Announce characters while typing.
|
||||||
charEcho=False
|
charEcho=False
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
Announce deleted chars
|
Announce deleted characters
|
||||||
charDeleteEcho=True
|
charDeleteEcho=True
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
@ -1058,71 +1090,77 @@ Values: on=''True'', off=''False''
|
|||||||
|
|
||||||
You can filter the keys on that the speech should interrupt
|
You can filter the keys on that the speech should interrupt
|
||||||
interruptOnKeyPressFilter=
|
interruptOnKeyPressFilter=
|
||||||
Values: (List) empty = all keys, otherwhise interrupt on given keys
|
Values: (List) empty = all keys, otherwise interrupt with specified keys
|
||||||
|
|
||||||
The timeout that is used for double tap shortcuts
|
The timeout that is used for double tap shortcuts
|
||||||
doubleTapTimeout=0.2
|
doubleTapTimeout=0.2
|
||||||
Values: Seconds
|
Values: Seconds
|
||||||
==== General ====
|
==== General ====
|
||||||
Overall stuff can be configured in section ''[general]''.
|
Overall settings can be configured from the section ''[general]''.
|
||||||
|
|
||||||
Set the current debug level:
|
Set the current debug level:
|
||||||
debugLevel=1
|
debugLevel=1
|
||||||
Values: off=0, error=1, warning=2, info=3
|
Values: off=0, error=1, warning=2, info=3
|
||||||
|
|
||||||
the current used punctuation and dict file:
|
the current punctuation and dict file in use:
|
||||||
punctuationProfile=default
|
punctuationProfile=default
|
||||||
Values: Text, see available profiles in ''/etc/fenrir/punctuation'' or in ''sourceTree/config/punctuation''
|
Values: Text, see available profiles in ''/etc/fenrir/punctuation'' or in ''sourceTree/config/punctuation''
|
||||||
|
|
||||||
The current used punctuation level.
|
The current punctuation level in use:
|
||||||
punctuationLevel=some
|
punctuationLevel=some
|
||||||
Values: Text, See available levels in the used punctuation file.
|
Values: Text, See available levels in the used punctuation file.
|
||||||
|
|
||||||
Respect pause for punctuations.
|
Respect pause for punctuations:
|
||||||
respectPunctuationPause=True
|
respectPunctuationPause=True
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
Add a pause on Line break.
|
Add a pause on Line break:
|
||||||
newLinePause=True
|
newLinePause=True
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
|
Specify the path where the clipboard should be exported to.
|
||||||
|
See [[#export clipboard to file|export clipboard to file]].
|
||||||
|
The variable ''$user'' is replaced by the current logged username.
|
||||||
|
clipboardExportPath=/tmp/fenrirClipboard
|
||||||
|
Values: Text, Systemfilepath
|
||||||
|
|
||||||
The number of available cipboards:
|
The number of available cipboards:
|
||||||
numberOfClipboards=10
|
numberOfClipboards=10
|
||||||
Values: Integer, 1 - 999
|
Values: Integer, 1 - 999
|
||||||
|
|
||||||
Replace emoticons like :) or ;) with there names.
|
Replace emoticons like :) or ;) with text insertions:
|
||||||
emoticons=True
|
emoticons=True
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
Define the current fenrir keys.
|
Define the current fenrir keys:
|
||||||
fenrirKeys=KEY_KP0,KEY_META,KEY_INSERT
|
fenrirKeys=KEY_KP0,KEY_META,KEY_INSERT
|
||||||
Values, Text list, separated by comma.
|
Values, Text list, separated by comma.
|
||||||
|
|
||||||
Define the current script keys.
|
Define the current script keys:
|
||||||
scriptKey=KEY_COMPOSE
|
scriptKey=KEY_COMPOSE
|
||||||
Values, Text list, separated by comma.
|
Values, Text list, separated by comma.
|
||||||
|
|
||||||
The timeformat that is used for output (time command)
|
The time format to be used for (time command) output:
|
||||||
timeFormat=%H:%M:%P
|
timeFormat=%H:%M:%P
|
||||||
Values: see python specification for [[https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior|datetime.strftime]]
|
Values: see python specification for [[https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior|datetime.strftime]]
|
||||||
|
|
||||||
The date format that is used for output (date command).
|
The date format to be used for (date command) output:
|
||||||
dateFormat=%A, %B %d, %Y
|
dateFormat=%A, %B %d, %Y
|
||||||
Values: see python specification for [[https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior|datetime.strftime]]
|
Values: see python specification for [[https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior|datetime.strftime]]
|
||||||
|
|
||||||
Enable or Disable the spellchecker while typing.
|
Enable or Disable spellcheck whilst typing:
|
||||||
autoSpellCheck=True
|
autoSpellCheck=True
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
The used dictionary for the spellchecker.
|
The use of the dictionary with spellcheck:
|
||||||
spellCheckLanguage=en_US
|
spellCheckLanguage=en_US
|
||||||
Values: Text, see aspell dictionary's.
|
Values: Text, see aspell dictionary's.
|
||||||
|
|
||||||
Folder Path for your scripts "scriptKey" functionality.
|
Folder Path for your scripts "scriptKey" functionality:
|
||||||
scriptPath=/usr/share/fenrir/scripts
|
scriptPath=/usr/share/fenrir/scripts
|
||||||
Values: Text, Existing path on file system.
|
Values: Text, Existing path on file system.
|
||||||
|
|
||||||
Overload commands or create new one without changing Fenrir default.
|
Override commands or create new ones without changing Fenrir defaults:
|
||||||
commandPath=/usr/share/fenrir/commands
|
commandPath=/usr/share/fenrir/commands
|
||||||
Values: Text, Existing path on file system.
|
Values: Text, Existing path on file system.
|
||||||
Subfolders in commandPath are:
|
Subfolders in commandPath are:
|
||||||
@ -1132,51 +1170,51 @@ Subfolders in commandPath are:
|
|||||||
* ''onScreenUpdate'' = executed when the screen is captured
|
* ''onScreenUpdate'' = executed when the screen is captured
|
||||||
|
|
||||||
==== Focus ====
|
==== Focus ====
|
||||||
The basic focus configuration is done in section ''[focus]''.
|
The configuration for basic focus is in the section ''[focus]''.
|
||||||
Follow the text cursor:
|
Follow the text cursor:
|
||||||
cursor=True
|
cursor=True
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
Follow highlighted text changes (Highlight Tracking)
|
Follow highlighted text changes (Highlight Tracking):
|
||||||
highlight=False
|
highlight=False
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
==== Review ====
|
==== Review ====
|
||||||
Configurations for the review mode are done in section ''[review]''.
|
Configurations for the review mode are in the section ''[review]''.
|
||||||
|
|
||||||
If "next word/ char" or "prev word/char" create an linebreak announce it.
|
If "next word/ char" or "prev word/char" create a linebreak, announce it:
|
||||||
lineBreak=True
|
lineBreak=True
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
If "next word/ char" or "prev word/char" can not be done because you reached the end of the screen announce it.
|
If "next word/ char" or "prev word/char" cannot be performed because you reached the end of the screen, announce it:
|
||||||
endOfScreen=True
|
endOfScreen=True
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
Leave the review mode when pressing a key
|
Leave the review mode when pressing a key:
|
||||||
leaveReviewOnKeypress=False
|
leaveReviewOnKeypress=False
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
Leave the review mode when changing the screen (From TTY3 to TTY4)
|
Leave the review mode when changing the screen (From TTY3 to TTY4):
|
||||||
leaveReviewOnScreenChange=True
|
leaveReviewOnScreenChange=True
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
==== Promote ====
|
==== Promote ====
|
||||||
"Promoted Lists" are configured in section ''[promote]''.
|
"Promoted Lists" are configured in the section ''[promote]''.
|
||||||
Turn Promoted Lists" on or off:
|
Turn Promoted Lists" on or off:
|
||||||
enabled=True
|
enabled=True
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
The minimum time interval for inactivity that activates promoting.
|
The minimum time interval of inactivity to activate promoting.
|
||||||
By default it promotes after 120 Seconds inactivity.
|
By default it promotes after 120 Seconds inactivity:
|
||||||
inactiveTimeoutSec=120
|
inactiveTimeoutSec=120
|
||||||
Values: in Seconds
|
Values: in Seconds
|
||||||
|
|
||||||
Define the list of promoted words comma seperated.
|
Define a list of promoted words comma seperated:
|
||||||
list=
|
list=
|
||||||
Values: text (comma seperated)
|
Values: text (comma seperated)
|
||||||
Example to promote the word "nickname" or an bash prompt:
|
Example to promote the word "nickname" or a bash prompt:
|
||||||
list=nickname,$:,#:
|
list=nickname,$:,#:
|
||||||
|
|
||||||
==== Time ====
|
==== Time ====
|
||||||
The automated time announcement is configured in section ''[time]''.
|
The automated time announcement is configured in the section ''[time]''.
|
||||||
Time announcement is disabled by default.
|
Time announcement is disabled by default.
|
||||||
Turn time announcement on or off:
|
Turn time announcement on or off:
|
||||||
enabled=True
|
enabled=True
|
||||||
@ -1190,20 +1228,20 @@ Should the date be announced (just on date change):
|
|||||||
presentDate=True
|
presentDate=True
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
Announce after a given period of seconds
|
Announce after a given period of seconds:
|
||||||
delaySec=0
|
delaySec=0
|
||||||
Value: in Seconds, 0 = Deactivated
|
Value: in Seconds, 0 = Deactivated
|
||||||
|
|
||||||
Announce after to fix minutes in an hour. if delaySec is >0 onMinutes is ignored.
|
Announce after to fix minutes in an hour. if delaySec is >0 onMinutes is ignored:
|
||||||
onMinutes=00,30
|
onMinutes=00,30
|
||||||
Example every 15 minutes:
|
Example every 15 minutes:
|
||||||
onMinutes=00,15,30,45
|
onMinutes=00,15,30,45
|
||||||
|
|
||||||
Just play an soundicon (not interrupting)
|
Just play a soundicon, (not interrupting):
|
||||||
announce=True
|
announce=True
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
|
|
||||||
Interrupt current speech for time announcement
|
Interrupt current speech for time announcement:
|
||||||
interrupt=False
|
interrupt=False
|
||||||
Values: on=''True'', off=''False''
|
Values: on=''True'', off=''False''
|
||||||
====== Customization ======
|
====== Customization ======
|
||||||
@ -1213,11 +1251,24 @@ The script key is the applications key. Usually this key can be found on the key
|
|||||||
When you name a script, the key name appears in the script seperated by the sequence __-__. So, for example, if you have a python weather script you want assigned to the script key plus the letter w you would name the script /usr/share/fenrir/scripts/weather__-__key_w.py
|
When you name a script, the key name appears in the script seperated by the sequence __-__. So, for example, if you have a python weather script you want assigned to the script key plus the letter w you would name the script /usr/share/fenrir/scripts/weather__-__key_w.py
|
||||||
Then, to access the script, simply press the script key and the letter w.
|
Then, to access the script, simply press the script key and the letter w.
|
||||||
Scripts must be executable. So, make sure to chmod 755 your script when you place it in the scripts directory.
|
Scripts must be executable. So, make sure to chmod 755 your script when you place it in the scripts directory.
|
||||||
|
The script gets some parameter from fenrir when it is executed. So that information is available in your script then.
|
||||||
|
|
||||||
|
==== Parameterlist ====
|
||||||
|
^Parameter ^Content ^
|
||||||
|
|$1|Username of the current logged in user|
|
||||||
|
|
||||||
|
==== Examples ====
|
||||||
|
Script that just speaks the current username when pressing ScriptKey + H.\\
|
||||||
|
File: ''/usr/share/fenrir/scripts/helloWorld__-__key_h.sh'':
|
||||||
|
#!/bin/bash
|
||||||
|
echo $1
|
||||||
|
|
||||||
|
|
||||||
===== Commands =====
|
===== Commands =====
|
||||||
You can place your own commands in "/usr/share/fenrir/commands" (path is configurable in settings.conf).
|
You can place your own commands in "/usr/share/fenrir/commands" (path is configurable in settings.conf).
|
||||||
Commands are python files with an special scheme. You can assign them to an shortcut using the filename without extension or place them in an hook trigger like OnInput or OnScreenChange. For deeper information see developer guide.
|
Commands are python files with a special scheme. You can assign them to a shortcut using the filename without an extension or place them in a hook trigger like OnInput or OnScreenChange. For further information see developer guide.
|
||||||
Good Examples: [[https://github.com/chrys87/fenrir/blob/master/src/fenrir/commands/commands/date.py|"date.py"]] (announce the Date), [[https://github.com/chrys87/fenrir/blob/master/src/fenrir/commands/commands/shut_up.py|"shut_up.py"]] (interrupt output)
|
Good Examples: [[https://github.com/chrys87/fenrir/blob/master/src/fenrir/commands/commands/date.py|"date.py"]] (announce the Date), [[https://github.com/chrys87/fenrir/blob/master/src/fenrir/commands/commands/shut_up.py|"shut_up.py"]] (interrupt output)
|
||||||
the basic scheme for an command is the following:
|
the basic scheme for a command is as follows:
|
||||||
|
|
||||||
from core import debug
|
from core import debug
|
||||||
|
|
||||||
@ -1235,23 +1286,28 @@ the basic scheme for an command is the following:
|
|||||||
def setCallback(self, callback):
|
def setCallback(self, callback):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
* [[https://github.com/chrys87/fenrir/blob/master/src/fenrir/commands/command_template.py|Template is here]]
|
* [[https://github.com/chrys87/fenrir/blob/master/src/fenrir/commands/command_template.py|Template lives here]]
|
||||||
* The class needs to have the name "command".
|
* The class needs to have the name "command".
|
||||||
* "initialize" is running once while loading the command.
|
* "initialize" is running once whilst loading the command.
|
||||||
* "shutdown" is running on unload the command (like quit fenrir)
|
* "shutdown" is running on unload like the command (quit fenrir)
|
||||||
* "getDescriptsion" just returns an string. That Sting is used in Tutorial Mode.
|
* "getDescriptsion" just returns an string. That String is used in Tutorial Mode.
|
||||||
* "run" is executed when the command is invoked. (shortcut is pressed, or trigger is running)
|
* "run" is executed when the command is invoked. (shortcut is pressed, or trigger isn't running)
|
||||||
* setCAllback is currently not used. and has no functionality yet.
|
* setCAllback is currently not used. and has no functionality yet.
|
||||||
|
|
||||||
|
|
||||||
====== Trouble Shooting ======
|
====== Troubleshooting ======
|
||||||
Fenrir does not start
|
Fenrir does not start
|
||||||
- Did you installed all dependencys
|
- Have you installed all the dependencies [[#Support and Requirements|Support and Requirements]]
|
||||||
- Try master, i changed many things for make it compatible to more systems
|
- Try using master, a lot of changes take place there to make Fenrir compatible with more systems
|
||||||
Fenrir does not consume the shortcuts
|
Fenrir does not utilize the shortcuts
|
||||||
- make sure you have python3-evdev installed
|
- Make sure you have python3-evdev installed
|
||||||
- use latest Fenrir version
|
- Use the latest Fenrir version
|
||||||
No Sound:
|
No Sound:
|
||||||
- run script to configure pulse for Fenrir ''tools/configure_pulse.sh'' (once as user and once as root, then restart)
|
- Run the scripts to configure pulse. found in: ''tools/configure_pulse.sh'' (once as your user and once as root. Then restart Fenrir)
|
||||||
- use ALSA
|
- use ALSA
|
||||||
- configure pulse systemwide
|
- Configure Pulse systemwide
|
||||||
|
No Speech:
|
||||||
|
- Run the scripts to configure pulse. found in: ''tools/configure_pulse.sh'' (once as your user and once as root. Then restart Fenrir)
|
||||||
|
- use ALSA
|
||||||
|
- Configure Pulse systemwide
|
||||||
|
- if you are using speech-dispatcher run "spd-conf" as user and as root once.
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
Known Bugs (Problems with the logic ):
|
Known Bugs (Problems with the logic ):
|
||||||
- word echo triggers twice if there are two spaces after an word and you arrow over them
|
- word echo triggers twice if there are two spaces after an word and you arrow over them
|
||||||
- spellcheck triggers twice if there are two spaces after an word and you arrow over them
|
- spellcheck triggers twice if there are two spaces after an word and you arrow over them
|
||||||
|
|
||||||
Glitches (improve diff results):
|
Glitches (improve diff results):
|
||||||
- For example, in screen, it just tells me bell in window, but doesn't tell me which one. (southernprince)
|
- For example, in screen, it just tells me bell in window, but doesn't tell me which one. (southernprince)
|
||||||
- alpine seems to have problems (southernprince)
|
- alpine seems to have problems (southernprince)
|
||||||
- whole status line in irssi is spoken insteed of just the changes
|
- whole status line in irssi is spoken insteed of just the changes
|
||||||
- whole status line in vim is spoken insteed of just the changes
|
- whole status line in vim is spoken insteed of just the changes
|
||||||
- keys sometimes get stuck
|
|
||||||
|
|
||||||
Questions:
|
|
||||||
- what is the correct codepage for cyrillic
|
|
||||||
- cyrillic (see autoencoding prototype)
|
|
||||||
|
@ -1,76 +1,88 @@
|
|||||||
#!/bin/python3
|
import time
|
||||||
#attrib:
|
|
||||||
#http://rampex.ihep.su/Linux/linux_howto/html/tutorials/mini/Colour-ls-6.html
|
|
||||||
#0 = black, 1 = blue, 2 = green, 3 = cyan, 4 = red, 5 = purple, 6 = brown/yellow, 7 = white.
|
|
||||||
#https://github.com/jwilk/vcsapeek/blob/master/linuxvt.py
|
|
||||||
#blink = 5 if attr & 1 else 0
|
|
||||||
#bold = 1 if attr & 16 else 0
|
|
||||||
from fcntl import ioctl
|
from fcntl import ioctl
|
||||||
from array import array
|
from array import array
|
||||||
import struct
|
from struct import unpack_from
|
||||||
|
from struct import unpack
|
||||||
|
from struct import pack
|
||||||
import errno
|
import errno
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
ttyno = 4
|
|
||||||
tty = open('/dev/tty%d' % ttyno, 'rb')
|
|
||||||
vcs = open('/dev/vcsa%d' % ttyno, 'rb')
|
|
||||||
|
|
||||||
head = vcs.read(4)
|
|
||||||
rows = int(head[0])
|
|
||||||
cols = int(head[1])
|
|
||||||
|
|
||||||
|
|
||||||
GIO_UNIMAP = 0x4B66
|
|
||||||
VT_GETHIFONTMASK = 0x560D
|
|
||||||
himask = array("H", (0,))
|
|
||||||
ioctl(tty, VT_GETHIFONTMASK, himask)
|
|
||||||
hichar, = struct.unpack_from("@H", himask)
|
|
||||||
|
|
||||||
sz = 512
|
|
||||||
line = ''
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
unipairs = array("H", [0]*(2*sz))
|
|
||||||
unimapdesc = array("B", struct.pack("@HP", sz, unipairs.buffer_info()[0]))
|
|
||||||
ioctl(tty.fileno(), GIO_UNIMAP, unimapdesc)
|
|
||||||
break
|
|
||||||
except IOError as e:
|
|
||||||
if e.errno != errno.ENOMEM:
|
|
||||||
raise
|
|
||||||
sz *= 2
|
|
||||||
|
|
||||||
tty.close()
|
|
||||||
|
|
||||||
ncodes, = struct.unpack_from("@H", unimapdesc)
|
|
||||||
utable = struct.unpack_from("@%dH" % (2*ncodes), unipairs)
|
|
||||||
|
|
||||||
charmap = {}
|
charmap = {}
|
||||||
for u, b in zip(utable[::2], utable[1::2]):
|
hichar = None
|
||||||
if charmap.get(b) is None:
|
def updateCharMap(screen):
|
||||||
charmap[b] = u
|
global hichar
|
||||||
|
ttyno = '4'
|
||||||
|
tty = open('/dev/tty' + screen, 'rb')
|
||||||
|
GIO_UNIMAP = 0x4B66
|
||||||
|
VT_GETHIFONTMASK = 0x560D
|
||||||
|
himask = array("H", (0,))
|
||||||
|
ioctl(tty, VT_GETHIFONTMASK, himask)
|
||||||
|
hichar, = unpack_from("@H", himask)
|
||||||
|
sz = 512
|
||||||
|
line = ''
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
unipairs = array("H", [0]*(2*sz))
|
||||||
|
unimapdesc = array("B", pack("@HP", sz, unipairs.buffer_info()[0]))
|
||||||
|
ioctl(tty.fileno(), GIO_UNIMAP, unimapdesc)
|
||||||
|
break
|
||||||
|
except IOError as e:
|
||||||
|
if e.errno != errno.ENOMEM:
|
||||||
|
raise
|
||||||
|
sz *= 2
|
||||||
|
tty.close()
|
||||||
|
ncodes, = unpack_from("@H", unimapdesc)
|
||||||
|
utable = unpack_from("@%dH" % (2*ncodes), unipairs)
|
||||||
|
for u, b in zip(utable[::2], utable[1::2]):
|
||||||
|
if charmap.get(b) is None:
|
||||||
|
charmap[b] = chr(u)
|
||||||
|
|
||||||
allText = []
|
|
||||||
allAttrib = []
|
|
||||||
for y in range(rows):
|
|
||||||
lineText = ''
|
|
||||||
lineAttrib = []
|
|
||||||
for x in range(cols):
|
|
||||||
data = vcs.read(2)
|
|
||||||
(sh,) = struct.unpack("=H", data)
|
|
||||||
attr = (sh >> 8) & 0xFF
|
|
||||||
ch = sh & 0xFF
|
|
||||||
if hichar == 0x100:
|
|
||||||
attr >>= 1
|
|
||||||
lineAttrib.append(attr)
|
|
||||||
ink = attr & 0x0F
|
|
||||||
paper = (attr>>4) & 0x0F
|
|
||||||
if (ink != 7) or (paper != 0):
|
|
||||||
print(ink,paper)
|
|
||||||
if sh & hichar:
|
|
||||||
ch |= 0x100
|
|
||||||
lineText += chr(charmap.get(ch, u'?'))
|
|
||||||
allText.append(lineText)
|
|
||||||
allAttrib.append(lineAttrib)
|
|
||||||
|
|
||||||
print(allText)
|
def autoDecodeVCSA(allData, rows, cols):
|
||||||
print(allAttrib)
|
allText = []
|
||||||
|
allAttrib = []
|
||||||
|
for y in range(rows):
|
||||||
|
lineText = ''
|
||||||
|
lineAttrib = []
|
||||||
|
i = 0
|
||||||
|
for x in range(cols):
|
||||||
|
data = allData[i: i + 2]
|
||||||
|
i += 2
|
||||||
|
if data == b' \x07':
|
||||||
|
#attr = 7
|
||||||
|
#ink = 7
|
||||||
|
#paper = 0
|
||||||
|
#ch = ' '
|
||||||
|
lineAttrib.append(7)
|
||||||
|
lineText += ' '
|
||||||
|
continue
|
||||||
|
(sh,) = unpack("=H", data)
|
||||||
|
attr = (sh >> 8) & 0xFF
|
||||||
|
ch = sh & 0xFF
|
||||||
|
if hichar == 0x100:
|
||||||
|
attr >>= 1
|
||||||
|
lineAttrib.append(attr)
|
||||||
|
ink = attr & 0x0F
|
||||||
|
paper = (attr>>4) & 0x0F
|
||||||
|
#if (ink != 7) or (paper != 0):
|
||||||
|
# print(ink,paper)
|
||||||
|
if sh & hichar:
|
||||||
|
ch |= 0x100
|
||||||
|
try:
|
||||||
|
lineText += charmap[ch]
|
||||||
|
except:
|
||||||
|
lineText += chr('?')
|
||||||
|
allText.append(lineText)
|
||||||
|
allAttrib.append(lineAttrib)
|
||||||
|
return allText, allAttrib
|
||||||
|
|
||||||
|
def m(screen):
|
||||||
|
s = time.time()
|
||||||
|
updateCharMap(str(screen))
|
||||||
|
print(time.time() -s )
|
||||||
|
vcsa = open('/dev/vcsa' + str(screen), 'rb')
|
||||||
|
head = vcsa.read(4)
|
||||||
|
rows = int(head[0])
|
||||||
|
cols = int(head[1])
|
||||||
|
text, attrib = autoDecodeVCSA(vcsa.read(), rows, cols)
|
||||||
|
print(time.time() -s )
|
||||||
|
|
||||||
|
37
play zone/epollScreen.py
Normal file
37
play zone/epollScreen.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#!/bin/python
|
||||||
|
|
||||||
|
import select
|
||||||
|
import time
|
||||||
|
|
||||||
|
currScreen = '2'
|
||||||
|
vcsa = {}
|
||||||
|
for i in range(1,7):
|
||||||
|
vcsa[str(i)] = open('/dev/vcs'+str(i),'rb')
|
||||||
|
|
||||||
|
tty = open('/sys/devices/virtual/tty/tty0/active','r')
|
||||||
|
currScreen = str(tty.read()[3:-1])
|
||||||
|
oldScreen = currScreen
|
||||||
|
watchdog = select.epoll()
|
||||||
|
watchdog.register(vcsa[currScreen], select.EPOLLPRI)
|
||||||
|
watchdog.register(tty, select.EPOLLPRI)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
changes = watchdog.poll()
|
||||||
|
print('-----------------------------')
|
||||||
|
print(changes)
|
||||||
|
for change in changes:
|
||||||
|
fileno = change[0]
|
||||||
|
event = change[1]
|
||||||
|
print(change,fileno, tty.fileno())
|
||||||
|
if fileno == tty.fileno():
|
||||||
|
tty.seek(0)
|
||||||
|
currScreen = str(tty.read()[3:-1])
|
||||||
|
if currScreen != oldScreen:
|
||||||
|
watchdog.unregister(vcsa[ oldScreen ])
|
||||||
|
watchdog.register(vcsa[ currScreen ], select.EPOLLPRI)
|
||||||
|
oldScreen = currScreen
|
||||||
|
print('new screen '+ currScreen)
|
||||||
|
else:
|
||||||
|
vcsa[currScreen].seek(0)
|
||||||
|
content = vcsa[currScreen].read()
|
||||||
|
print('update '+ str(time.time()))
|
@ -17,7 +17,7 @@ class command():
|
|||||||
return _('exits Fenrir')
|
return _('exits Fenrir')
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.env['general']['running'] = False
|
self.env['runtime']['eventManager'].stopMainEventLoop()
|
||||||
|
|
||||||
def setCallback(self, callback):
|
def setCallback(self, callback):
|
||||||
pass
|
pass
|
||||||
|
@ -14,13 +14,11 @@ class command():
|
|||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
pass
|
pass
|
||||||
def getDescription(self):
|
def getDescription(self):
|
||||||
self.env['general']['tutorialMode'] = False
|
self.env['runtime']['helpManager'].toggleTutorialMode()
|
||||||
|
#self.env['runtime']['outputManager'].presentText(, interrupt=True)
|
||||||
return _('You are leaving the tutorial mode. Press that shortcut again to enter the tutorial mode again.')
|
return _('You are leaving the tutorial mode. Press that shortcut again to enter the tutorial mode again.')
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
text = _('you entered the tutorial mode. In that mode the commands are not executed. but you get a description of what the shortcut does. To leave the tutorial mode, press that shortcut again.')
|
self.env['runtime']['helpManager'].toggleTutorialMode()
|
||||||
self.env['runtime']['outputManager'].presentText(text, interrupt=True)
|
self.env['runtime']['outputManager'].presentText( _('you entered the tutorial mode. In that mode the commands are not executed. but you get a description of what the shortcut does. To leave the tutorial mode, press that shortcut again.'), interrupt=True)
|
||||||
self.env['general']['tutorialMode'] = True
|
|
||||||
|
|
||||||
def setCallback(self, callback):
|
def setCallback(self, callback):
|
||||||
pass
|
pass
|
||||||
|
2
src/fenrir/commands/help/Readme.txt
Normal file
2
src/fenrir/commands/help/Readme.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
this folder contains help and tutorial related functions.
|
||||||
|
those are not bindable but hard coded.
|
22
src/fenrir/commands/help/curr_help.py
Normal file
22
src/fenrir/commands/help/curr_help.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Fenrir TTY screen reader
|
||||||
|
# By Chrys, Storm Dragon, and contributers.
|
||||||
|
|
||||||
|
from core import debug
|
||||||
|
|
||||||
|
class command():
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
def initialize(self, environment):
|
||||||
|
self.env = environment
|
||||||
|
def shutdown(self):
|
||||||
|
pass
|
||||||
|
def getDescription(self):
|
||||||
|
return _('get current help message')
|
||||||
|
def run(self):
|
||||||
|
text = self.env['runtime']['helpManager'].getHelpForCurrentIndex()
|
||||||
|
self.env['runtime']['outputManager'].presentText(text, interrupt=True)
|
||||||
|
def setCallback(self, callback):
|
||||||
|
pass
|
23
src/fenrir/commands/help/next_help.py
Normal file
23
src/fenrir/commands/help/next_help.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Fenrir TTY screen reader
|
||||||
|
# By Chrys, Storm Dragon, and contributers.
|
||||||
|
|
||||||
|
from core import debug
|
||||||
|
|
||||||
|
class command():
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
def initialize(self, environment):
|
||||||
|
self.env = environment
|
||||||
|
def shutdown(self):
|
||||||
|
pass
|
||||||
|
def getDescription(self):
|
||||||
|
return _('get next help message')
|
||||||
|
def run(self):
|
||||||
|
self.env['runtime']['helpManager'].nextIndex()
|
||||||
|
text = self.env['runtime']['helpManager'].getHelpForCurrentIndex()
|
||||||
|
self.env['runtime']['outputManager'].presentText(text, interrupt=True)
|
||||||
|
def setCallback(self, callback):
|
||||||
|
pass
|
23
src/fenrir/commands/help/prev_help.py
Normal file
23
src/fenrir/commands/help/prev_help.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Fenrir TTY screen reader
|
||||||
|
# By Chrys, Storm Dragon, and contributers.
|
||||||
|
|
||||||
|
from core import debug
|
||||||
|
|
||||||
|
class command():
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
def initialize(self, environment):
|
||||||
|
self.env = environment
|
||||||
|
def shutdown(self):
|
||||||
|
pass
|
||||||
|
def getDescription(self):
|
||||||
|
return _('get prev help message')
|
||||||
|
def run(self):
|
||||||
|
self.env['runtime']['helpManager'].prevIndex()
|
||||||
|
text = self.env['runtime']['helpManager'].getHelpForCurrentIndex()
|
||||||
|
self.env['runtime']['outputManager'].presentText(text, interrupt=True)
|
||||||
|
def setCallback(self, callback):
|
||||||
|
pass
|
@ -21,9 +21,7 @@ class command():
|
|||||||
if not self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'cursor'):
|
if not self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'cursor'):
|
||||||
return
|
return
|
||||||
if self.env['runtime']['screenManager'].isScreenChange():
|
if self.env['runtime']['screenManager'].isScreenChange():
|
||||||
return
|
return
|
||||||
if self.env['runtime']['inputManager'].noKeyPressed():
|
|
||||||
return
|
|
||||||
# detect an change on the screen, we just want to cursor arround, so no change should appear
|
# detect an change on the screen, we just want to cursor arround, so no change should appear
|
||||||
if self.env['runtime']['screenManager'].isDelta():
|
if self.env['runtime']['screenManager'].isDelta():
|
||||||
return
|
return
|
@ -19,9 +19,7 @@ class command():
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if not self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'cursor'):
|
if not self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'cursor'):
|
||||||
return
|
return
|
||||||
if self.env['runtime']['inputManager'].noKeyPressed():
|
|
||||||
return
|
|
||||||
if self.env['runtime']['screenManager'].isScreenChange():
|
if self.env['runtime']['screenManager'].isScreenChange():
|
||||||
return
|
return
|
||||||
# this leads to problems in vim -> status line change -> no announcement, so we do check the lengh as hack
|
# this leads to problems in vim -> status line change -> no announcement, so we do check the lengh as hack
|
@ -29,8 +29,6 @@ class command():
|
|||||||
# just when cursor move worddetection is needed
|
# just when cursor move worddetection is needed
|
||||||
if not self.env['runtime']['cursorManager'].isCursorHorizontalMove():
|
if not self.env['runtime']['cursorManager'].isCursorHorizontalMove():
|
||||||
return
|
return
|
||||||
if self.env['runtime']['inputManager'].noKeyPressed():
|
|
||||||
return
|
|
||||||
# for now no new line
|
# for now no new line
|
||||||
if self.env['runtime']['cursorManager'].isCursorVerticalMove():
|
if self.env['runtime']['cursorManager'].isCursorVerticalMove():
|
||||||
return
|
return
|
@ -39,8 +39,6 @@ class command():
|
|||||||
return
|
return
|
||||||
if not self.env['runtime']['settingsManager'].getSettingAsBool('general', 'autoSpellCheck'):
|
if not self.env['runtime']['settingsManager'].getSettingAsBool('general', 'autoSpellCheck'):
|
||||||
return
|
return
|
||||||
if self.env['runtime']['inputManager'].noKeyPressed():
|
|
||||||
return
|
|
||||||
if self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage') != self.language:
|
if self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage') != self.language:
|
||||||
try:
|
try:
|
||||||
self.updateSpellLanguage()
|
self.updateSpellLanguage()
|
@ -19,20 +19,16 @@ class command():
|
|||||||
def run(self):
|
def run(self):
|
||||||
if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'charDeleteEcho'):
|
if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'charDeleteEcho'):
|
||||||
return
|
return
|
||||||
|
|
||||||
# detect typing or chilling
|
# detect typing or chilling
|
||||||
if self.env['screen']['newCursor']['x'] >= self.env['screen']['oldCursor']['x']:
|
if self.env['screen']['newCursor']['x'] >= self.env['screen']['oldCursor']['x']:
|
||||||
return
|
return
|
||||||
|
|
||||||
# More than just a deletion happend
|
# More than just a deletion happend
|
||||||
|
|
||||||
if self.env['runtime']['screenManager'].isDelta():
|
if self.env['runtime']['screenManager'].isDelta():
|
||||||
return
|
return
|
||||||
# no deletion
|
# no deletion
|
||||||
if not self.env['runtime']['screenManager'].isNegativeDelta():
|
if not self.env['runtime']['screenManager'].isNegativeDelta():
|
||||||
return
|
return
|
||||||
if self.env['runtime']['inputManager'].noKeyPressed():
|
|
||||||
return
|
|
||||||
|
|
||||||
# too much for a single backspace...
|
# too much for a single backspace...
|
||||||
# word begin produce a diff wiht len == 2 |a | others with 1 |a|
|
# word begin produce a diff wiht len == 2 |a | others with 1 |a|
|
||||||
@ -43,7 +39,6 @@ class command():
|
|||||||
currNegativeDelta.strip() != '':
|
currNegativeDelta.strip() != '':
|
||||||
currNegativeDelta = currNegativeDelta.strip()
|
currNegativeDelta = currNegativeDelta.strip()
|
||||||
self.env['runtime']['outputManager'].presentText(currNegativeDelta, interrupt=True, ignorePunctuation=True, announceCapital=True, flush=False)
|
self.env['runtime']['outputManager'].presentText(currNegativeDelta, interrupt=True, ignorePunctuation=True, announceCapital=True, flush=False)
|
||||||
|
|
||||||
def setCallback(self, callback):
|
def setCallback(self, callback):
|
||||||
pass
|
pass
|
||||||
|
|
26
src/fenrir/commands/onCursorChange/66000-exit_review_mode.py
Normal file
26
src/fenrir/commands/onCursorChange/66000-exit_review_mode.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Fenrir TTY screen reader
|
||||||
|
# By Chrys, Storm Dragon, and contributers.
|
||||||
|
|
||||||
|
from core import debug
|
||||||
|
|
||||||
|
class command():
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
def initialize(self, environment):
|
||||||
|
self.env = environment
|
||||||
|
def shutdown(self):
|
||||||
|
pass
|
||||||
|
def getDescription(self):
|
||||||
|
return _('exits review mode')
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
if not self.env['runtime']['settingsManager'].getSettingAsBool('review', 'leaveReviewOnCursorChange'):
|
||||||
|
return
|
||||||
|
if self.env['runtime']['cursorManager'].isReviewMode():
|
||||||
|
self.env['runtime']['cursorManager'].clearReviewCursor()
|
||||||
|
|
||||||
|
def setCallback(self, callback):
|
||||||
|
pass
|
29
src/fenrir/commands/onHeartBeat/2000-GetSessionInfo.py
Executable file
29
src/fenrir/commands/onHeartBeat/2000-GetSessionInfo.py
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/python
|
||||||
|
import time
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Fenrir TTY screen reader
|
||||||
|
# By Chrys, Storm Dragon, and contributers.
|
||||||
|
|
||||||
|
from core import debug
|
||||||
|
import time
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
class command():
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
def initialize(self, environment):
|
||||||
|
self.env = environment
|
||||||
|
self.lastTime = datetime.datetime.now()
|
||||||
|
self.lastDateString = ''
|
||||||
|
self.lastTimeString = ''
|
||||||
|
def shutdown(self):
|
||||||
|
pass
|
||||||
|
def getDescription(self):
|
||||||
|
return 'No Description found'
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.env['runtime']['screenDriver'].getSessionInformation()
|
||||||
|
def setCallback(self, callback):
|
||||||
|
pass
|
||||||
|
|
0
src/fenrir/commands/onScreenUpdate/76000-time.py → src/fenrir/commands/onHeartBeat/76000-time.py
Normal file → Executable file
0
src/fenrir/commands/onScreenUpdate/76000-time.py → src/fenrir/commands/onHeartBeat/76000-time.py
Normal file → Executable file
0
src/fenrir/commands/onHeartBeat/__init__.py
Executable file
0
src/fenrir/commands/onHeartBeat/__init__.py
Executable file
@ -1,33 +0,0 @@
|
|||||||
#!/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Fenrir TTY screen reader
|
|
||||||
# By Chrys, Storm Dragon, and contributers.
|
|
||||||
|
|
||||||
from core import debug
|
|
||||||
|
|
||||||
class command():
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
def initialize(self, environment):
|
|
||||||
self.env = environment
|
|
||||||
def shutdown(self):
|
|
||||||
pass
|
|
||||||
def getDescription(self):
|
|
||||||
return 'No Description found'
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
return
|
|
||||||
if not self.env['runtime']['settingsManager'].getSettingAsBool('review', 'leaveReviewOnKeypress'):
|
|
||||||
return
|
|
||||||
if not self.env['runtime']['inputManager'].noKeyPressed():
|
|
||||||
return
|
|
||||||
if self.env['runtime']['screenManager'].isScreenChange():
|
|
||||||
return
|
|
||||||
if len(self.env['input']['prevDeepestInput']) > len(self.env['input']['currInput']):
|
|
||||||
return
|
|
||||||
self.env['runtime']['cursorManager'].clearReviewCursor()
|
|
||||||
|
|
||||||
def setCallback(self, callback):
|
|
||||||
pass
|
|
||||||
|
|
22
src/fenrir/commands/onPlugInputDevice/50000-UpdateDevices.py
Executable file
22
src/fenrir/commands/onPlugInputDevice/50000-UpdateDevices.py
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Fenrir TTY screen reader
|
||||||
|
# By Chrys, Storm Dragon, and contributers.
|
||||||
|
|
||||||
|
from core import debug
|
||||||
|
|
||||||
|
class command():
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
def initialize(self, environment):
|
||||||
|
self.env = environment
|
||||||
|
def shutdown(self):
|
||||||
|
pass
|
||||||
|
def getDescription(self):
|
||||||
|
return 'No description found'
|
||||||
|
def run(self):
|
||||||
|
if not self.env['runtime']['screenManager'].isSuspendingScreen(): # remove if all works
|
||||||
|
self.env['runtime']['inputManager'].updateInputDevices()
|
||||||
|
def setCallback(self, callback):
|
||||||
|
pass
|
@ -17,23 +17,23 @@ class command():
|
|||||||
return 'No Description found'
|
return 'No Description found'
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
if not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'autoReadIncoming'):
|
if not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'autoReadIncoming'):
|
||||||
return
|
return
|
||||||
# is there something to read?
|
# is there something to read?
|
||||||
if not self.env['runtime']['screenManager'].isDelta():
|
if not self.env['runtime']['screenManager'].isDelta():
|
||||||
return
|
return
|
||||||
|
if len(self.env['screen']['newDelta']) <=2:
|
||||||
|
return
|
||||||
# its a cursor movement (experimental) - maybe also check current shortcut string?
|
# its a cursor movement (experimental) - maybe also check current shortcut string?
|
||||||
|
|
||||||
#if not '$' in self.env['screen']['newDelta'] and
|
#if not '$' in self.env['screen']['newDelta'] and
|
||||||
# not '#' in self.env['screen']['newDelta']:
|
# not '#' in self.env['screen']['newDelta']:
|
||||||
if abs(self.env['screen']['newCursor']['x'] - self.env['screen']['oldCursor']['x']) >= 1:
|
if abs(self.env['screen']['newCursor']['x'] - self.env['screen']['oldCursor']['x']) == 1:
|
||||||
if len(self.env['screen']['newDelta'].strip(' \n\t0123456789')) <= 2:
|
# if len(self.env['screen']['newDelta'].strip(' \n\t0123456789')) <= 2:
|
||||||
return
|
return
|
||||||
if abs(self.env['screen']['newCursor']['y'] - self.env['screen']['oldCursor']['y']) == 1:
|
if abs(self.env['screen']['newCursor']['y'] - self.env['screen']['oldCursor']['y']) == 1:
|
||||||
if len(self.env['screen']['newDelta'].strip(' \n\t0123456789')) <= 2:
|
# if len(self.env['screen']['newDelta'].strip(' \n\t0123456789')) <= 2:
|
||||||
return
|
return
|
||||||
self.env['runtime']['outputManager'].presentText(self.env['screen']['newDelta'], interrupt=False, flush=False)
|
self.env['runtime']['outputManager'].presentText(self.env['screen']['newDelta'], interrupt=False, flush=False)
|
||||||
|
|
||||||
def setCallback(self, callback):
|
def setCallback(self, callback):
|
||||||
|
@ -22,7 +22,7 @@ class command():
|
|||||||
return
|
return
|
||||||
if self.env['runtime']['settingsManager'].getSetting('promote', 'list').strip(" \t\n") == '':
|
if self.env['runtime']['settingsManager'].getSetting('promote', 'list').strip(" \t\n") == '':
|
||||||
return
|
return
|
||||||
if self.env['screen']['newDelta'] == '':
|
if len(self.env['screen']['newDelta']) <= 2:
|
||||||
return
|
return
|
||||||
if int(time.time() - self.env['input']['lastInputTime']) < self.env['runtime']['settingsManager'].getSettingAsInt('promote', 'inactiveTimeoutSec'):
|
if int(time.time() - self.env['input']['lastInputTime']) < self.env['runtime']['settingsManager'].getSettingAsInt('promote', 'inactiveTimeoutSec'):
|
||||||
return
|
return
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
#!/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Fenrir TTY screen reader
|
|
||||||
# By Chrys, Storm Dragon, and contributers.
|
|
||||||
|
|
||||||
from core import debug
|
|
||||||
|
|
||||||
class command():
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
def initialize(self, environment):
|
|
||||||
self.env = environment
|
|
||||||
def shutdown(self):
|
|
||||||
pass
|
|
||||||
def getDescription(self):
|
|
||||||
return 'No Description found'
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
if not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'autoReadIncoming'):
|
|
||||||
return
|
|
||||||
# is there something to read?
|
|
||||||
#if not self.env['runtime']['screenManager'].isDelta():
|
|
||||||
# return
|
|
||||||
|
|
||||||
# its a cursor movement (experimental) - maybe also check current shortcut string?
|
|
||||||
if abs(self.env['screen']['newCursor']['x'] - self.env['screen']['oldCursor']['x']) >= 1:
|
|
||||||
if len(self.env['screen']['newDelta'].strip(' \n\t')) <= 2:
|
|
||||||
return
|
|
||||||
#if abs(self.env['screen']['newCursor']['y'] - self.env['screen']['oldCursor']['y']) = 1:
|
|
||||||
# return
|
|
||||||
self.env['runtime']['outputManager'].presentText(self.env['screen']['newDelta'], interrupt=False, flush=False)
|
|
||||||
|
|
||||||
def setCallback(self, callback):
|
|
||||||
pass
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
|||||||
from core import debug
|
from core import debug
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
# used as shared memory between commands
|
# used as shared memory between commands
|
||||||
# use this in your own commands
|
# use this in your own commands
|
||||||
commandBuffer = {
|
commandBuffer = {
|
||||||
@ -24,39 +23,7 @@ commandBuffer = {
|
|||||||
|
|
||||||
# used by the commandManager
|
# used by the commandManager
|
||||||
commandInfo = {
|
commandInfo = {
|
||||||
'currCommand': '',
|
#'currCommand': '',
|
||||||
'lastCommandExecutionTime': time.time(),
|
'lastCommandExecutionTime': time.time(),
|
||||||
'lastCommandRequestTime': time.time(),
|
'lastCommandRequestTime': time.time(),
|
||||||
}
|
}
|
||||||
|
|
||||||
# used by the commandManager
|
|
||||||
commands = {
|
|
||||||
'onInput':{
|
|
||||||
},
|
|
||||||
'onScreenChanged':{
|
|
||||||
},
|
|
||||||
'onScreenUpdate':{
|
|
||||||
},
|
|
||||||
'onApplicationChange':{
|
|
||||||
},
|
|
||||||
'commands':{
|
|
||||||
},
|
|
||||||
'onSwitchApplicationProfile':{
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
# used by the commandManager
|
|
||||||
commandsIgnore = {
|
|
||||||
'onInput':{
|
|
||||||
},
|
|
||||||
'onScreenChanged':{
|
|
||||||
},
|
|
||||||
'onScreenUpdate':{
|
|
||||||
},
|
|
||||||
'onApplicationChange':{
|
|
||||||
},
|
|
||||||
'commands':{
|
|
||||||
},
|
|
||||||
'onSwitchApplicationProfile':{
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
@ -15,10 +15,13 @@ class commandManager():
|
|||||||
def initialize(self, environment):
|
def initialize(self, environment):
|
||||||
self.env = environment
|
self.env = environment
|
||||||
# commands
|
# commands
|
||||||
|
self.env['commands'] = {}
|
||||||
|
self.env['commandsIgnore'] = {}
|
||||||
for commandFolder in self.env['general']['commandFolderList']:
|
for commandFolder in self.env['general']['commandFolderList']:
|
||||||
self.env['runtime']['commandManager'].loadCommands(commandFolder,
|
self.env['runtime']['commandManager'].loadCommands(commandFolder)
|
||||||
self.env['runtime']['settingsManager'].getSetting('general', 'commandPath'))
|
if self.env['runtime']['settingsManager'].getSetting('general', 'commandPath') != '':
|
||||||
self.env['runtime']['commandManager'].loadCommands(commandFolder)
|
self.env['runtime']['commandManager'].loadCommands(commandFolder,
|
||||||
|
self.env['runtime']['settingsManager'].getSetting('general', 'commandPath'))
|
||||||
|
|
||||||
# scripts for scriptKey
|
# scripts for scriptKey
|
||||||
self.env['runtime']['commandManager'].loadScriptCommands()
|
self.env['runtime']['commandManager'].loadScriptCommands()
|
||||||
@ -42,7 +45,8 @@ class commandManager():
|
|||||||
if not os.access(commandFolder, os.R_OK):
|
if not os.access(commandFolder, os.R_OK):
|
||||||
self.env['runtime']['debug'].writeDebugOut("commandFolder not readable:" + commandFolder ,debug.debugLevel.ERROR)
|
self.env['runtime']['debug'].writeDebugOut("commandFolder not readable:" + commandFolder ,debug.debugLevel.ERROR)
|
||||||
return
|
return
|
||||||
|
self.env['commands'][section] = {}
|
||||||
|
self.env['commandsIgnore'][section] = {}
|
||||||
commandList = glob.glob(commandFolder+'*')
|
commandList = glob.glob(commandFolder+'*')
|
||||||
for command in commandList:
|
for command in commandList:
|
||||||
try:
|
try:
|
||||||
@ -62,7 +66,6 @@ class commandManager():
|
|||||||
self.env['commands'][section][fileName.upper()].initialize(self.env)
|
self.env['commands'][section][fileName.upper()].initialize(self.env)
|
||||||
self.env['runtime']['debug'].writeDebugOut("Load command:" + section + "." + fileName.upper() ,debug.debugLevel.INFO, onAnyLevel=True)
|
self.env['runtime']['debug'].writeDebugOut("Load command:" + section + "." + fileName.upper() ,debug.debugLevel.INFO, onAnyLevel=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(command+str(e))
|
|
||||||
self.env['runtime']['debug'].writeDebugOut("Loading command:" + command ,debug.debugLevel.ERROR)
|
self.env['runtime']['debug'].writeDebugOut("Loading command:" + command ,debug.debugLevel.ERROR)
|
||||||
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
|
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
|
||||||
continue
|
continue
|
||||||
@ -123,7 +126,6 @@ class commandManager():
|
|||||||
shortcut.append(sorted(shortcutKeys))
|
shortcut.append(sorted(shortcutKeys))
|
||||||
self.env['bindings'][str(shortcut)] = fileName.upper()
|
self.env['bindings'][str(shortcut)] = fileName.upper()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
|
||||||
self.env['runtime']['debug'].writeDebugOut("Loading script:" + command ,debug.debugLevel.ERROR)
|
self.env['runtime']['debug'].writeDebugOut("Loading script:" + command ,debug.debugLevel.ERROR)
|
||||||
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
|
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
|
||||||
continue
|
continue
|
||||||
@ -172,37 +174,47 @@ class commandManager():
|
|||||||
self.env['runtime']['debug'].writeDebugOut("Executing trigger.command:" + trigger + "." + command ,debug.debugLevel.INFO)
|
self.env['runtime']['debug'].writeDebugOut("Executing trigger.command:" + trigger + "." + command ,debug.debugLevel.INFO)
|
||||||
self.env['commands'][trigger][command].run()
|
self.env['commands'][trigger][command].run()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.env['runtime']['debug'].writeDebugOut("Executing trigger:" + trigger + "." + command ,debug.debugLevel.ERROR)
|
self.env['runtime']['debug'].writeDebugOut("Executing trigger:" + trigger + "." + command + str(e) ,debug.debugLevel.ERROR)
|
||||||
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
|
|
||||||
|
|
||||||
def executeCommand(self, command, section = 'commands'):
|
def executeCommand(self, command, section = 'commands'):
|
||||||
if self.env['runtime']['screenManager'].isSuspendingScreen():
|
if self.env['runtime']['screenManager'].isSuspendingScreen():
|
||||||
return
|
return
|
||||||
if self.commandExists(command, section):
|
if self.commandExists(command, section):
|
||||||
try:
|
try:
|
||||||
if self.env['general']['tutorialMode']:
|
if self.env['runtime']['helpManager'].isTutorialMode() and section != 'help':
|
||||||
self.env['runtime']['debug'].writeDebugOut("Tutorial for command:" + section + "." + command ,debug.debugLevel.INFO)
|
self.env['runtime']['debug'].writeDebugOut("Tutorial for command:" + section + "." + command ,debug.debugLevel.INFO)
|
||||||
description = self.env['commands'][section][command].getDescription()
|
description = self.getCommandDescription(command, section)
|
||||||
self.env['runtime']['outputManager'].presentText(description, interrupt=True)
|
self.env['runtime']['outputManager'].presentText(description, interrupt=True)
|
||||||
else:
|
else:
|
||||||
self.env['runtime']['debug'].writeDebugOut("Executing command:" + section + "." + command ,debug.debugLevel.INFO)
|
self.env['runtime']['debug'].writeDebugOut("Executing command:" + section + "." + command ,debug.debugLevel.INFO)
|
||||||
self.env['commands'][section][command].run()
|
self.runCommand(command, section)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.env['runtime']['debug'].writeDebugOut("Executing command:" + section + "." + command ,debug.debugLevel.ERROR)
|
self.env['runtime']['debug'].writeDebugOut("Executing command:" + section + "." + command +' ' + str(e),debug.debugLevel.ERROR)
|
||||||
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
|
|
||||||
self.clearCommandQueued()
|
|
||||||
|
def runCommand(self, command, section = 'commands'):
|
||||||
|
if self.commandExists(command, section):
|
||||||
|
try:
|
||||||
|
self.env['runtime']['debug'].writeDebugOut("Executing command:" + section + "." + command ,debug.debugLevel.INFO)
|
||||||
|
self.env['commands'][section][command].run()
|
||||||
|
except Exception as e:
|
||||||
|
self.env['runtime']['debug'].writeDebugOut("Executing command:" + section + "." + command +' ' + str(e),debug.debugLevel.ERROR)
|
||||||
self.env['commandInfo']['lastCommandExecutionTime'] = time.time()
|
self.env['commandInfo']['lastCommandExecutionTime'] = time.time()
|
||||||
|
|
||||||
def isCommandQueued(self):
|
|
||||||
return self.env['commandInfo']['currCommand'] != ''
|
|
||||||
|
|
||||||
def clearCommandQueued(self):
|
|
||||||
self.env['commandInfo']['currCommand'] = ''
|
|
||||||
|
|
||||||
def queueCommand(self, command):
|
def getCommandDescription(self, command, section = 'commands'):
|
||||||
if command == '':
|
if self.commandExists(command, section):
|
||||||
return
|
try:
|
||||||
self.env['commandInfo']['currCommand'] = command
|
return self.env['commands'][section][command].getDescription()
|
||||||
|
except Exception as e:
|
||||||
|
self.env['runtime']['debug'].writeDebugOut('commandManager.getCommandDescription:' + str(e),debug.debugLevel.ERROR)
|
||||||
|
self.env['commandInfo']['lastCommandExecutionTime'] = time.time()
|
||||||
|
|
||||||
def commandExists(self, command, section = 'commands'):
|
def commandExists(self, command, section = 'commands'):
|
||||||
return( command in self.env['commands'][section])
|
return( command in self.env['commands'][section])
|
||||||
|
def getShortcutForCommand(self, command):
|
||||||
|
shortcut = ''
|
||||||
|
try:
|
||||||
|
shortcut = list(self.env['bindings'].keys())[list(self.env['bindings'].values()).index(command)]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return shortcut
|
||||||
|
@ -19,8 +19,6 @@ environment = {
|
|||||||
'runtime': runtimeData,
|
'runtime': runtimeData,
|
||||||
'general': generalData,
|
'general': generalData,
|
||||||
'settings': settingsData,
|
'settings': settingsData,
|
||||||
'commands': commandData.commands,
|
|
||||||
'commandsIgnore': commandData.commandsIgnore,
|
|
||||||
'commandInfo': commandData.commandInfo,
|
'commandInfo': commandData.commandInfo,
|
||||||
'commandBuffer': commandData.commandBuffer,
|
'commandBuffer': commandData.commandBuffer,
|
||||||
'input': inputData,
|
'input': inputData,
|
||||||
|
24
src/fenrir/core/eventData.py
Executable file
24
src/fenrir/core/eventData.py
Executable file
@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Fenrir TTY screen reader
|
||||||
|
# By Chrys, Storm Dragon, and contributers.
|
||||||
|
|
||||||
|
from core import debug
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
class fenrirEventType(Enum):
|
||||||
|
Ignore = 0
|
||||||
|
StopMainLoop = 1
|
||||||
|
ScreenUpdate = 2
|
||||||
|
KeyboardInput = 3
|
||||||
|
BrailleInput = 4
|
||||||
|
PlugInputDevice = 5
|
||||||
|
BrailleFlush = 6
|
||||||
|
ScreenChanged = 7
|
||||||
|
HeartBeat = 8 # for time based scheduling
|
||||||
|
ExecuteCommand = 9
|
||||||
|
def __int__(self):
|
||||||
|
return self.value
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
@ -4,29 +4,14 @@
|
|||||||
# Fenrir TTY screen reader
|
# Fenrir TTY screen reader
|
||||||
# By Chrys, Storm Dragon, and contributers.
|
# By Chrys, Storm Dragon, and contributers.
|
||||||
|
|
||||||
#from core import debug
|
from core import debug
|
||||||
|
from core.eventData import fenrirEventType
|
||||||
from queue import Empty
|
from queue import Empty
|
||||||
import time
|
import time
|
||||||
from enum import Enum
|
|
||||||
from multiprocessing import Process, Queue
|
from multiprocessing import Process, Queue
|
||||||
from multiprocessing.sharedctypes import Value
|
from multiprocessing.sharedctypes import Value
|
||||||
from ctypes import c_bool
|
from ctypes import c_bool
|
||||||
|
|
||||||
class fenrirEventType(Enum):
|
|
||||||
Ignore = 0
|
|
||||||
StopMainLoop = 1
|
|
||||||
ScreenUpdate = 2
|
|
||||||
KeyboardInput = 3
|
|
||||||
BrailleInput = 4
|
|
||||||
PlugInputDevice = 5
|
|
||||||
BrailleFlush = 6
|
|
||||||
ScreenChanged = 7
|
|
||||||
def __int__(self):
|
|
||||||
return self.value
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
|
|
||||||
class eventManager():
|
class eventManager():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._mainLoopRunning = Value(c_bool, True)
|
self._mainLoopRunning = Value(c_bool, True)
|
||||||
@ -34,11 +19,20 @@ class eventManager():
|
|||||||
self._eventQueue = Queue() # multiprocessing.Queue()
|
self._eventQueue = Queue() # multiprocessing.Queue()
|
||||||
self.cleanEventQueue()
|
self.cleanEventQueue()
|
||||||
def initialize(self, environment):
|
def initialize(self, environment):
|
||||||
self.env = environment
|
self.env = environment
|
||||||
|
self.addSimpleEventThread(fenrirEventType.HeartBeat, self.heartBeatTimer)
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
self.terminateAllProcesses()
|
self.terminateAllProcesses()
|
||||||
self.cleanEventQueue()
|
self.cleanEventQueue()
|
||||||
|
def heartBeatTimer(self):
|
||||||
|
try:
|
||||||
|
time.sleep(0.5)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
#self.env['runtime']['settingsManager'].getSettingAsFloat('screen', 'screenUpdateDelay')
|
||||||
|
return time.time()
|
||||||
def terminateAllProcesses(self):
|
def terminateAllProcesses(self):
|
||||||
|
time.sleep(1)
|
||||||
for proc in self._eventProcesses:
|
for proc in self._eventProcesses:
|
||||||
try:
|
try:
|
||||||
proc.terminate()
|
proc.terminate()
|
||||||
@ -46,20 +40,24 @@ class eventManager():
|
|||||||
print(e)
|
print(e)
|
||||||
def proceedEventLoop(self):
|
def proceedEventLoop(self):
|
||||||
event = self._eventQueue.get()
|
event = self._eventQueue.get()
|
||||||
|
st = time.time()
|
||||||
self.eventDispatcher(event)
|
self.eventDispatcher(event)
|
||||||
|
#print('NET loop ' + str(time.time() - st))
|
||||||
def eventDispatcher(self, event):
|
def eventDispatcher(self, event):
|
||||||
|
self.env['runtime']['debug'].writeDebugOut('eventManager:eventDispatcher:start: event:' + str(event['Type']) + ' QueueSize:' + str( self._eventQueue.qsize()),debug.debugLevel.INFO)
|
||||||
if not event:
|
if not event:
|
||||||
return
|
return
|
||||||
|
if not event['Type']:
|
||||||
|
return
|
||||||
if event['Type'] == fenrirEventType.Ignore:
|
if event['Type'] == fenrirEventType.Ignore:
|
||||||
return
|
return
|
||||||
elif event['Type'] == fenrirEventType.StopMainLoop:
|
elif event['Type'] == fenrirEventType.StopMainLoop:
|
||||||
self._mainLoopRunning.value = 0
|
self.handleStopMainLoop(event)
|
||||||
return
|
return
|
||||||
elif event['Type'] == fenrirEventType.ScreenUpdate:
|
elif event['Type'] == fenrirEventType.ScreenUpdate:
|
||||||
print('do an update')
|
self.env['runtime']['fenrirManager'].handleScreenUpdate(event)
|
||||||
pass
|
|
||||||
elif event['Type'] == fenrirEventType.KeyboardInput:
|
elif event['Type'] == fenrirEventType.KeyboardInput:
|
||||||
pass
|
self.env['runtime']['fenrirManager'].handleInput(event)
|
||||||
elif event['Type'] == fenrirEventType.BrailleInput:
|
elif event['Type'] == fenrirEventType.BrailleInput:
|
||||||
pass
|
pass
|
||||||
elif event['Type'] == fenrirEventType.PlugInputDevice:
|
elif event['Type'] == fenrirEventType.PlugInputDevice:
|
||||||
@ -67,20 +65,42 @@ class eventManager():
|
|||||||
elif event['Type'] == fenrirEventType.BrailleFlush:
|
elif event['Type'] == fenrirEventType.BrailleFlush:
|
||||||
pass
|
pass
|
||||||
elif event['Type'] == fenrirEventType.ScreenChanged:
|
elif event['Type'] == fenrirEventType.ScreenChanged:
|
||||||
pass
|
self.env['runtime']['fenrirManager'].handleScreenChange(event)
|
||||||
|
elif event['Type'] == fenrirEventType.HeartBeat:
|
||||||
|
self.env['runtime']['fenrirManager'].handleHeartBeat(event)
|
||||||
|
elif event['Type'] == fenrirEventType.ExecuteCommand:
|
||||||
|
self.env['runtime']['fenrirManager'].handleExecuteCommand(event)
|
||||||
|
def isMainEventLoopRunning(self):
|
||||||
|
return self._mainLoopRunning.value == 1
|
||||||
def startMainEventLoop(self):
|
def startMainEventLoop(self):
|
||||||
self._mainLoopRunning.value = True
|
self._mainLoopRunning.value = 1
|
||||||
while(self._mainLoopRunning.value):
|
while( self.isMainEventLoopRunning()):
|
||||||
self.proceedEventLoop()
|
self.proceedEventLoop()
|
||||||
|
|
||||||
|
def handleStopMainLoop(self, event):
|
||||||
|
self._mainLoopRunning.value = 0
|
||||||
|
time.sleep(0.1)
|
||||||
def stopMainEventLoop(self, Force = False):
|
def stopMainEventLoop(self, Force = False):
|
||||||
if Force:
|
if Force:
|
||||||
self._mainLoopRunning.value = False
|
self._mainLoopRunning.value = 0
|
||||||
self._eventQueue.put({"Type":fenrirEventType.StopMainLoop,"Data":None})
|
self._eventQueue.put({"Type":fenrirEventType.StopMainLoop,"Data":None})
|
||||||
def addEventThread(self, event, function):
|
def addCustomEventThread(self, function, pargs = None, multiprocess=False):
|
||||||
self._mainLoopRunning.value = True
|
self._mainLoopRunning.value = 1
|
||||||
t = Process(target=self.eventWorkerThread, args=(event, function))
|
|
||||||
|
if multiprocess:
|
||||||
|
t = Process(target=self.customEventWorkerThread, args=(self._eventQueue, function, pargs))
|
||||||
|
else:# thread not implemented yet
|
||||||
|
t = Process(target=self.customEventWorkerThread, args=(self._eventQueue, function, pargs))
|
||||||
self._eventProcesses.append(t)
|
self._eventProcesses.append(t)
|
||||||
t.start()
|
t.start()
|
||||||
|
def addSimpleEventThread(self, event, function, pargs = None, multiprocess=False, runOnce = False):
|
||||||
|
self._mainLoopRunning.value = 1
|
||||||
|
if multiprocess:
|
||||||
|
t = Process(target=self.simpleEventWorkerThread, args=(event, function, pargs))
|
||||||
|
self._eventProcesses.append(t)
|
||||||
|
else:# thread not implemented yet
|
||||||
|
t = Process(target=self.simpleEventWorkerThread, args=(event, function, pargs))
|
||||||
|
t.start()
|
||||||
def cleanEventQueue(self):
|
def cleanEventQueue(self):
|
||||||
if self._eventQueue.empty():
|
if self._eventQueue.empty():
|
||||||
return
|
return
|
||||||
@ -94,32 +114,34 @@ class eventManager():
|
|||||||
return False
|
return False
|
||||||
self._eventQueue.put({"Type":event,"Data":data})
|
self._eventQueue.put({"Type":event,"Data":data})
|
||||||
return True
|
return True
|
||||||
def eventWorkerThread(self, event, function):
|
def customEventWorkerThread(self, eventQueue, function, args):
|
||||||
|
#if not isinstance(eventQueue, Queue):
|
||||||
|
# return
|
||||||
|
if not callable(function):
|
||||||
|
return
|
||||||
|
while self.isMainEventLoopRunning():
|
||||||
|
try:
|
||||||
|
if args:
|
||||||
|
function(self._mainLoopRunning, eventQueue, args)
|
||||||
|
else:
|
||||||
|
function(self._mainLoopRunning, eventQueue)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
def simpleEventWorkerThread(self, event, function, args, runOnce = False):
|
||||||
if not isinstance(event, fenrirEventType):
|
if not isinstance(event, fenrirEventType):
|
||||||
return
|
return
|
||||||
if not callable(function):
|
if not callable(function):
|
||||||
return
|
return
|
||||||
while self._mainLoopRunning.value:
|
while self.isMainEventLoopRunning():
|
||||||
Data = None
|
Data = None
|
||||||
try:
|
try:
|
||||||
Data = function()
|
if args != None:
|
||||||
|
Data = function(self._mainLoopRunning, args)
|
||||||
|
else:
|
||||||
|
Data = function()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
self.env['runtime']['debug'].writeDebugOut('eventManager:simpleEventWorkerThread:function():' + st(e),debug.debugLevel.ERROR)
|
||||||
self.putToEventQueue(event, Data)
|
self.putToEventQueue(event, Data)
|
||||||
'''
|
if runOnce:
|
||||||
def p():
|
break
|
||||||
time.sleep(0.02)
|
|
||||||
return("p")
|
|
||||||
|
|
||||||
i = 1
|
|
||||||
e = eventManager()
|
|
||||||
e.addEventThread(fenrirEventType.ScreenUpdate,p)
|
|
||||||
e.addEventThread(fenrirEventType.BrailleInput,p)
|
|
||||||
e.addEventThread(fenrirEventType.PlugInputDevice,p)
|
|
||||||
e.addEventThread(fenrirEventType.ScreenChanged,p)
|
|
||||||
time.sleep(1.5)
|
|
||||||
e.addEventThread(fenrirEventType.StopMainLoop,e.stopMainEventLoop)
|
|
||||||
s = time.time()
|
|
||||||
e.startMainEventLoop()
|
|
||||||
print(time.time() - s )
|
|
||||||
'''
|
|
||||||
|
@ -13,6 +13,7 @@ if not os.path.dirname(os.path.realpath(fenrirVersion.__file__)) in sys.path:
|
|||||||
from core import i18n
|
from core import i18n
|
||||||
from core import settingsManager
|
from core import settingsManager
|
||||||
from core import debug
|
from core import debug
|
||||||
|
from core.eventData import fenrirEventType
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
class fenrirManager():
|
class fenrirManager():
|
||||||
@ -22,22 +23,24 @@ class fenrirManager():
|
|||||||
if not cliArgs:
|
if not cliArgs:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
self.environment = settingsManager.settingsManager().initFenrirConfig(cliArgs)
|
self.environment = settingsManager.settingsManager().initFenrirConfig(cliArgs, self)
|
||||||
if not self.environment:
|
if not self.environment:
|
||||||
raise RuntimeError('Cannot Initialize. Maybe the configfile is not available or not parseable')
|
raise RuntimeError('Cannot Initialize. Maybe the configfile is not available or not parseable')
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
raise
|
raise
|
||||||
self.initialized = True
|
|
||||||
self.environment['runtime']['outputManager'].presentText(_("Start Fenrir"), soundIcon='ScreenReaderOn', interrupt=True)
|
self.environment['runtime']['outputManager'].presentText(_("Start Fenrir"), soundIcon='ScreenReaderOn', interrupt=True)
|
||||||
signal.signal(signal.SIGINT, self.captureSignal)
|
signal.signal(signal.SIGINT, self.captureSignal)
|
||||||
signal.signal(signal.SIGTERM, self.captureSignal)
|
signal.signal(signal.SIGTERM, self.captureSignal)
|
||||||
self.wasCommand = False
|
self.initialized = True
|
||||||
|
self.modifierInput = False
|
||||||
|
self.singleKeyCommand = False
|
||||||
|
self.command = ''
|
||||||
def handleArgs(self):
|
def handleArgs(self):
|
||||||
args = None
|
args = None
|
||||||
parser = argparse.ArgumentParser(description="Fenrir Help")
|
parser = argparse.ArgumentParser(description="Fenrir Help")
|
||||||
parser.add_argument('-s', '--setting', metavar='SETTING-FILE', default='/etc/fenrir/settings/settings.conf', help='Use a specified settingsfile')
|
parser.add_argument('-s', '--setting', metavar='SETTING-FILE', default='/etc/fenrir/settings/settings.conf', help='Use a specified settingsfile')
|
||||||
parser.add_argument('-o', '--options', metavar='SECTION#SETTING=VALUE,..', default='', help='Overwrite options in given settings file')
|
parser.add_argument('-o', '--options', metavar='SECTION#SETTING=VALUE,..', default='', help='Overwrite options in given settings file')
|
||||||
|
parser.add_argument('-d', '--debug', action='store_true', help='Turns on Debugmode')
|
||||||
try:
|
try:
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -46,79 +49,123 @@ class fenrirManager():
|
|||||||
def proceed(self):
|
def proceed(self):
|
||||||
if not self.initialized:
|
if not self.initialized:
|
||||||
return
|
return
|
||||||
while(self.environment['general']['running']):
|
self.environment['runtime']['eventManager'].startMainEventLoop()
|
||||||
try:
|
|
||||||
self.handleProcess()
|
|
||||||
except Exception as e:
|
|
||||||
self.environment['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
|
|
||||||
self.shutdown()
|
self.shutdown()
|
||||||
|
def handleInput(self, event):
|
||||||
def handleProcess(self):
|
#startTime = time.time()
|
||||||
eventReceived = self.environment['runtime']['inputManager'].getInputEvent()
|
eventReceived = self.environment['runtime']['inputManager'].getInputEvent()
|
||||||
startTime = time.time()
|
|
||||||
if not eventReceived:
|
|
||||||
if not self.environment['runtime']['screenManager'].isSuspendingScreen():
|
|
||||||
self.environment['runtime']['inputManager'].updateInputDevices()
|
|
||||||
if eventReceived:
|
if eventReceived:
|
||||||
self.prepareCommand()
|
|
||||||
if not (self.wasCommand or self.environment['general']['tutorialMode']) or self.environment['runtime']['screenManager'].isSuspendingScreen():
|
if self.environment['runtime']['screenManager'].isSuspendingScreen():
|
||||||
self.environment['runtime']['inputManager'].writeEventBuffer()
|
self.environment['runtime']['inputManager'].writeEventBuffer()
|
||||||
|
else:
|
||||||
|
if self.environment['runtime']['helpManager'].isTutorialMode():
|
||||||
|
self.environment['runtime']['inputManager'].clearEventBuffer()
|
||||||
|
|
||||||
|
self.detectCommand()
|
||||||
|
|
||||||
|
if self.modifierInput:
|
||||||
|
self.environment['runtime']['inputManager'].clearEventBuffer()
|
||||||
|
if self.singleKeyCommand:
|
||||||
|
if self.environment['runtime']['inputManager'].noKeyPressed():
|
||||||
|
self.environment['runtime']['inputManager'].clearEventBuffer()
|
||||||
|
else:
|
||||||
|
self.environment['runtime']['inputManager'].writeEventBuffer()
|
||||||
if self.environment['runtime']['inputManager'].noKeyPressed():
|
if self.environment['runtime']['inputManager'].noKeyPressed():
|
||||||
if self.wasCommand:
|
self.modifierInput = False
|
||||||
self.wasCommand = False
|
self.singleKeyCommand = False
|
||||||
self.environment['runtime']['inputManager'].clearEventBuffer()
|
if self.environment['input']['keyForeward'] > 0:
|
||||||
if self.environment['general']['tutorialMode']:
|
self.environment['input']['keyForeward'] -=1
|
||||||
self.environment['runtime']['inputManager'].clearEventBuffer()
|
|
||||||
if self.environment['input']['keyForeward'] > 0:
|
|
||||||
self.environment['input']['keyForeward'] -=1
|
|
||||||
self.environment['runtime']['screenManager'].update('onInput')
|
self.environment['runtime']['screenManager'].update('onInput')
|
||||||
self.environment['runtime']['commandManager'].executeDefaultTrigger('onInput')
|
self.environment['runtime']['commandManager'].executeDefaultTrigger('onInput')
|
||||||
else:
|
#print('handleInput:',time.time() - startTime)
|
||||||
self.environment['runtime']['screenManager'].update('onUpdate')
|
def handleExecuteCommand(self, event):
|
||||||
|
if event['Data'] == '':
|
||||||
|
return
|
||||||
|
command = event['Data']
|
||||||
|
if self.environment['runtime']['helpManager'].isTutorialMode():
|
||||||
|
if self.environment['runtime']['commandManager'].commandExists( command, 'help'):
|
||||||
|
self.environment['runtime']['commandManager'].executeCommand( command, 'help')
|
||||||
|
return
|
||||||
|
self.environment['runtime']['commandManager'].executeCommand( command, 'commands')
|
||||||
|
def handleScreenChange(self, event):
|
||||||
|
self.environment['runtime']['screenManager'].update('onScreenChange')
|
||||||
|
'''
|
||||||
if self.environment['runtime']['applicationManager'].isApplicationChange():
|
if self.environment['runtime']['applicationManager'].isApplicationChange():
|
||||||
self.environment['runtime']['commandManager'].executeDefaultTrigger('onApplicationChange')
|
self.environment['runtime']['commandManager'].executeDefaultTrigger('onApplicationChange')
|
||||||
self.environment['runtime']['commandManager'].executeSwitchTrigger('onSwitchApplicationProfile', \
|
self.environment['runtime']['commandManager'].executeSwitchTrigger('onSwitchApplicationProfile', \
|
||||||
self.environment['runtime']['applicationManager'].getPrevApplication(), \
|
self.environment['runtime']['applicationManager'].getPrevApplication(), \
|
||||||
self.environment['runtime']['applicationManager'].getCurrentApplication())
|
self.environment['runtime']['applicationManager'].getCurrentApplication())
|
||||||
|
'''
|
||||||
if self.environment['runtime']['screenManager'].isScreenChange():
|
self.environment['runtime']['commandManager'].executeDefaultTrigger('onScreenChanged')
|
||||||
self.environment['runtime']['commandManager'].executeDefaultTrigger('onScreenChanged')
|
|
||||||
else:
|
def handleScreenUpdate(self, event):
|
||||||
self.environment['runtime']['commandManager'].executeDefaultTrigger('onScreenUpdate')
|
#startTime = time.time()
|
||||||
#self.environment['runtime']['outputManager'].brailleText(flush=False)
|
|
||||||
self.handleCommands()
|
|
||||||
#print(time.time()-startTime)
|
|
||||||
|
|
||||||
def prepareCommand(self):
|
self.environment['runtime']['screenManager'].update('onUpdate')
|
||||||
if self.environment['runtime']['screenManager'].isSuspendingScreen():
|
'''
|
||||||
self.wasCommand = False
|
if self.environment['runtime']['applicationManager'].isApplicationChange():
|
||||||
return
|
self.environment['runtime']['commandManager'].executeDefaultTrigger('onApplicationChange')
|
||||||
if self.environment['runtime']['inputManager'].noKeyPressed():
|
self.environment['runtime']['commandManager'].executeSwitchTrigger('onSwitchApplicationProfile', \
|
||||||
return
|
self.environment['runtime']['applicationManager'].getPrevApplication(), \
|
||||||
|
self.environment['runtime']['applicationManager'].getCurrentApplication())
|
||||||
|
'''
|
||||||
|
# has cursor changed?
|
||||||
|
if self.environment['runtime']['cursorManager'].isCursorVerticalMove() or \
|
||||||
|
self.environment['runtime']['cursorManager'].isCursorHorizontalMove():
|
||||||
|
self.environment['runtime']['commandManager'].executeDefaultTrigger('onCursorChange')
|
||||||
|
self.environment['runtime']['commandManager'].executeDefaultTrigger('onScreenUpdate')
|
||||||
|
#print('handleScreenUpdate:',time.time() - startTime)
|
||||||
|
|
||||||
|
def handlePlugInputDevice(self, event):
|
||||||
|
self.environment['runtime']['commandManager'].executeDefaultTrigger('PlugInputDevice')
|
||||||
|
|
||||||
|
def handleHeartBeat(self, event):
|
||||||
|
self.environment['runtime']['commandManager'].executeDefaultTrigger('onHeartBeat')
|
||||||
|
#self.environment['runtime']['outputManager'].brailleText(flush=False)
|
||||||
|
|
||||||
|
def detectCommand(self):
|
||||||
if self.environment['input']['keyForeward'] > 0:
|
if self.environment['input']['keyForeward'] > 0:
|
||||||
return
|
return
|
||||||
shortcut = self.environment['runtime']['inputManager'].getCurrShortcut()
|
if self.environment['runtime']['inputManager'].isKeyPress():
|
||||||
command = self.environment['runtime']['inputManager'].getCommandForShortcut(shortcut)
|
self.modifierInput = self.environment['runtime']['inputManager'].currKeyIsModifier()
|
||||||
if len(self.environment['input']['prevDeepestInput']) <= len(self.environment['input']['currInput']):
|
else:
|
||||||
self.wasCommand = command != '' or self.environment['runtime']['inputManager'].isFenrirKeyPressed() or self.environment['runtime']['inputManager'].isScriptKeyPressed()
|
if not self.environment['runtime']['inputManager'].noKeyPressed():
|
||||||
if command == '':
|
if self.singleKeyCommand:
|
||||||
return
|
self.singleKeyCommand = len(self.environment['input']['prevDeepestInput']) == 1
|
||||||
|
# key is already released. we need the old one
|
||||||
self.environment['runtime']['commandManager'].queueCommand(command)
|
if not( self.singleKeyCommand and self.environment['runtime']['inputManager'].noKeyPressed()):
|
||||||
|
shortcut = self.environment['runtime']['inputManager'].getCurrShortcut()
|
||||||
|
self.command = self.environment['runtime']['inputManager'].getCommandForShortcut(shortcut)
|
||||||
|
if not self.modifierInput:
|
||||||
|
if self.environment['runtime']['inputManager'].isKeyPress():
|
||||||
|
if self.command != '':
|
||||||
|
self.singleKeyCommand = True
|
||||||
|
|
||||||
def handleCommands(self):
|
if not (self.singleKeyCommand or self.modifierInput):
|
||||||
if not self.environment['runtime']['commandManager'].isCommandQueued():
|
|
||||||
return
|
return
|
||||||
self.environment['runtime']['commandManager'].executeCommand( self.environment['commandInfo']['currCommand'], 'commands')
|
|
||||||
|
# fire event
|
||||||
|
if self.command != '':
|
||||||
|
if self.modifierInput:
|
||||||
|
self.environment['runtime']['eventManager'].putToEventQueue(fenrirEventType.ExecuteCommand, self.command)
|
||||||
|
self.command = ''
|
||||||
|
else:
|
||||||
|
if self.singleKeyCommand:
|
||||||
|
if self.environment['runtime']['inputManager'].noKeyPressed():
|
||||||
|
self.environment['runtime']['eventManager'].putToEventQueue(fenrirEventType.ExecuteCommand, self.command)
|
||||||
|
self.command = ''
|
||||||
def shutdownRequest(self):
|
def shutdownRequest(self):
|
||||||
self.environment['general']['running'] = False
|
self.environment['runtime']['eventManager'].stopMainEventLoop()
|
||||||
|
|
||||||
def captureSignal(self, siginit, frame):
|
def captureSignal(self, siginit, frame):
|
||||||
self.shutdownRequest()
|
self.shutdownRequest()
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
|
self.environment['runtime']['eventManager'].stopMainEventLoop()
|
||||||
self.environment['runtime']['outputManager'].presentText(_("Quit Fenrir"), soundIcon='ScreenReaderOff', interrupt=True)
|
self.environment['runtime']['outputManager'].presentText(_("Quit Fenrir"), soundIcon='ScreenReaderOff', interrupt=True)
|
||||||
|
self.environment['runtime']['eventManager'].cleanEventQueue()
|
||||||
|
self.environment['runtime']['eventManager'].stopMainEventLoop(True)
|
||||||
for currManager in self.environment['general']['managerList']:
|
for currManager in self.environment['general']['managerList']:
|
||||||
if self.environment['runtime'][currManager]:
|
if self.environment['runtime'][currManager]:
|
||||||
self.environment['runtime'][currManager].shutdown()
|
self.environment['runtime'][currManager].shutdown()
|
||||||
|
@ -7,13 +7,12 @@
|
|||||||
from core import debug
|
from core import debug
|
||||||
|
|
||||||
generalData = {
|
generalData = {
|
||||||
'running': True,
|
|
||||||
'args': None,
|
'args': None,
|
||||||
'tutorialMode': False,
|
'tutorialMode': False,
|
||||||
'currUser':'',
|
'currUser':'',
|
||||||
'prevUser':'',
|
'prevUser':'',
|
||||||
'managerList':['eventManager','punctuationManager','cursorManager','applicationManager','commandManager'
|
'managerList':['eventManager','punctuationManager','cursorManager','applicationManager','commandManager'
|
||||||
,'screenManager','inputManager','outputManager','debug'],
|
,'screenManager','inputManager','outputManager','helpManager','debug'],
|
||||||
'commandFolderList':['commands','onInput','onScreenUpdate','onScreenChanged'
|
'commandFolderList':['commands','onInput', 'onCursorChange', 'onScreenUpdate','onScreenChanged','onHeartBeat', 'onPlugInputDevice'
|
||||||
,'onApplicationChange','onSwitchApplicationProfile',],
|
,'onApplicationChange','onSwitchApplicationProfile','help',],
|
||||||
}
|
}
|
||||||
|
81
src/fenrir/core/helpManager.py
Executable file
81
src/fenrir/core/helpManager.py
Executable file
@ -0,0 +1,81 @@
|
|||||||
|
#!/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Fenrir TTY screen reader
|
||||||
|
# By Chrys, Storm Dragon, and contributers.
|
||||||
|
|
||||||
|
from core import debug
|
||||||
|
|
||||||
|
|
||||||
|
class helpManager():
|
||||||
|
def __init__(self):
|
||||||
|
self.helpDict = {}
|
||||||
|
self.tutorialListIndex = None
|
||||||
|
def initialize(self, environment):
|
||||||
|
self.env = environment
|
||||||
|
def shutdown(self):
|
||||||
|
pass
|
||||||
|
def toggleTutorialMode(self):
|
||||||
|
self.setTutorialMode(not self.env['general']['tutorialMode'])
|
||||||
|
def setTutorialMode(self, newTutorialMode):
|
||||||
|
self.env['general']['tutorialMode'] = newTutorialMode
|
||||||
|
if newTutorialMode:
|
||||||
|
self.createHelpDict()
|
||||||
|
self.env['bindings'][str([1, ['KEY_ESC']])] = 'TOGGLE_TUTORIAL_MODE'
|
||||||
|
self.env['bindings'][str([1, ['KEY_UP']])] = 'PREV_HELP'
|
||||||
|
self.env['bindings'][str([1, ['KEY_DOWN']])] = 'NEXT_HELP'
|
||||||
|
self.env['bindings'][str([1, ['KEY_SPACE']])] = 'CURR_HELP'
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
del(self.env['bindings'][str([1, ['KEY_ESC']])])
|
||||||
|
del(self.env['bindings'][str([1, ['KEY_UP']])])
|
||||||
|
del(self.env['bindings'][str([1, ['KEY_DOWN']])])
|
||||||
|
del(self.env['bindings'][str([1, ['KEY_SPACE']])])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
def isTutorialMode(self):
|
||||||
|
return self.env['general']['tutorialMode']
|
||||||
|
def getCommandHelpText(self, command, section = 'commands'):
|
||||||
|
commandName = command.lower()
|
||||||
|
commandName = commandName.split('__-__')[0]
|
||||||
|
commandName = commandName.replace('_',' ')
|
||||||
|
commandName = commandName.replace('_',' ')
|
||||||
|
if command == 'TOGGLE_TUTORIAL_MODE':
|
||||||
|
commandDescription = _('toggles the tutorial mode')
|
||||||
|
else:
|
||||||
|
commandDescription = self.env['runtime']['commandManager'].getCommandDescription( command, section = 'commands')
|
||||||
|
if commandDescription == '':
|
||||||
|
commandDescription = 'no Description available'
|
||||||
|
commandShortcut = self.env['runtime']['commandManager'].getShortcutForCommand( command)
|
||||||
|
commandShortcut = commandShortcut.replace('KEY_',' ')
|
||||||
|
commandShortcut = commandShortcut.replace('[','')
|
||||||
|
commandShortcut = commandShortcut.replace(']','')
|
||||||
|
commandShortcut = commandShortcut.replace("'",'')
|
||||||
|
if commandShortcut == '':
|
||||||
|
commandShortcut = 'unbound'
|
||||||
|
helptext = commandName + ', Shortcut ' + commandShortcut + ', Description ' + commandDescription
|
||||||
|
return helptext
|
||||||
|
def createHelpDict(self, section = 'commands'):
|
||||||
|
self.helpDict = {}
|
||||||
|
for command in sorted(self.env['commands'][section].keys()):
|
||||||
|
self.helpDict[len(self.helpDict)] = self.getCommandHelpText(command, section)
|
||||||
|
if len(self.helpDict) > 0:
|
||||||
|
self.tutorialListIndex = 0
|
||||||
|
else:
|
||||||
|
self.tutorialListIndex = None
|
||||||
|
def getHelpForCurrentIndex(self):
|
||||||
|
if self.tutorialListIndex == None:
|
||||||
|
return ''
|
||||||
|
return self.helpDict[self.tutorialListIndex]
|
||||||
|
def nextIndex(self):
|
||||||
|
if self.tutorialListIndex == None:
|
||||||
|
return
|
||||||
|
self.tutorialListIndex += 1
|
||||||
|
if self.tutorialListIndex >= len(self.helpDict):
|
||||||
|
self.tutorialListIndex = 0
|
||||||
|
def prevIndex(self):
|
||||||
|
if self.tutorialListIndex == None:
|
||||||
|
return
|
||||||
|
self.tutorialListIndex -= 1
|
||||||
|
if self.tutorialListIndex < 0:
|
||||||
|
self.tutorialListIndex = len(self.helpDict) - 1
|
@ -39,7 +39,7 @@ class inputManager():
|
|||||||
self.env['input']['currInput'].remove(mEvent['EventName'])
|
self.env['input']['currInput'].remove(mEvent['EventName'])
|
||||||
if len(self.env['input']['currInput']) > 1:
|
if len(self.env['input']['currInput']) > 1:
|
||||||
self.env['input']['currInput'] = sorted(self.env['input']['currInput'])
|
self.env['input']['currInput'] = sorted(self.env['input']['currInput'])
|
||||||
if len(self.env['input']['currInput']) == 0:
|
elif len(self.env['input']['currInput']) == 0:
|
||||||
self.env['input']['prevDeepestInput'] = []
|
self.env['input']['prevDeepestInput'] = []
|
||||||
self.env['input']['shortcutRepeat'] = 1
|
self.env['input']['shortcutRepeat'] = 1
|
||||||
self.setLedState = self.handleLedStates(mEvent)
|
self.setLedState = self.handleLedStates(mEvent)
|
||||||
@ -141,13 +141,6 @@ class inputManager():
|
|||||||
eventName = 'KEY_SCRIPT'
|
eventName = 'KEY_SCRIPT'
|
||||||
return eventName
|
return eventName
|
||||||
|
|
||||||
def isConsumeInput(self):
|
|
||||||
return self.env['runtime']['commandManager'].isCommandQueued() and \
|
|
||||||
not self.env['input']['keyForeward']
|
|
||||||
#and
|
|
||||||
# not (self.env['input']['keyForeward'] or \
|
|
||||||
# self.env['runtime']['settingsManager'].getSettingAsBool(, 'keyboard', 'grabDevices'))
|
|
||||||
|
|
||||||
def clearEventBuffer(self):
|
def clearEventBuffer(self):
|
||||||
self.env['runtime']['inputDriver'].clearEventBuffer()
|
self.env['runtime']['inputDriver'].clearEventBuffer()
|
||||||
|
|
||||||
@ -155,24 +148,15 @@ class inputManager():
|
|||||||
try:
|
try:
|
||||||
if self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'):
|
if self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'):
|
||||||
self.env['runtime']['inputDriver'].writeEventBuffer()
|
self.env['runtime']['inputDriver'].writeEventBuffer()
|
||||||
time.sleep(0.008)
|
|
||||||
self.clearEventBuffer()
|
self.clearEventBuffer()
|
||||||
if len(self.env['input']['currInput']) == 1:
|
|
||||||
if self.env['input']['currInput'][0] in ['KEY_UP','KEY_DOWN']:
|
|
||||||
time.sleep(0.08) # hack for tintin history because it needs more time
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.env['runtime']['debug'].writeDebugOut("Error while writeUInput",debug.debugLevel.ERROR)
|
self.env['runtime']['debug'].writeDebugOut("Error while writeUInput",debug.debugLevel.ERROR)
|
||||||
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
|
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
|
||||||
|
|
||||||
def isFenrirKeyPressed(self):
|
|
||||||
return 'KEY_FENRIR' in self.env['input']['prevDeepestInput']
|
|
||||||
|
|
||||||
def isScriptKeyPressed(self):
|
|
||||||
return 'KEY_SCRIPT' in self.env['input']['prevDeepestInput']
|
|
||||||
|
|
||||||
def noKeyPressed(self):
|
def noKeyPressed(self):
|
||||||
return self.env['input']['currInput'] == []
|
return self.env['input']['currInput'] == []
|
||||||
|
def isKeyPress(self):
|
||||||
|
return (self.env['input']['prevInput'] == []) and (self.env['input']['currInput'] != [])
|
||||||
def getPrevDeepestInput(self):
|
def getPrevDeepestInput(self):
|
||||||
shortcut = []
|
shortcut = []
|
||||||
shortcut.append(self.env['input']['shortcutRepeat'])
|
shortcut.append(self.env['input']['shortcutRepeat'])
|
||||||
@ -185,10 +169,13 @@ class inputManager():
|
|||||||
shortcut.append(self.env['input']['prevInput'])
|
shortcut.append(self.env['input']['prevInput'])
|
||||||
return str(shortcut)
|
return str(shortcut)
|
||||||
|
|
||||||
def getCurrShortcut(self):
|
def getCurrShortcut(self, inputSequence = None):
|
||||||
shortcut = []
|
shortcut = []
|
||||||
shortcut.append(self.env['input']['shortcutRepeat'])
|
shortcut.append(self.env['input']['shortcutRepeat'])
|
||||||
shortcut.append(self.env['input']['currInput'])
|
if inputSequence:
|
||||||
|
shortcut.append(inputSequence)
|
||||||
|
else:
|
||||||
|
shortcut.append(self.env['input']['currInput'])
|
||||||
if len(self.env['input']['prevInput']) < len(self.env['input']['currInput']):
|
if len(self.env['input']['prevInput']) < len(self.env['input']['currInput']):
|
||||||
if self.env['input']['shortcutRepeat'] > 1 and not self.shortcutExists(str(shortcut)):
|
if self.env['input']['shortcutRepeat'] > 1 and not self.shortcutExists(str(shortcut)):
|
||||||
shortcut = []
|
shortcut = []
|
||||||
@ -198,10 +185,17 @@ class inputManager():
|
|||||||
self.env['runtime']['debug'].writeDebugOut("currShortcut " + str(shortcut) ,debug.debugLevel.INFO)
|
self.env['runtime']['debug'].writeDebugOut("currShortcut " + str(shortcut) ,debug.debugLevel.INFO)
|
||||||
return str(shortcut)
|
return str(shortcut)
|
||||||
|
|
||||||
|
def currKeyIsModifier(self):
|
||||||
|
if len(self.env['input']['prevDeepestInput']) != 1:
|
||||||
|
return False
|
||||||
|
return (self.env['input']['currInput'][0] =='KEY_FENRIR') or (self.env['input']['currInput'][0] == 'KEY_SCRIPT')
|
||||||
|
|
||||||
def isFenrirKey(self, eventName):
|
def isFenrirKey(self, eventName):
|
||||||
return eventName in self.env['input']['fenrirKey']
|
return eventName in self.env['input']['fenrirKey']
|
||||||
|
|
||||||
def isScriptKey(self, eventName):
|
def isScriptKey(self, eventName):
|
||||||
return eventName in self.env['input']['scriptKey']
|
return eventName in self.env['input']['scriptKey']
|
||||||
|
|
||||||
def getCommandForShortcut(self, shortcut):
|
def getCommandForShortcut(self, shortcut):
|
||||||
if not self.shortcutExists(shortcut):
|
if not self.shortcutExists(shortcut):
|
||||||
return ''
|
return ''
|
||||||
|
@ -21,16 +21,19 @@ class screenManager():
|
|||||||
self.env['runtime']['settingsManager'].shutdownDriver('screenDriver')
|
self.env['runtime']['settingsManager'].shutdownDriver('screenDriver')
|
||||||
|
|
||||||
def update(self, trigger='onUpdate'):
|
def update(self, trigger='onUpdate'):
|
||||||
self.env['runtime']['screenDriver'].getCurrScreen()
|
self.env['runtime']['screenDriver'].getCurrScreen()
|
||||||
self.env['runtime']['screenDriver'].getSessionInformation()
|
|
||||||
|
if trigger == 'onScreenChange':
|
||||||
|
self.env['runtime']['screenDriver'].getSessionInformation()
|
||||||
|
|
||||||
self.env['screen']['oldApplication'] = self.env['screen']['newApplication']
|
self.env['screen']['oldApplication'] = self.env['screen']['newApplication']
|
||||||
if self.isScreenChange():
|
if self.isScreenChange():
|
||||||
self.changeBrailleScreen()
|
self.changeBrailleScreen()
|
||||||
if not self.isSuspendingScreen(self.env['screen']['newTTY']):
|
if not self.isSuspendingScreen(self.env['screen']['newTTY']):
|
||||||
self.env['runtime']['screenDriver'].update(trigger)
|
self.env['runtime']['screenDriver'].update(trigger)
|
||||||
if trigger == 'onUpdate' or self.isScreenChange() \
|
#if trigger == 'onUpdate' or self.isScreenChange() \
|
||||||
or len(self.env['screen']['newDelta']) > 6:
|
# or len(self.env['screen']['newDelta']) > 6:
|
||||||
self.env['runtime']['screenDriver'].getCurrApplication()
|
# self.env['runtime']['screenDriver'].getCurrApplication()
|
||||||
self.env['screen']['lastScreenUpdate'] = time.time()
|
self.env['screen']['lastScreenUpdate'] = time.time()
|
||||||
|
|
||||||
def isSuspendingScreen(self, screen = None):
|
def isSuspendingScreen(self, screen = None):
|
||||||
@ -42,6 +45,7 @@ class screenManager():
|
|||||||
ignoreScreens.extend(fixIgnoreScreens.split(','))
|
ignoreScreens.extend(fixIgnoreScreens.split(','))
|
||||||
if self.env['runtime']['settingsManager'].getSettingAsBool('screen', 'autodetectSuspendingScreen'):
|
if self.env['runtime']['settingsManager'].getSettingAsBool('screen', 'autodetectSuspendingScreen'):
|
||||||
ignoreScreens.extend(self.env['screen']['autoIgnoreScreens'])
|
ignoreScreens.extend(self.env['screen']['autoIgnoreScreens'])
|
||||||
|
self.env['runtime']['debug'].writeDebugOut('screenManager:isSuspendingScreen ' + str(ignoreScreens) + ' '+ str(self.env['screen']['newTTY']),debug.debugLevel.INFO)
|
||||||
return (screen in ignoreScreens)
|
return (screen in ignoreScreens)
|
||||||
|
|
||||||
def isScreenChange(self):
|
def isScreenChange(self):
|
||||||
|
@ -76,7 +76,7 @@ settingsData = {
|
|||||||
'review':{
|
'review':{
|
||||||
'lineBreak': True,
|
'lineBreak': True,
|
||||||
'endOfScreen': True,
|
'endOfScreen': True,
|
||||||
'leaveReviewOnKeypress': False,
|
'leaveReviewOnCursorChange': True,
|
||||||
'leaveReviewOnScreenChange': True,
|
'leaveReviewOnScreenChange': True,
|
||||||
},
|
},
|
||||||
'promote':{
|
'promote':{
|
||||||
|
@ -15,6 +15,7 @@ from core import screenManager
|
|||||||
from core import punctuationManager
|
from core import punctuationManager
|
||||||
from core import cursorManager
|
from core import cursorManager
|
||||||
from core import applicationManager
|
from core import applicationManager
|
||||||
|
from core import helpManager
|
||||||
from core import environment
|
from core import environment
|
||||||
from core import inputData
|
from core import inputData
|
||||||
from core.settingsData import settingsData
|
from core.settingsData import settingsData
|
||||||
@ -69,8 +70,10 @@ class settingsManager():
|
|||||||
self.env['runtime']['debug'].writeDebugOut("invalid shortcut (missing KEY_FENRIR): "+ str(shortcut) + ' command:' +commandName ,debug.debugLevel.ERROR)
|
self.env['runtime']['debug'].writeDebugOut("invalid shortcut (missing KEY_FENRIR): "+ str(shortcut) + ' command:' +commandName ,debug.debugLevel.ERROR)
|
||||||
continue
|
continue
|
||||||
self.env['runtime']['debug'].writeDebugOut("Shortcut: "+ str(shortcut) + ' command:' +commandName ,debug.debugLevel.INFO, onAnyLevel=True)
|
self.env['runtime']['debug'].writeDebugOut("Shortcut: "+ str(shortcut) + ' command:' +commandName ,debug.debugLevel.INFO, onAnyLevel=True)
|
||||||
self.env['bindings'][str(shortcut)] = commandName
|
self.env['bindings'][str(shortcut)] = commandName
|
||||||
kbConfig.close()
|
kbConfig.close()
|
||||||
|
# fix bindings
|
||||||
|
self.env['bindings'][str([1, ['KEY_F1', 'KEY_FENRIR']])] = 'TOGGLE_TUTORIAL_MODE'
|
||||||
|
|
||||||
def loadSoundIcons(self, soundIconPath):
|
def loadSoundIcons(self, soundIconPath):
|
||||||
siConfig = open(soundIconPath + '/soundicons.conf',"r")
|
siConfig = open(soundIconPath + '/soundicons.conf',"r")
|
||||||
@ -147,7 +150,7 @@ class settingsManager():
|
|||||||
def getSetting(self, section, setting):
|
def getSetting(self, section, setting):
|
||||||
value = ''
|
value = ''
|
||||||
try:
|
try:
|
||||||
value = self.settingArgDict[section][setting]
|
value = self.settingArgDict[section.lower()][setting.lower()]
|
||||||
return value
|
return value
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
@ -160,10 +163,10 @@ class settingsManager():
|
|||||||
def getSettingAsInt(self, section, setting):
|
def getSettingAsInt(self, section, setting):
|
||||||
value = 0
|
value = 0
|
||||||
try:
|
try:
|
||||||
value = int(self.settingArgDict[section][setting])
|
value = int(self.settingArgDict[section.lower()][setting.lower()])
|
||||||
return value
|
return value
|
||||||
except:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
value = self.env['settings'].getint(section, setting)
|
value = self.env['settings'].getint(section, setting)
|
||||||
except:
|
except:
|
||||||
@ -173,7 +176,7 @@ class settingsManager():
|
|||||||
def getSettingAsFloat(self, section, setting):
|
def getSettingAsFloat(self, section, setting):
|
||||||
value = 0.0
|
value = 0.0
|
||||||
try:
|
try:
|
||||||
value = float(self.settingArgDict[section][setting])
|
value = float(self.settingArgDict[section.lower()][setting.lower()])
|
||||||
return value
|
return value
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
@ -186,7 +189,7 @@ class settingsManager():
|
|||||||
def getSettingAsBool(self, section, setting):
|
def getSettingAsBool(self, section, setting):
|
||||||
value = False
|
value = False
|
||||||
try:
|
try:
|
||||||
value = self.settingArgDict[section][setting].upper() in ['1','YES','JA','TRUE']
|
value = self.settingArgDict[section.lower()][setting.lower()].upper() in ['1','YES','JA','TRUE']
|
||||||
return value
|
return value
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
@ -226,8 +229,16 @@ class settingsManager():
|
|||||||
for key in keyList:
|
for key in keyList:
|
||||||
if not key in self.env['input']['scriptKey']:
|
if not key in self.env['input']['scriptKey']:
|
||||||
self.env['input']['scriptKey'].append(key)
|
self.env['input']['scriptKey'].append(key)
|
||||||
|
def setOptionArgDict(self, section, option, value):
|
||||||
|
section = section.lower()
|
||||||
|
option = option.lower()
|
||||||
|
try:
|
||||||
|
e = self.settingArgDict[section]
|
||||||
|
except KeyError:
|
||||||
|
self.settingArgDict[section] = {}
|
||||||
|
self.settingArgDict[section][option] = str(value)
|
||||||
|
|
||||||
def parseSettingArgs(self, settingArgs):
|
def parseSettingArgs(self, settingArgs):
|
||||||
optionArgDict = {}
|
|
||||||
for optionElem in settingArgs.split(';'):
|
for optionElem in settingArgs.split(';'):
|
||||||
if len(optionElem.split('#',1)) != 2:
|
if len(optionElem.split('#',1)) != 2:
|
||||||
continue
|
continue
|
||||||
@ -236,13 +247,9 @@ class settingsManager():
|
|||||||
section = str(optionElem.split('#',1)[0]).lower()
|
section = str(optionElem.split('#',1)[0]).lower()
|
||||||
option = str(optionElem.split('#',1)[1].split('=',1)[0]).lower()
|
option = str(optionElem.split('#',1)[1].split('=',1)[0]).lower()
|
||||||
value = optionElem.split('#',1)[1].split('=',1)[1]
|
value = optionElem.split('#',1)[1].split('=',1)[1]
|
||||||
try:
|
self.setOptionArgDict(section, option, value)
|
||||||
e = optionArgDict[section]
|
|
||||||
except KeyError:
|
def initFenrirConfig(self, cliArgs, fenrirManager = None, environment = environment.environment):
|
||||||
optionArgDict[section] = {}
|
|
||||||
optionArgDict[section][option] = str(value)
|
|
||||||
return optionArgDict
|
|
||||||
def initFenrirConfig(self, cliArgs, environment = environment.environment):
|
|
||||||
settingsRoot = '/etc/fenrir/'
|
settingsRoot = '/etc/fenrir/'
|
||||||
settingsFile = cliArgs.setting
|
settingsFile = cliArgs.setting
|
||||||
soundRoot = '/usr/share/sounds/fenrir/'
|
soundRoot = '/usr/share/sounds/fenrir/'
|
||||||
@ -271,11 +278,15 @@ class settingsManager():
|
|||||||
validConfig = environment['runtime']['settingsManager'].loadSettings(settingsFile)
|
validConfig = environment['runtime']['settingsManager'].loadSettings(settingsFile)
|
||||||
if not validConfig:
|
if not validConfig:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if cliArgs.options != '':
|
if cliArgs.options != '':
|
||||||
self.settingArgDict = self.parseSettingArgs(cliArgs.options)
|
self.parseSettingArgs(cliArgs.options)
|
||||||
|
if cliArgs.debug:
|
||||||
|
self.setOptionArgDict('general', 'debugLevel', 3)
|
||||||
|
|
||||||
self.setFenrirKeys(self.getSetting('general','fenrirKeys'))
|
self.setFenrirKeys(self.getSetting('general','fenrirKeys'))
|
||||||
self.setScriptKeys(self.getSetting('general','scriptKeys'))
|
self.setScriptKeys(self.getSetting('general','scriptKeys'))
|
||||||
|
|
||||||
if not os.path.exists(self.getSetting('keyboard','keyboardLayout')):
|
if not os.path.exists(self.getSetting('keyboard','keyboardLayout')):
|
||||||
if os.path.exists(settingsRoot + 'keyboard/' + self.getSetting('keyboard','keyboardLayout')):
|
if os.path.exists(settingsRoot + 'keyboard/' + self.getSetting('keyboard','keyboardLayout')):
|
||||||
self.setSetting('keyboard', 'keyboardLayout', settingsRoot + 'keyboard/' + self.getSetting('keyboard','keyboardLayout'))
|
self.setSetting('keyboard', 'keyboardLayout', settingsRoot + 'keyboard/' + self.getSetting('keyboard','keyboardLayout'))
|
||||||
@ -304,6 +315,8 @@ class settingsManager():
|
|||||||
else:
|
else:
|
||||||
environment['runtime']['settingsManager'].loadDicts(self.getSetting('general','punctuationProfile'))
|
environment['runtime']['settingsManager'].loadDicts(self.getSetting('general','punctuationProfile'))
|
||||||
|
|
||||||
|
if fenrirManager:
|
||||||
|
environment['runtime']['fenrirManager'] = fenrirManager
|
||||||
environment['runtime']['eventManager'] = eventManager.eventManager()
|
environment['runtime']['eventManager'] = eventManager.eventManager()
|
||||||
environment['runtime']['eventManager'].initialize(environment)
|
environment['runtime']['eventManager'].initialize(environment)
|
||||||
environment['runtime']['inputManager'] = inputManager.inputManager()
|
environment['runtime']['inputManager'] = inputManager.inputManager()
|
||||||
@ -318,15 +331,17 @@ class settingsManager():
|
|||||||
environment['runtime']['cursorManager'].initialize(environment)
|
environment['runtime']['cursorManager'].initialize(environment)
|
||||||
environment['runtime']['applicationManager'] = applicationManager.applicationManager()
|
environment['runtime']['applicationManager'] = applicationManager.applicationManager()
|
||||||
environment['runtime']['applicationManager'].initialize(environment)
|
environment['runtime']['applicationManager'].initialize(environment)
|
||||||
|
environment['runtime']['helpManager'] = helpManager.helpManager()
|
||||||
|
environment['runtime']['helpManager'].initialize(environment)
|
||||||
if environment['runtime']['screenManager'] == None:
|
if environment['runtime']['screenManager'] == None:
|
||||||
environment['runtime']['screenManager'] = screenManager.screenManager()
|
environment['runtime']['screenManager'] = screenManager.screenManager()
|
||||||
environment['runtime']['screenManager'].initialize(environment)
|
environment['runtime']['screenManager'].initialize(environment)
|
||||||
|
|
||||||
environment['runtime']['debug'].writeDebugOut('\/-------environment-------\/',debug.debugLevel.INFO, onAnyLevel=True)
|
environment['runtime']['debug'].writeDebugOut('\/-------environment-------\/',debug.debugLevel.INFO, onAnyLevel=True)
|
||||||
environment['runtime']['debug'].writeDebugOut(str(environment),debug.debugLevel.INFO, onAnyLevel=True)
|
environment['runtime']['debug'].writeDebugOut(str(environment), debug.debugLevel.INFO, onAnyLevel=True)
|
||||||
environment['runtime']['debug'].writeDebugOut('\/-------settings.conf-------\/',debug.debugLevel.INFO, onAnyLevel=True)
|
environment['runtime']['debug'].writeDebugOut('\/-------settings.conf-------\/', debug.debugLevel.INFO, onAnyLevel=True)
|
||||||
environment['runtime']['debug'].writeDebugOut(str(environment['settings']._sections
|
environment['runtime']['debug'].writeDebugOut(str(environment['settings']._sections) , debug.debugLevel.INFO, onAnyLevel=True)
|
||||||
),debug.debugLevel.INFO, onAnyLevel=True)
|
environment['runtime']['debug'].writeDebugOut('\/-------self.settingArgDict-------\/',debug.debugLevel.INFO, onAnyLevel=True)
|
||||||
|
environment['runtime']['debug'].writeDebugOut(str( self.settingArgDict) ,debug.debugLevel.INFO, onAnyLevel=True)
|
||||||
return environment
|
return environment
|
||||||
|
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
# By Chrys, Storm Dragon, and contributers.
|
# By Chrys, Storm Dragon, and contributers.
|
||||||
|
|
||||||
_evdevAvailable = False
|
_evdevAvailable = False
|
||||||
|
_udevAvailable = False
|
||||||
_evdevAvailableError = ''
|
_evdevAvailableError = ''
|
||||||
|
_udevAvailableError = ''
|
||||||
try:
|
try:
|
||||||
import evdev
|
import evdev
|
||||||
from evdev import InputDevice, UInput
|
from evdev import InputDevice, UInput
|
||||||
@ -13,42 +15,93 @@ try:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
_evdevAvailableError = str(e)
|
_evdevAvailableError = str(e)
|
||||||
|
|
||||||
|
try:
|
||||||
|
import pyudev
|
||||||
|
_udevAvailable = True
|
||||||
|
except Exception as e:
|
||||||
|
_udevAvailableError = str(e)
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from select import select
|
from select import select
|
||||||
|
import multiprocessing
|
||||||
|
from multiprocessing.sharedctypes import Value
|
||||||
|
from ctypes import c_bool
|
||||||
|
|
||||||
|
from core.eventData import fenrirEventType
|
||||||
from core import inputData
|
from core import inputData
|
||||||
from core import debug
|
from core import debug
|
||||||
|
|
||||||
|
|
||||||
class driver():
|
class driver():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self._manager = multiprocessing.Manager()
|
||||||
self.iDevices = {}
|
self.iDevices = {}
|
||||||
|
self.iDevicesFD = None
|
||||||
self.uDevices = {}
|
self.uDevices = {}
|
||||||
self.iDeviceNo = 0
|
self.iDeviceNo = 0
|
||||||
self._initialized = False
|
self._initialized = False
|
||||||
|
self.watchDog = Value(c_bool, True)
|
||||||
def initialize(self, environment):
|
def initialize(self, environment):
|
||||||
self.env = environment
|
self.env = environment
|
||||||
global _evdevAvailable
|
global _evdevAvailable
|
||||||
|
global _udevAvailable
|
||||||
self._initialized = _evdevAvailable
|
self._initialized = _evdevAvailable
|
||||||
if not self._initialized:
|
if not self._initialized:
|
||||||
global _evdevAvailableError
|
global _evdevAvailableError
|
||||||
self.env['runtime']['debug'].writeDebugOut('InputDriver: ' + _evdevAvailableError,debug.debugLevel.ERROR)
|
self.env['runtime']['debug'].writeDebugOut('InputDriver: ' + _evdevAvailableError,debug.debugLevel.ERROR)
|
||||||
return
|
return
|
||||||
|
self.updateInputDevices()
|
||||||
|
if _udevAvailable:
|
||||||
|
self.env['runtime']['eventManager'].addCustomEventThread(self.plugInputDeviceWatchdogUdev)
|
||||||
|
else:
|
||||||
|
self.env['runtime']['eventManager'].addSimpleEventThread(fenrirEventType.PlugInputDevice, self.plugInputDeviceWatchdogTimer)
|
||||||
|
self.env['runtime']['eventManager'].addSimpleEventThread(fenrirEventType.KeyboardInput, self.inputWatchdog, {'dev':self.iDevicesFD})
|
||||||
|
def plugInputDeviceWatchdogUdev(self,active , eventQueue):
|
||||||
|
context = pyudev.Context()
|
||||||
|
monitor = pyudev.Monitor.from_netlink(context)
|
||||||
|
monitor.filter_by(subsystem='input')
|
||||||
|
monitor.start()
|
||||||
|
while active:
|
||||||
|
devices = monitor.poll(2)
|
||||||
|
if devices:
|
||||||
|
for device in devices:
|
||||||
|
if not active:
|
||||||
|
return
|
||||||
|
print('drin')
|
||||||
|
eventQueue.put({"Type":fenrirEventType.PlugInputDevice,"Data":''})
|
||||||
|
|
||||||
|
#self.env['runtime']['settingsManager'].getSettingAsFloat('screen', 'screenUpdateDelay')
|
||||||
|
return time.time()
|
||||||
|
def plugInputDeviceWatchdogTimer(self):
|
||||||
|
time.sleep(2.5)
|
||||||
|
return time.time()
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
if not self._initialized:
|
if not self._initialized:
|
||||||
return
|
return
|
||||||
|
def inputWatchdog(self,active , iDevicesFD):
|
||||||
|
deviceFd = []
|
||||||
|
for fd in iDevicesFD['dev']:
|
||||||
|
deviceFd.append(fd)
|
||||||
|
while self.watchDog.value == 0:
|
||||||
|
if active.value == 0:
|
||||||
|
return
|
||||||
|
r = []
|
||||||
|
while r == []:
|
||||||
|
r, w, x = select(deviceFd, [], [], 2)
|
||||||
|
self.watchDog.value = 0
|
||||||
def getInputEvent(self):
|
def getInputEvent(self):
|
||||||
if not self.hasIDevices():
|
if not self.hasIDevices():
|
||||||
time.sleep(0.008) # dont flood CPU
|
self.watchDog.value = 1
|
||||||
return None
|
return None
|
||||||
event = None
|
event = None
|
||||||
r, w, x = select(self.iDevices, [], [], self.env['runtime']['settingsManager'].getSettingAsFloat('screen', 'screenUpdateDelay'))
|
r, w, x = select(self.iDevices, [], [], 0.0001)
|
||||||
if r != []:
|
if r != []:
|
||||||
for fd in r:
|
for fd in r:
|
||||||
try:
|
try:
|
||||||
event = self.iDevices[fd].read_one()
|
event = self.iDevices[fd].read_one()
|
||||||
except:
|
except:
|
||||||
self.removeDevice(fd)
|
self.removeDevice(fd)
|
||||||
|
self.watchDog.value = 1
|
||||||
return None
|
return None
|
||||||
foreward = False
|
foreward = False
|
||||||
while(event):
|
while(event):
|
||||||
@ -66,6 +119,7 @@ class driver():
|
|||||||
continue
|
continue
|
||||||
if not foreward:
|
if not foreward:
|
||||||
if currMapEvent['EventState'] in [0,1,2]:
|
if currMapEvent['EventState'] in [0,1,2]:
|
||||||
|
self.watchDog.value = 1
|
||||||
return currMapEvent
|
return currMapEvent
|
||||||
else:
|
else:
|
||||||
if not event.type in [0,1,4]:
|
if not event.type in [0,1,4]:
|
||||||
@ -73,7 +127,8 @@ class driver():
|
|||||||
event = self.iDevices[fd].read_one()
|
event = self.iDevices[fd].read_one()
|
||||||
if foreward:
|
if foreward:
|
||||||
self.writeEventBuffer()
|
self.writeEventBuffer()
|
||||||
self.clearEventBuffer()
|
self.clearEventBuffer()
|
||||||
|
self.watchDog.value = 1
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def writeEventBuffer(self):
|
def writeEventBuffer(self):
|
||||||
@ -92,7 +147,7 @@ class driver():
|
|||||||
return
|
return
|
||||||
uDevice.write_event(event)
|
uDevice.write_event(event)
|
||||||
uDevice.syn()
|
uDevice.syn()
|
||||||
time.sleep(0.01)
|
time.sleep(0.0001)
|
||||||
|
|
||||||
def updateInputDevices(self, force = False, init = False):
|
def updateInputDevices(self, force = False, init = False):
|
||||||
if init:
|
if init:
|
||||||
@ -145,6 +200,11 @@ class driver():
|
|||||||
self.env['runtime']['debug'].writeDebugOut('Device added (Name):' + self.iDevices[currDevice.fd].name,debug.debugLevel.INFO)
|
self.env['runtime']['debug'].writeDebugOut('Device added (Name):' + self.iDevices[currDevice.fd].name,debug.debugLevel.INFO)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.env['runtime']['debug'].writeDebugOut("Skip Inputdevice : " + deviceFile +' ' + str(e),debug.debugLevel.ERROR)
|
self.env['runtime']['debug'].writeDebugOut("Skip Inputdevice : " + deviceFile +' ' + str(e),debug.debugLevel.ERROR)
|
||||||
|
self.iDevicesFD = multiprocessing.Array('i', len(self.iDevices))
|
||||||
|
i = 0
|
||||||
|
for fd in self.iDevices:
|
||||||
|
self.iDevicesFD[i] = fd
|
||||||
|
i +=1
|
||||||
self.iDeviceNo = len(evdev.list_devices())
|
self.iDeviceNo = len(evdev.list_devices())
|
||||||
|
|
||||||
def mapEvent(self, event):
|
def mapEvent(self, event):
|
||||||
@ -191,6 +251,9 @@ class driver():
|
|||||||
self.grabDevice(fd)
|
self.grabDevice(fd)
|
||||||
|
|
||||||
def grabDevice(self, fd):
|
def grabDevice(self, fd):
|
||||||
|
if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'):
|
||||||
|
self.uDevices[fd] = None
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
self.uDevices[fd] = UInput.from_device(self.iDevices[fd].fn)
|
self.uDevices[fd] = UInput.from_device(self.iDevices[fd].fn)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -232,7 +295,12 @@ class driver():
|
|||||||
try:
|
try:
|
||||||
del(self.uDevices[fd])
|
del(self.uDevices[fd])
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
self.iDevicesFD = multiprocessing.Array('i', len(self.iDevices))
|
||||||
|
i = 0
|
||||||
|
for fd in self.iDevices:
|
||||||
|
self.iDevicesFD[i] = fd
|
||||||
|
i +=1
|
||||||
def hasIDevices(self):
|
def hasIDevices(self):
|
||||||
if not self._initialized:
|
if not self._initialized:
|
||||||
return False
|
return False
|
||||||
|
@ -3,23 +3,42 @@
|
|||||||
|
|
||||||
# Fenrir TTY screen reader
|
# Fenrir TTY screen reader
|
||||||
# By Chrys, Storm Dragon, and contributers.
|
# By Chrys, Storm Dragon, and contributers.
|
||||||
|
#attrib:
|
||||||
|
#http://rampex.ihep.su/Linux/linux_howto/html/tutorials/mini/Colour-ls-6.html
|
||||||
|
#0 = black, 1 = blue, 2 = green, 3 = cyan, 4 = red, 5 = purple, 6 = brown/yellow, 7 = white.
|
||||||
|
#https://github.com/jwilk/vcsapeek/blob/master/linuxvt.py
|
||||||
|
#blink = 5 if attr & 1 else 0
|
||||||
|
#bold = 1 if attr & 16 else 0
|
||||||
|
|
||||||
|
|
||||||
import difflib
|
import difflib
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import fcntl
|
import glob, os
|
||||||
import termios
|
import termios
|
||||||
import time
|
import time
|
||||||
|
import select
|
||||||
import dbus
|
import dbus
|
||||||
from core import debug
|
import fcntl
|
||||||
|
from array import array
|
||||||
|
import errno
|
||||||
|
import sys
|
||||||
from utils import screen_utils
|
from utils import screen_utils
|
||||||
|
from fcntl import ioctl
|
||||||
|
from struct import unpack_from, unpack, pack
|
||||||
|
from core import debug
|
||||||
|
from core.eventData import fenrirEventType
|
||||||
|
|
||||||
|
|
||||||
class driver():
|
class driver():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.vcsaDevicePath = '/dev/vcsa'
|
self.vcsaDevicePath = '/dev/vcsa'
|
||||||
self.ListSessions = None
|
self.ListSessions = None
|
||||||
|
self.charmap = {}
|
||||||
|
self.hichar = None
|
||||||
def initialize(self, environment):
|
def initialize(self, environment):
|
||||||
self.env = environment
|
self.env = environment
|
||||||
|
self.env['runtime']['eventManager'].addCustomEventThread(self.updateWatchdog)
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
pass
|
pass
|
||||||
def getCurrScreen(self):
|
def getCurrScreen(self):
|
||||||
@ -92,9 +111,126 @@ class driver():
|
|||||||
self.env['general']['currUser'] = session[2]
|
self.env['general']['currUser'] = session[2]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.env['runtime']['debug'].writeDebugOut('getSessionInformation: Maybe no LoginD:' + str(e),debug.debugLevel.ERROR)
|
self.env['runtime']['debug'].writeDebugOut('getSessionInformation: Maybe no LoginD:' + str(e),debug.debugLevel.ERROR)
|
||||||
self.env['screen']['autoIgnoreScreens'] = []
|
self.env['screen']['autoIgnoreScreens'] = []
|
||||||
|
self.env['runtime']['debug'].writeDebugOut('getSessionInformation:' + str(self.env['screen']['autoIgnoreScreens']) + ' ' + str(self.env['general']) ,debug.debugLevel.INFO)
|
||||||
|
|
||||||
|
def updateWatchdog(self,active , eventQueue):
|
||||||
|
try:
|
||||||
|
vcsa = {}
|
||||||
|
vcsaDevices = glob.glob('/dev/vcsa*')
|
||||||
|
for vcsaDev in vcsaDevices:
|
||||||
|
index = vcsaDev[9:]
|
||||||
|
vcsa[str(index)] = open(vcsaDev,'rb')
|
||||||
|
|
||||||
|
tty = open('/sys/devices/virtual/tty/tty0/active','r')
|
||||||
|
currScreen = str(tty.read()[3:-1])
|
||||||
|
oldScreen = currScreen
|
||||||
|
watchdog = select.epoll()
|
||||||
|
watchdog.register(vcsa[currScreen], select.EPOLLPRI)
|
||||||
|
watchdog.register(tty, select.EPOLLPRI)
|
||||||
|
lastScreenContent = b''
|
||||||
|
while active.value == 1:
|
||||||
|
changes = watchdog.poll(2)
|
||||||
|
for change in changes:
|
||||||
|
fileno = change[0]
|
||||||
|
event = change[1]
|
||||||
|
if fileno == tty.fileno():
|
||||||
|
self.env['runtime']['debug'].writeDebugOut('ScreenChange',debug.debugLevel.INFO)
|
||||||
|
tty.seek(0)
|
||||||
|
currScreen = str(tty.read()[3:-1])
|
||||||
|
if currScreen != oldScreen:
|
||||||
|
try:
|
||||||
|
watchdog.unregister(vcsa[ oldScreen ])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
watchdog.register(vcsa[ currScreen ], select.EPOLLPRI)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
oldScreen = currScreen
|
||||||
|
eventQueue.put({"Type":fenrirEventType.ScreenChanged,"Data":''})
|
||||||
|
try:
|
||||||
|
vcsa[currScreen].seek(0)
|
||||||
|
lastScreenContent = vcsa[currScreen].read()
|
||||||
|
except:
|
||||||
|
lastScreenContent = b''
|
||||||
|
else:
|
||||||
|
self.env['runtime']['debug'].writeDebugOut('ScreenUpdate',debug.debugLevel.INFO)
|
||||||
|
vcsa[currScreen].seek(0)
|
||||||
|
screenContent = vcsa[currScreen].read()
|
||||||
|
if screenContent != lastScreenContent:
|
||||||
|
eventQueue.put({"Type":fenrirEventType.ScreenUpdate,"Data":''})
|
||||||
|
lastScreenContent = screenContent
|
||||||
|
except Exception as e:
|
||||||
|
self.env['runtime']['debug'].writeDebugOut('VCSA:updateWatchdog:' + str(e),debug.debugLevel.ERROR)
|
||||||
|
|
||||||
|
def updateCharMap(self, screen):
|
||||||
|
tty = open('/dev/tty' + screen, 'rb')
|
||||||
|
GIO_UNIMAP = 0x4B66
|
||||||
|
VT_GETHIFONTMASK = 0x560D
|
||||||
|
himask = array("H", (0,))
|
||||||
|
ioctl(tty, VT_GETHIFONTMASK, himask)
|
||||||
|
self.hichar, = unpack_from("@H", himask)
|
||||||
|
sz = 512
|
||||||
|
line = ''
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
unipairs = array("H", [0]*(2*sz))
|
||||||
|
unimapdesc = array("B", pack("@HP", sz, unipairs.buffer_info()[0]))
|
||||||
|
ioctl(tty.fileno(), GIO_UNIMAP, unimapdesc)
|
||||||
|
break
|
||||||
|
except IOError as e:
|
||||||
|
if e.errno != errno.ENOMEM:
|
||||||
|
raise
|
||||||
|
sz *= 2
|
||||||
|
tty.close()
|
||||||
|
ncodes, = unpack_from("@H", unimapdesc)
|
||||||
|
utable = unpack_from("@%dH" % (2*ncodes), unipairs)
|
||||||
|
for u, b in zip(utable[::2], utable[1::2]):
|
||||||
|
if self.charmap.get(b) is None:
|
||||||
|
self.charmap[b] = chr(u)
|
||||||
|
|
||||||
|
def autoDecodeVCSA(self, allData, rows, cols):
|
||||||
|
allText = ''
|
||||||
|
allAttrib = b''
|
||||||
|
i = 0
|
||||||
|
for y in range(rows):
|
||||||
|
lineText = ''
|
||||||
|
lineAttrib = b''
|
||||||
|
for x in range(cols):
|
||||||
|
data = allData[i: i + 2]
|
||||||
|
i += 2
|
||||||
|
if data == b' \x07':
|
||||||
|
#attr = 7
|
||||||
|
#ink = 7
|
||||||
|
#paper = 0
|
||||||
|
#ch = ' '
|
||||||
|
lineAttrib += b'7'
|
||||||
|
lineText += ' '
|
||||||
|
continue
|
||||||
|
(sh,) = unpack("=H", data)
|
||||||
|
attr = (sh >> 8) & 0xFF
|
||||||
|
ch = sh & 0xFF
|
||||||
|
if self.hichar == 0x100:
|
||||||
|
attr >>= 1
|
||||||
|
lineAttrib += bytes(attr)
|
||||||
|
ink = attr & 0x0F
|
||||||
|
paper = (attr>>4) & 0x0F
|
||||||
|
#if (ink != 7) or (paper != 0):
|
||||||
|
# print(ink,paper)
|
||||||
|
if sh & self.hichar:
|
||||||
|
ch |= 0x100
|
||||||
|
try:
|
||||||
|
lineText += self.charmap[ch]
|
||||||
|
except KeyError:
|
||||||
|
lineText += chr('?')
|
||||||
|
allText += lineText + '\n'
|
||||||
|
allAttrib += lineAttrib
|
||||||
|
return str(allText), allAttrib
|
||||||
|
|
||||||
def update(self, trigger='onUpdate'):
|
def update(self, trigger='onUpdate'):
|
||||||
|
if trigger == 'onInput': # no need for an update on input for VCSA
|
||||||
|
return
|
||||||
newContentBytes = b''
|
newContentBytes = b''
|
||||||
try:
|
try:
|
||||||
# read screen
|
# read screen
|
||||||
@ -124,10 +260,17 @@ class driver():
|
|||||||
self.env['screen']['newCursor']['x'] = int( self.env['screen']['newContentBytes'][2])
|
self.env['screen']['newCursor']['x'] = int( self.env['screen']['newContentBytes'][2])
|
||||||
self.env['screen']['newCursor']['y'] = int( self.env['screen']['newContentBytes'][3])
|
self.env['screen']['newCursor']['y'] = int( self.env['screen']['newContentBytes'][3])
|
||||||
# analyze content
|
# analyze content
|
||||||
self.env['screen']['newContentText'] = self.env['screen']['newContentBytes'][4:][::2].decode(screenEncoding, "replace").encode('utf-8').decode('utf-8')
|
|
||||||
self.env['screen']['newContentText'] = screen_utils.removeNonprintable(self.env['screen']['newContentText'])
|
if screenEncoding.upper() == 'AUTO':
|
||||||
self.env['screen']['newContentAttrib'] = self.env['screen']['newContentBytes'][5:][::2]
|
self.updateCharMap(str(self.env['screen']['newTTY']))
|
||||||
self.env['screen']['newContentText'] = screen_utils.insertNewlines(self.env['screen']['newContentText'], self.env['screen']['columns'])
|
self.env['screen']['newContentText'], \
|
||||||
|
self.env['screen']['newContentAttrib'] =\
|
||||||
|
self.autoDecodeVCSA(self.env['screen']['newContentBytes'][4:], self.env['screen']['lines'], self.env['screen']['columns'])
|
||||||
|
else:
|
||||||
|
self.env['screen']['newContentText'] = self.env['screen']['newContentBytes'][4:][::2].decode(screenEncoding, "replace").encode('utf-8').decode('utf-8')
|
||||||
|
self.env['screen']['newContentText'] = screen_utils.removeNonprintable(self.env['screen']['newContentText'])
|
||||||
|
self.env['screen']['newContentAttrib'] = self.env['screen']['newContentBytes'][5:][::2]
|
||||||
|
self.env['screen']['newContentText'] = screen_utils.insertNewlines(self.env['screen']['newContentText'], self.env['screen']['columns'])
|
||||||
|
|
||||||
if self.env['screen']['newTTY'] != self.env['screen']['oldTTY']:
|
if self.env['screen']['newTTY'] != self.env['screen']['oldTTY']:
|
||||||
self.env['screen']['oldContentBytes'] = b''
|
self.env['screen']['oldContentBytes'] = b''
|
||||||
|
Loading…
Reference in New Issue
Block a user