2018-03-21 06:10:28 -04:00
#!/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
2018-05-11 18:23:45 -04:00
import signal , time , argparse , sys
2018-03-21 06:10:28 -04:00
from fenrirscreenreader . core import i18n
from fenrirscreenreader . core import settingsManager
from fenrirscreenreader . core import debug
from fenrirscreenreader . core . eventData import fenrirEventType
class fenrirManager ( ) :
def __init__ ( self ) :
self . initialized = False
cliArgs = self . handleArgs ( )
if not cliArgs :
2018-09-10 22:05:13 -04:00
return
2018-03-21 06:10:28 -04:00
try :
2018-03-25 10:05:10 -04:00
self . environment = settingsManager . settingsManager ( ) . initFenrirConfig ( cliArgs , self )
2018-03-21 06:10:28 -04:00
if not self . environment :
raise RuntimeError ( ' Cannot Initialize. Maybe the configfile is not available or not parseable ' )
except RuntimeError :
raise
2018-09-10 22:05:13 -04:00
self . environment [ ' runtime ' ] [ ' outputManager ' ] . presentText ( _ ( " Start Fenrir " ) , soundIcon = ' ScreenReaderOn ' , interrupt = True )
2018-03-21 06:10:28 -04:00
signal . signal ( signal . SIGINT , self . captureSignal )
signal . signal ( signal . SIGTERM , self . captureSignal )
self . initialized = True
self . modifierInput = False
self . singleKeyCommand = False
self . command = ' '
2018-05-11 18:23:45 -04:00
self . setProcessName ( )
2018-03-21 06:10:28 -04:00
def handleArgs ( self ) :
args = None
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 ' )
2018-09-10 22:05:13 -04:00
parser . add_argument ( ' -o ' , ' --options ' , metavar = ' SECTION#SETTING=VALUE;.. ' , default = ' ' , help = ' Overwrite options in given settings file. Sections, settings and Values are cases sensitive ' )
2018-03-21 06:10:28 -04:00
parser . add_argument ( ' -d ' , ' --debug ' , action = ' store_true ' , help = ' Turns on Debugmode ' )
2018-09-10 22:05:13 -04:00
parser . add_argument ( ' -p ' , ' --print ' , action = ' store_true ' , help = ' Print debug messages on screen ' )
2019-05-17 04:18:48 -04:00
parser . add_argument ( ' -e ' , ' --emulated-pty ' , action = ' store_true ' , help = ' Use PTY emulation and escape sequences for input. Allows to use fenrir on the desktop, in a terminal for X or Wayland ' )
2018-09-10 22:05:13 -04:00
parser . add_argument ( ' -E ' , ' --emulated-evdev ' , action = ' store_true ' , help = ' Use PTY emulation and evdev for input (single instance) ' )
2018-03-21 06:10:28 -04:00
try :
args = parser . parse_args ( )
except Exception as e :
parser . print_help ( )
return args
def proceed ( self ) :
if not self . initialized :
return
self . environment [ ' runtime ' ] [ ' eventManager ' ] . startMainEventLoop ( )
self . shutdown ( )
def handleInput ( self , event ) :
2018-03-28 12:11:03 -04:00
#startTime = time.time()
2018-09-10 22:05:13 -04:00
self . environment [ ' runtime ' ] [ ' debug ' ] . writeDebugOut ( ' DEBUG INPUT fenrirMan: ' + str ( event ) , debug . debugLevel . INFO )
2018-03-21 06:10:28 -04:00
if not event [ ' Data ' ] :
event [ ' Data ' ] = self . environment [ ' runtime ' ] [ ' inputManager ' ] . getInputEvent ( )
2018-09-10 22:05:13 -04:00
if event [ ' Data ' ] :
event [ ' Data ' ] [ ' EventName ' ] = self . environment [ ' runtime ' ] [ ' inputManager ' ] . convertEventName ( event [ ' Data ' ] [ ' EventName ' ] )
2018-03-21 06:10:28 -04:00
self . environment [ ' runtime ' ] [ ' inputManager ' ] . handleInputEvent ( event [ ' Data ' ] )
else :
return
2018-03-22 16:01:38 -04:00
2018-03-21 06:10:28 -04:00
if self . environment [ ' runtime ' ] [ ' inputManager ' ] . noKeyPressed ( ) :
2018-09-10 22:05:13 -04:00
self . environment [ ' runtime ' ] [ ' inputManager ' ] . clearLastDeepInput ( )
2018-03-21 06:10:28 -04:00
if self . environment [ ' runtime ' ] [ ' screenManager ' ] . isSuspendingScreen ( ) :
2018-09-10 22:05:13 -04:00
self . environment [ ' runtime ' ] [ ' inputManager ' ] . writeEventBuffer ( )
2018-03-21 06:10:28 -04:00
else :
if self . environment [ ' runtime ' ] [ ' helpManager ' ] . isTutorialMode ( ) :
2018-09-10 22:05:13 -04:00
self . environment [ ' runtime ' ] [ ' inputManager ' ] . clearEventBuffer ( )
2019-03-03 14:57:58 -05:00
self . environment [ ' runtime ' ] [ ' inputManager ' ] . keyEcho ( event [ ' Data ' ] )
2019-02-03 17:52:12 -05:00
if self . environment [ ' runtime ' ] [ ' vmenuManager ' ] . getActive ( ) :
self . environment [ ' runtime ' ] [ ' inputManager ' ] . clearEventBuffer ( )
2018-03-21 06:10:28 -04:00
2018-09-10 22:05:13 -04:00
self . detectShortcutCommand ( )
2018-03-21 06:10:28 -04:00
if self . modifierInput :
2018-09-10 22:05:13 -04:00
self . environment [ ' runtime ' ] [ ' inputManager ' ] . clearEventBuffer ( )
2018-03-21 06:10:28 -04:00
if self . singleKeyCommand :
if self . environment [ ' runtime ' ] [ ' inputManager ' ] . noKeyPressed ( ) :
self . environment [ ' runtime ' ] [ ' inputManager ' ] . clearEventBuffer ( )
2019-02-03 17:52:12 -05:00
else :
2018-09-10 22:05:13 -04:00
self . environment [ ' runtime ' ] [ ' inputManager ' ] . writeEventBuffer ( )
2018-03-21 06:10:28 -04:00
if self . environment [ ' runtime ' ] [ ' inputManager ' ] . noKeyPressed ( ) :
self . modifierInput = False
self . singleKeyCommand = False
if self . environment [ ' input ' ] [ ' keyForeward ' ] > 0 :
self . environment [ ' input ' ] [ ' keyForeward ' ] - = 1
2018-09-10 22:05:13 -04:00
self . environment [ ' runtime ' ] [ ' commandManager ' ] . executeDefaultTrigger ( ' onKeyInput ' )
2018-03-21 06:10:28 -04:00
#print('handleInput:',time.time() - startTime)
2018-03-24 17:50:27 -04:00
def handleByteInput ( self , event ) :
2018-03-24 21:02:18 -04:00
if not event [ ' Data ' ] :
return
2018-03-24 17:50:27 -04:00
if event [ ' Data ' ] == b ' ' :
2018-03-24 21:02:18 -04:00
return
2018-05-29 16:47:10 -04:00
self . environment [ ' runtime ' ] [ ' byteManager ' ] . handleByteInput ( event [ ' Data ' ] )
self . environment [ ' runtime ' ] [ ' commandManager ' ] . executeDefaultTrigger ( ' onByteInput ' )
def handleExecuteCommand ( self , event ) :
if not event [ ' Data ' ] :
return
2018-03-21 06:10:28 -04:00
if event [ ' Data ' ] == ' ' :
return
command = event [ ' Data ' ]
2019-02-04 13:05:31 -05:00
# special modes
2018-03-21 06:10:28 -04:00
if self . environment [ ' runtime ' ] [ ' helpManager ' ] . isTutorialMode ( ) :
if self . environment [ ' runtime ' ] [ ' commandManager ' ] . commandExists ( command , ' help ' ) :
self . environment [ ' runtime ' ] [ ' commandManager ' ] . executeCommand ( command , ' help ' )
return
2019-02-04 13:05:31 -05:00
elif self . environment [ ' runtime ' ] [ ' vmenuManager ' ] . getActive ( ) :
if self . environment [ ' runtime ' ] [ ' commandManager ' ] . commandExists ( command , ' vmenu-navigation ' ) :
self . environment [ ' runtime ' ] [ ' commandManager ' ] . executeCommand ( command , ' vmenu-navigation ' )
return
# default
2019-03-03 14:57:58 -05:00
self . environment [ ' runtime ' ] [ ' commandManager ' ] . executeCommand ( command , ' commands ' )
2018-09-05 13:13:20 -04:00
def handleRemoteIncomming ( self , event ) :
if not event [ ' Data ' ] :
return
2019-03-03 14:57:58 -05:00
self . environment [ ' runtime ' ] [ ' remoteManager ' ] . handleRemoteIncomming ( event [ ' Data ' ] )
2019-02-03 17:52:12 -05:00
def handleScreenChange ( self , event ) :
2018-03-21 06:10:28 -04:00
self . environment [ ' runtime ' ] [ ' screenManager ' ] . hanldeScreenChange ( event [ ' Data ' ] )
'''
if self . environment [ ' runtime ' ] [ ' applicationManager ' ] . isApplicationChange ( ) :
self . environment [ ' runtime ' ] [ ' commandManager ' ] . executeDefaultTrigger ( ' onApplicationChange ' )
self . environment [ ' runtime ' ] [ ' commandManager ' ] . executeSwitchTrigger ( ' onSwitchApplicationProfile ' , \
self . environment [ ' runtime ' ] [ ' applicationManager ' ] . getPrevApplication ( ) , \
self . environment [ ' runtime ' ] [ ' applicationManager ' ] . getCurrentApplication ( ) )
'''
2019-02-03 17:52:12 -05:00
if self . environment [ ' runtime ' ] [ ' vmenuManager ' ] . getActive ( ) :
return
self . environment [ ' runtime ' ] [ ' commandManager ' ] . executeDefaultTrigger ( ' onScreenChanged ' )
self . environment [ ' runtime ' ] [ ' screenDriver ' ] . getCurrScreen ( )
2018-03-21 06:10:28 -04:00
def handleScreenUpdate ( self , event ) :
#startTime = time.time()
self . environment [ ' runtime ' ] [ ' screenManager ' ] . handleScreenUpdate ( event [ ' Data ' ] )
'''
if self . environment [ ' runtime ' ] [ ' applicationManager ' ] . isApplicationChange ( ) :
self . environment [ ' runtime ' ] [ ' commandManager ' ] . executeDefaultTrigger ( ' onApplicationChange ' )
self . environment [ ' runtime ' ] [ ' commandManager ' ] . executeSwitchTrigger ( ' onSwitchApplicationProfile ' , \
self . environment [ ' runtime ' ] [ ' applicationManager ' ] . getPrevApplication ( ) , \
2019-02-03 17:52:12 -05:00
self . environment [ ' runtime ' ] [ ' applicationManager ' ] . getCurrentApplication ( ) )
2018-03-21 06:10:28 -04:00
'''
# timout for the last keypress
if time . time ( ) - self . environment [ ' runtime ' ] [ ' inputManager ' ] . getLastInputTime ( ) > = 0.3 :
2019-02-03 17:52:12 -05:00
self . environment [ ' runtime ' ] [ ' inputManager ' ] . clearLastDeepInput ( )
# has cursor changed?
2018-03-21 06:10:28 -04:00
if self . environment [ ' runtime ' ] [ ' cursorManager ' ] . isCursorVerticalMove ( ) or \
self . environment [ ' runtime ' ] [ ' cursorManager ' ] . isCursorHorizontalMove ( ) :
self . environment [ ' runtime ' ] [ ' commandManager ' ] . executeDefaultTrigger ( ' onCursorChange ' )
self . environment [ ' runtime ' ] [ ' commandManager ' ] . executeDefaultTrigger ( ' onScreenUpdate ' )
self . environment [ ' runtime ' ] [ ' inputManager ' ] . clearLastDeepInput ( )
#print('handleScreenUpdate:',time.time() - startTime)
def handlePlugInputDevice ( self , event ) :
2018-05-18 06:39:57 -04:00
self . environment [ ' runtime ' ] [ ' inputManager ' ] . handlePlugInputDevice ( event [ ' Data ' ] )
2019-02-03 17:52:12 -05:00
self . environment [ ' runtime ' ] [ ' commandManager ' ] . executeDefaultTrigger ( ' onPlugInputDevice ' , force = True )
2018-03-21 06:10:28 -04:00
def handleHeartBeat ( self , event ) :
self . environment [ ' runtime ' ] [ ' commandManager ' ] . executeDefaultTrigger ( ' onHeartBeat ' , force = True )
2019-02-03 17:52:12 -05:00
#self.environment['runtime']['outputManager'].brailleText(flush=False)
2018-03-25 18:32:25 -04:00
2018-03-26 15:34:15 -04:00
2018-03-26 02:55:26 -04:00
def detectShortcutCommand ( self ) :
2018-03-21 06:10:28 -04:00
if self . environment [ ' input ' ] [ ' keyForeward ' ] > 0 :
return
if self . environment [ ' runtime ' ] [ ' inputManager ' ] . isKeyPress ( ) :
self . modifierInput = self . environment [ ' runtime ' ] [ ' inputManager ' ] . currKeyIsModifier ( )
else :
if not self . environment [ ' runtime ' ] [ ' inputManager ' ] . noKeyPressed ( ) :
if self . singleKeyCommand :
self . singleKeyCommand = len ( self . environment [ ' runtime ' ] [ ' inputManager ' ] . getLastDeepestInput ( ) ) == 1
# key is already released. we need the old one
if not ( self . singleKeyCommand and self . environment [ ' runtime ' ] [ ' inputManager ' ] . noKeyPressed ( ) ) :
shortcut = self . environment [ ' runtime ' ] [ ' inputManager ' ] . getCurrShortcut ( )
2018-03-25 18:32:25 -04:00
self . command = self . environment [ ' runtime ' ] [ ' inputManager ' ] . getCommandForShortcut ( shortcut )
2019-02-03 17:52:12 -05:00
2018-03-21 06:10:28 -04:00
if not self . modifierInput :
if self . environment [ ' runtime ' ] [ ' inputManager ' ] . isKeyPress ( ) :
if self . command != ' ' :
self . singleKeyCommand = True
if not ( self . singleKeyCommand or self . modifierInput ) :
return
2019-02-03 17:52:12 -05:00
# fire event
2018-03-21 06:10:28 -04:00
if self . command != ' ' :
2019-02-03 17:52:12 -05:00
if self . modifierInput :
2018-03-21 06:10:28 -04:00
self . environment [ ' runtime ' ] [ ' eventManager ' ] . putToEventQueue ( fenrirEventType . ExecuteCommand , self . command )
2019-02-03 17:52:12 -05:00
self . command = ' '
else :
2018-03-21 06:10:28 -04:00
if self . singleKeyCommand :
if self . environment [ ' runtime ' ] [ ' inputManager ' ] . noKeyPressed ( ) :
self . environment [ ' runtime ' ] [ ' eventManager ' ] . putToEventQueue ( fenrirEventType . ExecuteCommand , self . command )
self . command = ' '
2018-05-11 18:23:45 -04:00
def setProcessName ( self , name = ' fenrir ' ) :
""" Attempts to set the process name to ' fenrir ' . """
2018-03-21 06:10:28 -04:00
2018-05-11 18:23:45 -04:00
#sys.argv[0] = name
# Disabling the import error of setproctitle.
# pylint: disable-msg=F0401
try :
from setproctitle import setproctitle
except ImportError :
pass
else :
setproctitle ( name )
return True
try :
from ctypes import cdll , byref , create_string_buffer
libc = cdll . LoadLibrary ( ' libc.so.6 ' )
stringBuffer = create_string_buffer ( len ( name ) + 1 )
stringBuffer . value = bytes ( name , ' UTF-8 ' )
libc . prctl ( 15 , byref ( stringBuffer ) , 0 , 0 , 0 )
return True
except :
pass
return False
2018-03-21 06:10:28 -04:00
def shutdownRequest ( self ) :
try :
self . environment [ ' runtime ' ] [ ' eventManager ' ] . stopMainEventLoop ( )
except :
pass
def captureSignal ( self , siginit , frame ) :
self . shutdownRequest ( )
def shutdown ( self ) :
2019-02-03 17:52:12 -05:00
self . environment [ ' runtime ' ] [ ' eventManager ' ] . stopMainEventLoop ( )
2018-03-21 06:10:28 -04:00
self . environment [ ' runtime ' ] [ ' outputManager ' ] . presentText ( _ ( " Quit Fenrir " ) , soundIcon = ' ScreenReaderOff ' , interrupt = True )
self . environment [ ' runtime ' ] [ ' eventManager ' ] . cleanEventQueue ( )
2018-04-13 17:42:18 -04:00
time . sleep ( 0.6 )
2018-03-21 06:10:28 -04:00
for currManager in self . environment [ ' general ' ] [ ' managerList ' ] :
if self . environment [ ' runtime ' ] [ currManager ] :
self . environment [ ' runtime ' ] [ currManager ] . shutdown ( )
del self . environment [ ' runtime ' ] [ currManager ]
self . environment = None