230 lines
9.9 KiB
Python
230 lines
9.9 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Fenrir TTY screen reader
|
|
# By Chrys, Storm Dragon, and contributors.
|
|
|
|
import signal
|
|
import time
|
|
import os
|
|
import sys
|
|
|
|
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, cliArgs):
|
|
self.isInitialized = False
|
|
try:
|
|
self.environment = settingsManager.settingsManager().initFenrirConfig(cliArgs, self)
|
|
if not self.environment:
|
|
raise RuntimeError('Cannot Initialize. Maybe the configfile is not available or not parseable')
|
|
except RuntimeError:
|
|
raise
|
|
|
|
self.environment['runtime']['outputManager'].presentText(_("Start Fenrir"), soundIcon='ScreenReaderOn', interrupt=True)
|
|
signal.signal(signal.SIGINT, self.captureSignal)
|
|
signal.signal(signal.SIGTERM, self.captureSignal)
|
|
|
|
self.isInitialized = True
|
|
self.modifierInput = False
|
|
self.singleKeyCommand = False
|
|
self.command = ''
|
|
self.setProcessName()
|
|
|
|
def proceed(self):
|
|
if not self.isInitialized:
|
|
return
|
|
self.environment['runtime']['eventManager'].startMainEventLoop()
|
|
self.shutdown()
|
|
|
|
def handleInput(self, event):
|
|
self.environment['runtime']['debug'].writeDebugOut('DEBUG INPUT fenrirMan:' + str(event), debug.debugLevel.INFO)
|
|
|
|
if not event['Data']:
|
|
event['Data'] = self.environment['runtime']['inputManager'].getInputEvent()
|
|
|
|
if event['Data']:
|
|
event['Data']['EventName'] = self.environment['runtime']['inputManager'].convertEventName(event['Data']['EventName'])
|
|
self.environment['runtime']['inputManager'].handleInputEvent(event['Data'])
|
|
else:
|
|
return
|
|
|
|
if self.environment['runtime']['inputManager'].noKeyPressed():
|
|
self.environment['runtime']['inputManager'].clearLastDeepInput()
|
|
|
|
if self.environment['runtime']['screenManager'].isSuspendingScreen():
|
|
self.environment['runtime']['inputManager'].writeEventBuffer()
|
|
else:
|
|
if self.environment['runtime']['helpManager'].isTutorialMode():
|
|
self.environment['runtime']['inputManager'].clearEventBuffer()
|
|
self.environment['runtime']['inputManager'].keyEcho(event['Data'])
|
|
|
|
if self.environment['runtime']['vmenuManager'].getActive():
|
|
self.environment['runtime']['inputManager'].clearEventBuffer()
|
|
|
|
self.detectShortcutCommand()
|
|
|
|
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():
|
|
self.modifierInput = False
|
|
self.singleKeyCommand = False
|
|
self.environment['runtime']['inputManager'].writeEventBuffer()
|
|
self.environment['runtime']['inputManager'].handleDeviceGrab()
|
|
|
|
if self.environment['input']['keyForeward'] > 0:
|
|
self.environment['input']['keyForeward'] -= 1
|
|
|
|
self.environment['runtime']['commandManager'].executeDefaultTrigger('onKeyInput')
|
|
|
|
def handleByteInput(self, event):
|
|
if not event['Data'] or event['Data'] == b'':
|
|
return
|
|
self.environment['runtime']['byteManager'].handleByteInput(event['Data'])
|
|
self.environment['runtime']['commandManager'].executeDefaultTrigger('onByteInput')
|
|
|
|
def handleExecuteCommand(self, event):
|
|
if not event['Data'] or event['Data'] == '':
|
|
return
|
|
currentCommand = event['Data']
|
|
|
|
# special modes
|
|
if self.environment['runtime']['helpManager'].isTutorialMode():
|
|
if self.environment['runtime']['commandManager'].commandExists(currentCommand, 'help'):
|
|
self.environment['runtime']['commandManager'].executeCommand(currentCommand, 'help')
|
|
return
|
|
elif self.environment['runtime']['vmenuManager'].getActive():
|
|
if self.environment['runtime']['commandManager'].commandExists(currentCommand, 'vmenu-navigation'):
|
|
self.environment['runtime']['commandManager'].executeCommand(currentCommand, 'vmenu-navigation')
|
|
return
|
|
|
|
# default
|
|
self.environment['runtime']['commandManager'].executeCommand(currentCommand, 'commands')
|
|
|
|
def handleRemoteIncomming(self, event):
|
|
if not event['Data']:
|
|
return
|
|
self.environment['runtime']['remoteManager'].handleRemoteIncomming(event['Data'])
|
|
|
|
def handleScreenChange(self, event):
|
|
self.environment['runtime']['screenManager'].hanldeScreenChange(event['Data'])
|
|
if self.environment['runtime']['vmenuManager'].getActive():
|
|
return
|
|
self.environment['runtime']['commandManager'].executeDefaultTrigger('onScreenChanged')
|
|
self.environment['runtime']['screenDriver'].getCurrScreen()
|
|
|
|
def handleScreenUpdate(self, event):
|
|
self.environment['runtime']['screenManager'].handleScreenUpdate(event['Data'])
|
|
|
|
if time.time() - self.environment['runtime']['inputManager'].getLastInputTime() >= 0.3:
|
|
self.environment['runtime']['inputManager'].clearLastDeepInput()
|
|
|
|
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()
|
|
|
|
def handlePlugInputDevice(self, event):
|
|
try:
|
|
self.environment['runtime']['inputManager'].setLastDetectedDevices(event['Data'])
|
|
except:
|
|
pass
|
|
self.environment['runtime']['inputManager'].handlePlugInputDevice(event['Data'])
|
|
self.environment['runtime']['commandManager'].executeDefaultTrigger('onPlugInputDevice', force=True)
|
|
self.environment['runtime']['inputManager'].setLastDetectedDevices(None)
|
|
|
|
def handleHeartBeat(self, event):
|
|
self.environment['runtime']['commandManager'].executeDefaultTrigger('onHeartBeat', force=True)
|
|
|
|
def detectShortcutCommand(self):
|
|
if self.environment['input']['keyForeward'] > 0:
|
|
return
|
|
|
|
if len(self.environment['input']['prevInput']) > len(self.environment['input']['currInput']):
|
|
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['input']['currInput']) == 1
|
|
|
|
if not(self.singleKeyCommand and self.environment['runtime']['inputManager'].noKeyPressed()):
|
|
currentShortcut = self.environment['runtime']['inputManager'].getCurrShortcut()
|
|
self.command = self.environment['runtime']['inputManager'].getCommandForShortcut(currentShortcut)
|
|
|
|
if not self.modifierInput:
|
|
if self.environment['runtime']['inputManager'].isKeyPress():
|
|
if self.command != '':
|
|
self.singleKeyCommand = True
|
|
|
|
if not (self.singleKeyCommand or self.modifierInput):
|
|
return
|
|
|
|
# fire event
|
|
if self.command != '':
|
|
if self.modifierInput:
|
|
self.environment['runtime']['eventManager'].putToEventQueue(fenrirEventType.ExecuteCommand, self.command)
|
|
self.command = ''
|
|
else:
|
|
if self.singleKeyCommand:
|
|
self.environment['runtime']['eventManager'].putToEventQueue(fenrirEventType.ExecuteCommand, self.command)
|
|
self.command = ''
|
|
|
|
def setProcessName(self, name='fenrir'):
|
|
"""Attempts to set the process name to 'fenrir'."""
|
|
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
|
|
|
|
def shutdownRequest(self):
|
|
try:
|
|
self.environment['runtime']['eventManager'].stopMainEventLoop()
|
|
except:
|
|
pass
|
|
|
|
def captureSignal(self, sigInit, frame):
|
|
self.shutdownRequest()
|
|
|
|
def shutdown(self):
|
|
self.environment['runtime']['inputManager'].ungrabAllDevices()
|
|
self.environment['runtime']['eventManager'].stopMainEventLoop()
|
|
self.environment['runtime']['outputManager'].presentText(_("Quit Fenrir"), soundIcon='ScreenReaderOff', interrupt=True)
|
|
self.environment['runtime']['eventManager'].cleanEventQueue()
|
|
time.sleep(0.6)
|
|
|
|
for currentManager in self.environment['general']['managerList']:
|
|
if self.environment['runtime'][currentManager]:
|
|
self.environment['runtime'][currentManager].shutdown()
|
|
del self.environment['runtime'][currentManager]
|
|
|
|
self.environment = None
|