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:
chrys
2017-07-23 21:02:52 +02:00
48 changed files with 1165 additions and 568 deletions

View File

@ -17,7 +17,7 @@ class command():
return _('exits Fenrir')
def run(self):
self.env['general']['running'] = False
self.env['runtime']['eventManager'].stopMainEventLoop()
def setCallback(self, callback):
pass

View File

@ -14,13 +14,11 @@ class command():
def shutdown(self):
pass
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.')
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']['outputManager'].presentText(text, interrupt=True)
self.env['general']['tutorialMode'] = True
self.env['runtime']['helpManager'].toggleTutorialMode()
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)
def setCallback(self, callback):
pass

View File

@ -0,0 +1,2 @@
this folder contains help and tutorial related functions.
those are not bindable but hard coded.

View 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

View 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

View 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

View File

@ -21,9 +21,7 @@ class command():
if not self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'cursor'):
return
if self.env['runtime']['screenManager'].isScreenChange():
return
if self.env['runtime']['inputManager'].noKeyPressed():
return
return
# detect an change on the screen, we just want to cursor arround, so no change should appear
if self.env['runtime']['screenManager'].isDelta():
return

View File

@ -19,9 +19,7 @@ class command():
def run(self):
if not self.env['runtime']['settingsManager'].getSettingAsBool('focus', 'cursor'):
return
if self.env['runtime']['inputManager'].noKeyPressed():
return
return
if self.env['runtime']['screenManager'].isScreenChange():
return
# this leads to problems in vim -> status line change -> no announcement, so we do check the lengh as hack

View File

@ -29,8 +29,6 @@ class command():
# just when cursor move worddetection is needed
if not self.env['runtime']['cursorManager'].isCursorHorizontalMove():
return
if self.env['runtime']['inputManager'].noKeyPressed():
return
# for now no new line
if self.env['runtime']['cursorManager'].isCursorVerticalMove():
return

View File

@ -39,8 +39,6 @@ class command():
return
if not self.env['runtime']['settingsManager'].getSettingAsBool('general', 'autoSpellCheck'):
return
if self.env['runtime']['inputManager'].noKeyPressed():
return
if self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage') != self.language:
try:
self.updateSpellLanguage()

View File

@ -19,20 +19,16 @@ class command():
def run(self):
if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'charDeleteEcho'):
return
# detect typing or chilling
if self.env['screen']['newCursor']['x'] >= self.env['screen']['oldCursor']['x']:
return
# More than just a deletion happend
if self.env['runtime']['screenManager'].isDelta():
return
# no deletion
if not self.env['runtime']['screenManager'].isNegativeDelta():
return
if self.env['runtime']['inputManager'].noKeyPressed():
return
return
# too much for a single backspace...
# word begin produce a diff wiht len == 2 |a | others with 1 |a|
@ -43,7 +39,6 @@ class command():
currNegativeDelta.strip() != '':
currNegativeDelta = currNegativeDelta.strip()
self.env['runtime']['outputManager'].presentText(currNegativeDelta, interrupt=True, ignorePunctuation=True, announceCapital=True, flush=False)
def setCallback(self, callback):
pass

View 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

View 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

View File

View 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

View 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

View File

@ -17,23 +17,23 @@ class command():
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
if len(self.env['screen']['newDelta']) <=2:
return
# its a cursor movement (experimental) - maybe also check current shortcut string?
#if not '$' in self.env['screen']['newDelta'] and
# not '#' in self.env['screen']['newDelta']:
if abs(self.env['screen']['newCursor']['x'] - self.env['screen']['oldCursor']['x']) >= 1:
if len(self.env['screen']['newDelta'].strip(' \n\t0123456789')) <= 2:
return
if abs(self.env['screen']['newCursor']['x'] - self.env['screen']['oldCursor']['x']) == 1:
# if len(self.env['screen']['newDelta'].strip(' \n\t0123456789')) <= 2:
return
if abs(self.env['screen']['newCursor']['y'] - self.env['screen']['oldCursor']['y']) == 1:
if len(self.env['screen']['newDelta'].strip(' \n\t0123456789')) <= 2:
return
# if len(self.env['screen']['newDelta'].strip(' \n\t0123456789')) <= 2:
return
self.env['runtime']['outputManager'].presentText(self.env['screen']['newDelta'], interrupt=False, flush=False)
def setCallback(self, callback):

View File

@ -22,7 +22,7 @@ class command():
return
if self.env['runtime']['settingsManager'].getSetting('promote', 'list').strip(" \t\n") == '':
return
if self.env['screen']['newDelta'] == '':
if len(self.env['screen']['newDelta']) <= 2:
return
if int(time.time() - self.env['input']['lastInputTime']) < self.env['runtime']['settingsManager'].getSettingAsInt('promote', 'inactiveTimeoutSec'):
return

View File

@ -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

View File

@ -7,7 +7,6 @@
from core import debug
import time
# used as shared memory between commands
# use this in your own commands
commandBuffer = {
@ -24,39 +23,7 @@ commandBuffer = {
# used by the commandManager
commandInfo = {
'currCommand': '',
#'currCommand': '',
'lastCommandExecutionTime': 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':{
},
}

View File

@ -15,10 +15,13 @@ class commandManager():
def initialize(self, environment):
self.env = environment
# commands
self.env['commands'] = {}
self.env['commandsIgnore'] = {}
for commandFolder in self.env['general']['commandFolderList']:
self.env['runtime']['commandManager'].loadCommands(commandFolder,
self.env['runtime']['settingsManager'].getSetting('general', 'commandPath'))
self.env['runtime']['commandManager'].loadCommands(commandFolder)
self.env['runtime']['commandManager'].loadCommands(commandFolder)
if self.env['runtime']['settingsManager'].getSetting('general', 'commandPath') != '':
self.env['runtime']['commandManager'].loadCommands(commandFolder,
self.env['runtime']['settingsManager'].getSetting('general', 'commandPath'))
# scripts for scriptKey
self.env['runtime']['commandManager'].loadScriptCommands()
@ -42,7 +45,8 @@ class commandManager():
if not os.access(commandFolder, os.R_OK):
self.env['runtime']['debug'].writeDebugOut("commandFolder not readable:" + commandFolder ,debug.debugLevel.ERROR)
return
self.env['commands'][section] = {}
self.env['commandsIgnore'][section] = {}
commandList = glob.glob(commandFolder+'*')
for command in commandList:
try:
@ -62,7 +66,6 @@ class commandManager():
self.env['commands'][section][fileName.upper()].initialize(self.env)
self.env['runtime']['debug'].writeDebugOut("Load command:" + section + "." + fileName.upper() ,debug.debugLevel.INFO, onAnyLevel=True)
except Exception as e:
print(command+str(e))
self.env['runtime']['debug'].writeDebugOut("Loading command:" + command ,debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
continue
@ -123,7 +126,6 @@ class commandManager():
shortcut.append(sorted(shortcutKeys))
self.env['bindings'][str(shortcut)] = fileName.upper()
except Exception as e:
print(e)
self.env['runtime']['debug'].writeDebugOut("Loading script:" + command ,debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
continue
@ -172,37 +174,47 @@ class commandManager():
self.env['runtime']['debug'].writeDebugOut("Executing trigger.command:" + trigger + "." + command ,debug.debugLevel.INFO)
self.env['commands'][trigger][command].run()
except Exception as e:
self.env['runtime']['debug'].writeDebugOut("Executing trigger:" + trigger + "." + command ,debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut("Executing trigger:" + trigger + "." + command + str(e) ,debug.debugLevel.ERROR)
def executeCommand(self, command, section = 'commands'):
if self.env['runtime']['screenManager'].isSuspendingScreen():
return
if self.commandExists(command, section):
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)
description = self.env['commands'][section][command].getDescription()
description = self.getCommandDescription(command, section)
self.env['runtime']['outputManager'].presentText(description, interrupt=True)
else:
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:
self.env['runtime']['debug'].writeDebugOut("Executing command:" + section + "." + command ,debug.debugLevel.ERROR)
self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
self.clearCommandQueued()
self.env['runtime']['debug'].writeDebugOut("Executing command:" + section + "." + command +' ' + str(e),debug.debugLevel.ERROR)
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()
def isCommandQueued(self):
return self.env['commandInfo']['currCommand'] != ''
def clearCommandQueued(self):
self.env['commandInfo']['currCommand'] = ''
def queueCommand(self, command):
if command == '':
return
self.env['commandInfo']['currCommand'] = command
def getCommandDescription(self, command, section = 'commands'):
if self.commandExists(command, section):
try:
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'):
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

View File

@ -19,8 +19,6 @@ environment = {
'runtime': runtimeData,
'general': generalData,
'settings': settingsData,
'commands': commandData.commands,
'commandsIgnore': commandData.commandsIgnore,
'commandInfo': commandData.commandInfo,
'commandBuffer': commandData.commandBuffer,
'input': inputData,

24
src/fenrir/core/eventData.py Executable file
View 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

View File

@ -4,29 +4,14 @@
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
#from core import debug
from core import debug
from core.eventData import fenrirEventType
from queue import Empty
import time
from enum import Enum
from multiprocessing import Process, Queue
from multiprocessing.sharedctypes import Value
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():
def __init__(self):
self._mainLoopRunning = Value(c_bool, True)
@ -34,11 +19,20 @@ class eventManager():
self._eventQueue = Queue() # multiprocessing.Queue()
self.cleanEventQueue()
def initialize(self, environment):
self.env = environment
self.env = environment
self.addSimpleEventThread(fenrirEventType.HeartBeat, self.heartBeatTimer)
def shutdown(self):
self.terminateAllProcesses()
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):
time.sleep(1)
for proc in self._eventProcesses:
try:
proc.terminate()
@ -46,20 +40,24 @@ class eventManager():
print(e)
def proceedEventLoop(self):
event = self._eventQueue.get()
st = time.time()
self.eventDispatcher(event)
#print('NET loop ' + str(time.time() - st))
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:
return
if not event['Type']:
return
if event['Type'] == fenrirEventType.Ignore:
return
elif event['Type'] == fenrirEventType.StopMainLoop:
self._mainLoopRunning.value = 0
self.handleStopMainLoop(event)
return
elif event['Type'] == fenrirEventType.ScreenUpdate:
print('do an update')
pass
self.env['runtime']['fenrirManager'].handleScreenUpdate(event)
elif event['Type'] == fenrirEventType.KeyboardInput:
pass
self.env['runtime']['fenrirManager'].handleInput(event)
elif event['Type'] == fenrirEventType.BrailleInput:
pass
elif event['Type'] == fenrirEventType.PlugInputDevice:
@ -67,20 +65,42 @@ class eventManager():
elif event['Type'] == fenrirEventType.BrailleFlush:
pass
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):
self._mainLoopRunning.value = True
while(self._mainLoopRunning.value):
self._mainLoopRunning.value = 1
while( self.isMainEventLoopRunning()):
self.proceedEventLoop()
def handleStopMainLoop(self, event):
self._mainLoopRunning.value = 0
time.sleep(0.1)
def stopMainEventLoop(self, Force = False):
if Force:
self._mainLoopRunning.value = False
self._mainLoopRunning.value = 0
self._eventQueue.put({"Type":fenrirEventType.StopMainLoop,"Data":None})
def addEventThread(self, event, function):
self._mainLoopRunning.value = True
t = Process(target=self.eventWorkerThread, args=(event, function))
def addCustomEventThread(self, function, pargs = None, multiprocess=False):
self._mainLoopRunning.value = 1
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)
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):
if self._eventQueue.empty():
return
@ -94,32 +114,34 @@ class eventManager():
return False
self._eventQueue.put({"Type":event,"Data":data})
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):
return
if not callable(function):
return
while self._mainLoopRunning.value:
while self.isMainEventLoopRunning():
Data = None
try:
Data = function()
if args != None:
Data = function(self._mainLoopRunning, args)
else:
Data = function()
except Exception as e:
print(e)
self.env['runtime']['debug'].writeDebugOut('eventManager:simpleEventWorkerThread:function():' + st(e),debug.debugLevel.ERROR)
self.putToEventQueue(event, Data)
'''
def p():
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 )
'''
if runOnce:
break

View File

@ -13,6 +13,7 @@ if not os.path.dirname(os.path.realpath(fenrirVersion.__file__)) in sys.path:
from core import i18n
from core import settingsManager
from core import debug
from core.eventData import fenrirEventType
import argparse
class fenrirManager():
@ -22,22 +23,24 @@ class fenrirManager():
if not cliArgs:
return
try:
self.environment = settingsManager.settingsManager().initFenrirConfig(cliArgs)
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.initialized = True
self.environment['runtime']['outputManager'].presentText(_("Start Fenrir"), soundIcon='ScreenReaderOn', interrupt=True)
signal.signal(signal.SIGINT, 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):
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')
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:
args = parser.parse_args()
except Exception as e:
@ -46,79 +49,123 @@ class fenrirManager():
def proceed(self):
if not self.initialized:
return
while(self.environment['general']['running']):
try:
self.handleProcess()
except Exception as e:
self.environment['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)
self.environment['runtime']['eventManager'].startMainEventLoop()
self.shutdown()
def handleProcess(self):
def handleInput(self, event):
#startTime = time.time()
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:
self.prepareCommand()
if not (self.wasCommand or self.environment['general']['tutorialMode']) or self.environment['runtime']['screenManager'].isSuspendingScreen():
self.environment['runtime']['inputManager'].writeEventBuffer()
if self.environment['runtime']['screenManager'].isSuspendingScreen():
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.wasCommand:
self.wasCommand = False
self.environment['runtime']['inputManager'].clearEventBuffer()
if self.environment['general']['tutorialMode']:
self.environment['runtime']['inputManager'].clearEventBuffer()
if self.environment['input']['keyForeward'] > 0:
self.environment['input']['keyForeward'] -=1
self.modifierInput = False
self.singleKeyCommand = False
if self.environment['input']['keyForeward'] > 0:
self.environment['input']['keyForeward'] -=1
self.environment['runtime']['screenManager'].update('onInput')
self.environment['runtime']['commandManager'].executeDefaultTrigger('onInput')
else:
self.environment['runtime']['screenManager'].update('onUpdate')
self.environment['runtime']['commandManager'].executeDefaultTrigger('onInput')
#print('handleInput:',time.time() - startTime)
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():
self.environment['runtime']['commandManager'].executeDefaultTrigger('onApplicationChange')
self.environment['runtime']['commandManager'].executeSwitchTrigger('onSwitchApplicationProfile', \
self.environment['runtime']['applicationManager'].getPrevApplication(), \
self.environment['runtime']['applicationManager'].getCurrentApplication())
if self.environment['runtime']['screenManager'].isScreenChange():
self.environment['runtime']['commandManager'].executeDefaultTrigger('onScreenChanged')
else:
self.environment['runtime']['commandManager'].executeDefaultTrigger('onScreenUpdate')
#self.environment['runtime']['outputManager'].brailleText(flush=False)
self.handleCommands()
#print(time.time()-startTime)
'''
self.environment['runtime']['commandManager'].executeDefaultTrigger('onScreenChanged')
def handleScreenUpdate(self, event):
#startTime = time.time()
def prepareCommand(self):
if self.environment['runtime']['screenManager'].isSuspendingScreen():
self.wasCommand = False
return
if self.environment['runtime']['inputManager'].noKeyPressed():
return
self.environment['runtime']['screenManager'].update('onUpdate')
'''
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())
'''
# 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:
return
shortcut = self.environment['runtime']['inputManager'].getCurrShortcut()
command = self.environment['runtime']['inputManager'].getCommandForShortcut(shortcut)
if len(self.environment['input']['prevDeepestInput']) <= len(self.environment['input']['currInput']):
self.wasCommand = command != '' or self.environment['runtime']['inputManager'].isFenrirKeyPressed() or self.environment['runtime']['inputManager'].isScriptKeyPressed()
if command == '':
return
self.environment['runtime']['commandManager'].queueCommand(command)
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']['prevDeepestInput']) == 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()
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.environment['runtime']['commandManager'].isCommandQueued():
if not (self.singleKeyCommand or self.modifierInput):
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):
self.environment['general']['running'] = False
self.environment['runtime']['eventManager'].stopMainEventLoop()
def captureSignal(self, siginit, frame):
self.shutdownRequest()
def shutdown(self):
self.environment['runtime']['eventManager'].stopMainEventLoop()
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']:
if self.environment['runtime'][currManager]:
self.environment['runtime'][currManager].shutdown()

View File

@ -7,13 +7,12 @@
from core import debug
generalData = {
'running': True,
'args': None,
'tutorialMode': False,
'currUser':'',
'prevUser':'',
'managerList':['eventManager','punctuationManager','cursorManager','applicationManager','commandManager'
,'screenManager','inputManager','outputManager','debug'],
'commandFolderList':['commands','onInput','onScreenUpdate','onScreenChanged'
,'onApplicationChange','onSwitchApplicationProfile',],
,'screenManager','inputManager','outputManager','helpManager','debug'],
'commandFolderList':['commands','onInput', 'onCursorChange', 'onScreenUpdate','onScreenChanged','onHeartBeat', 'onPlugInputDevice'
,'onApplicationChange','onSwitchApplicationProfile','help',],
}

81
src/fenrir/core/helpManager.py Executable file
View 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

View File

@ -39,7 +39,7 @@ class inputManager():
self.env['input']['currInput'].remove(mEvent['EventName'])
if len(self.env['input']['currInput']) > 1:
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']['shortcutRepeat'] = 1
self.setLedState = self.handleLedStates(mEvent)
@ -141,13 +141,6 @@ class inputManager():
eventName = 'KEY_SCRIPT'
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):
self.env['runtime']['inputDriver'].clearEventBuffer()
@ -155,24 +148,15 @@ class inputManager():
try:
if self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'):
self.env['runtime']['inputDriver'].writeEventBuffer()
time.sleep(0.008)
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:
self.env['runtime']['debug'].writeDebugOut("Error while writeUInput",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):
return self.env['input']['currInput'] == []
def isKeyPress(self):
return (self.env['input']['prevInput'] == []) and (self.env['input']['currInput'] != [])
def getPrevDeepestInput(self):
shortcut = []
shortcut.append(self.env['input']['shortcutRepeat'])
@ -185,10 +169,13 @@ class inputManager():
shortcut.append(self.env['input']['prevInput'])
return str(shortcut)
def getCurrShortcut(self):
def getCurrShortcut(self, inputSequence = None):
shortcut = []
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 self.env['input']['shortcutRepeat'] > 1 and not self.shortcutExists(str(shortcut)):
shortcut = []
@ -198,10 +185,17 @@ class inputManager():
self.env['runtime']['debug'].writeDebugOut("currShortcut " + str(shortcut) ,debug.debugLevel.INFO)
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):
return eventName in self.env['input']['fenrirKey']
def isScriptKey(self, eventName):
return eventName in self.env['input']['scriptKey']
def getCommandForShortcut(self, shortcut):
if not self.shortcutExists(shortcut):
return ''

View File

@ -21,16 +21,19 @@ class screenManager():
self.env['runtime']['settingsManager'].shutdownDriver('screenDriver')
def update(self, trigger='onUpdate'):
self.env['runtime']['screenDriver'].getCurrScreen()
self.env['runtime']['screenDriver'].getSessionInformation()
self.env['runtime']['screenDriver'].getCurrScreen()
if trigger == 'onScreenChange':
self.env['runtime']['screenDriver'].getSessionInformation()
self.env['screen']['oldApplication'] = self.env['screen']['newApplication']
if self.isScreenChange():
self.changeBrailleScreen()
if not self.isSuspendingScreen(self.env['screen']['newTTY']):
self.env['runtime']['screenDriver'].update(trigger)
if trigger == 'onUpdate' or self.isScreenChange() \
or len(self.env['screen']['newDelta']) > 6:
self.env['runtime']['screenDriver'].getCurrApplication()
#if trigger == 'onUpdate' or self.isScreenChange() \
# or len(self.env['screen']['newDelta']) > 6:
# self.env['runtime']['screenDriver'].getCurrApplication()
self.env['screen']['lastScreenUpdate'] = time.time()
def isSuspendingScreen(self, screen = None):
@ -42,6 +45,7 @@ class screenManager():
ignoreScreens.extend(fixIgnoreScreens.split(','))
if self.env['runtime']['settingsManager'].getSettingAsBool('screen', 'autodetectSuspendingScreen'):
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)
def isScreenChange(self):

View File

@ -76,7 +76,7 @@ settingsData = {
'review':{
'lineBreak': True,
'endOfScreen': True,
'leaveReviewOnKeypress': False,
'leaveReviewOnCursorChange': True,
'leaveReviewOnScreenChange': True,
},
'promote':{

View File

@ -15,6 +15,7 @@ from core import screenManager
from core import punctuationManager
from core import cursorManager
from core import applicationManager
from core import helpManager
from core import environment
from core import inputData
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)
continue
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()
# fix bindings
self.env['bindings'][str([1, ['KEY_F1', 'KEY_FENRIR']])] = 'TOGGLE_TUTORIAL_MODE'
def loadSoundIcons(self, soundIconPath):
siConfig = open(soundIconPath + '/soundicons.conf',"r")
@ -147,7 +150,7 @@ class settingsManager():
def getSetting(self, section, setting):
value = ''
try:
value = self.settingArgDict[section][setting]
value = self.settingArgDict[section.lower()][setting.lower()]
return value
except:
pass
@ -160,10 +163,10 @@ class settingsManager():
def getSettingAsInt(self, section, setting):
value = 0
try:
value = int(self.settingArgDict[section][setting])
value = int(self.settingArgDict[section.lower()][setting.lower()])
return value
except:
pass
except Exception as e:
pass
try:
value = self.env['settings'].getint(section, setting)
except:
@ -173,7 +176,7 @@ class settingsManager():
def getSettingAsFloat(self, section, setting):
value = 0.0
try:
value = float(self.settingArgDict[section][setting])
value = float(self.settingArgDict[section.lower()][setting.lower()])
return value
except Exception as e:
pass
@ -186,7 +189,7 @@ class settingsManager():
def getSettingAsBool(self, section, setting):
value = False
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
except Exception as e:
pass
@ -226,8 +229,16 @@ class settingsManager():
for key in keyList:
if not key in self.env['input']['scriptKey']:
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):
optionArgDict = {}
for optionElem in settingArgs.split(';'):
if len(optionElem.split('#',1)) != 2:
continue
@ -236,13 +247,9 @@ class settingsManager():
section = str(optionElem.split('#',1)[0]).lower()
option = str(optionElem.split('#',1)[1].split('=',1)[0]).lower()
value = optionElem.split('#',1)[1].split('=',1)[1]
try:
e = optionArgDict[section]
except KeyError:
optionArgDict[section] = {}
optionArgDict[section][option] = str(value)
return optionArgDict
def initFenrirConfig(self, cliArgs, environment = environment.environment):
self.setOptionArgDict(section, option, value)
def initFenrirConfig(self, cliArgs, fenrirManager = None, environment = environment.environment):
settingsRoot = '/etc/fenrir/'
settingsFile = cliArgs.setting
soundRoot = '/usr/share/sounds/fenrir/'
@ -271,11 +278,15 @@ class settingsManager():
validConfig = environment['runtime']['settingsManager'].loadSettings(settingsFile)
if not validConfig:
return None
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.setScriptKeys(self.getSetting('general','scriptKeys'))
if not os.path.exists(self.getSetting('keyboard','keyboardLayout')):
if os.path.exists(settingsRoot + 'keyboard/' + self.getSetting('keyboard','keyboardLayout')):
self.setSetting('keyboard', 'keyboardLayout', settingsRoot + 'keyboard/' + self.getSetting('keyboard','keyboardLayout'))
@ -304,6 +315,8 @@ class settingsManager():
else:
environment['runtime']['settingsManager'].loadDicts(self.getSetting('general','punctuationProfile'))
if fenrirManager:
environment['runtime']['fenrirManager'] = fenrirManager
environment['runtime']['eventManager'] = eventManager.eventManager()
environment['runtime']['eventManager'].initialize(environment)
environment['runtime']['inputManager'] = inputManager.inputManager()
@ -318,15 +331,17 @@ class settingsManager():
environment['runtime']['cursorManager'].initialize(environment)
environment['runtime']['applicationManager'] = applicationManager.applicationManager()
environment['runtime']['applicationManager'].initialize(environment)
environment['runtime']['helpManager'] = helpManager.helpManager()
environment['runtime']['helpManager'].initialize(environment)
if environment['runtime']['screenManager'] == None:
environment['runtime']['screenManager'] = screenManager.screenManager()
environment['runtime']['screenManager'].initialize(environment)
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('\/-------settings.conf-------\/',debug.debugLevel.INFO, onAnyLevel=True)
environment['runtime']['debug'].writeDebugOut(str(environment['settings']._sections
),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(str(environment['settings']._sections) , 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

View File

@ -5,7 +5,9 @@
# By Chrys, Storm Dragon, and contributers.
_evdevAvailable = False
_udevAvailable = False
_evdevAvailableError = ''
_udevAvailableError = ''
try:
import evdev
from evdev import InputDevice, UInput
@ -13,42 +15,93 @@ try:
except Exception as e:
_evdevAvailableError = str(e)
try:
import pyudev
_udevAvailable = True
except Exception as e:
_udevAvailableError = str(e)
import time
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 debug
class driver():
def __init__(self):
self._manager = multiprocessing.Manager()
self.iDevices = {}
self.iDevicesFD = None
self.uDevices = {}
self.iDeviceNo = 0
self._initialized = False
self.watchDog = Value(c_bool, True)
def initialize(self, environment):
self.env = environment
global _evdevAvailable
global _udevAvailable
self._initialized = _evdevAvailable
if not self._initialized:
global _evdevAvailableError
self.env['runtime']['debug'].writeDebugOut('InputDriver: ' + _evdevAvailableError,debug.debugLevel.ERROR)
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):
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):
if not self.hasIDevices():
time.sleep(0.008) # dont flood CPU
self.watchDog.value = 1
return 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 != []:
for fd in r:
try:
event = self.iDevices[fd].read_one()
except:
self.removeDevice(fd)
self.watchDog.value = 1
return None
foreward = False
while(event):
@ -66,6 +119,7 @@ class driver():
continue
if not foreward:
if currMapEvent['EventState'] in [0,1,2]:
self.watchDog.value = 1
return currMapEvent
else:
if not event.type in [0,1,4]:
@ -73,7 +127,8 @@ class driver():
event = self.iDevices[fd].read_one()
if foreward:
self.writeEventBuffer()
self.clearEventBuffer()
self.clearEventBuffer()
self.watchDog.value = 1
return None
def writeEventBuffer(self):
@ -92,7 +147,7 @@ class driver():
return
uDevice.write_event(event)
uDevice.syn()
time.sleep(0.01)
time.sleep(0.0001)
def updateInputDevices(self, force = False, init = False):
if init:
@ -145,6 +200,11 @@ class driver():
self.env['runtime']['debug'].writeDebugOut('Device added (Name):' + self.iDevices[currDevice.fd].name,debug.debugLevel.INFO)
except Exception as e:
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())
def mapEvent(self, event):
@ -191,6 +251,9 @@ class driver():
self.grabDevice(fd)
def grabDevice(self, fd):
if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'):
self.uDevices[fd] = None
return
try:
self.uDevices[fd] = UInput.from_device(self.iDevices[fd].fn)
except Exception as e:
@ -232,7 +295,12 @@ class driver():
try:
del(self.uDevices[fd])
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):
if not self._initialized:
return False

View File

@ -3,23 +3,42 @@
# Fenrir TTY screen reader
# 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 re
import subprocess
import fcntl
import glob, os
import termios
import time
import select
import dbus
from core import debug
import fcntl
from array import array
import errno
import sys
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():
def __init__(self):
self.vcsaDevicePath = '/dev/vcsa'
self.ListSessions = None
self.charmap = {}
self.hichar = None
def initialize(self, environment):
self.env = environment
self.env['runtime']['eventManager'].addCustomEventThread(self.updateWatchdog)
def shutdown(self):
pass
def getCurrScreen(self):
@ -92,9 +111,126 @@ class driver():
self.env['general']['currUser'] = session[2]
except Exception as e:
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'):
if trigger == 'onInput': # no need for an update on input for VCSA
return
newContentBytes = b''
try:
# read screen
@ -124,10 +260,17 @@ class driver():
self.env['screen']['newCursor']['x'] = int( self.env['screen']['newContentBytes'][2])
self.env['screen']['newCursor']['y'] = int( self.env['screen']['newContentBytes'][3])
# 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'])
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 screenEncoding.upper() == 'AUTO':
self.updateCharMap(str(self.env['screen']['newTTY']))
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']:
self.env['screen']['oldContentBytes'] = b''