Moved flag parsing to launcher. Got read of fenrir-daemon and put everything into the fenrir launcher.

This commit is contained in:
Storm Dragon
2024-12-07 23:36:21 -05:00
parent 4c9e0bfd36
commit 9cdf80b313
4 changed files with 161 additions and 189 deletions

View File

@ -2,109 +2,50 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
import signal, time, argparse, os, sys
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
from fenrirscreenreader import fenrirVersion
class fenrirManager():
def __init__(self):
self.initialized = False
cliArgs = self.handleArgs()
if not cliArgs:
return
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.initialized = True
self.isInitialized = True
self.modifierInput = False
self.singleKeyCommand = False
self.command = ''
self.setProcessName()
def handleArgs(self):
"""
Parse and handle command line arguments for Fenrir.
Returns:
argparse.Namespace: Parsed command line arguments
None: If argument parsing fails
"""
parser = argparse.ArgumentParser(
description="Fenrir - A console screen reader for Linux",
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument(
'-v', '--version',
action='version',
version=f'Fenrir screen reader version {fenrirVersion.version}-{fenrirVersion.codeName}',
help='Show version information and exit'
)
parser.add_argument(
'-s', '--setting',
metavar='SETTING-FILE',
default='/etc/fenrir/settings/settings.conf',
help='Path to custom settings file'
)
parser.add_argument(
'-o', '--options',
metavar='SECTION#SETTING=VALUE;..',
default='',
help='Override settings file options. Format: SECTION#SETTING=VALUE;... (case sensitive)'
)
parser.add_argument(
'-d', '--debug',
action='store_true',
help='Enable debug mode'
)
parser.add_argument(
'-p', '--print',
action='store_true',
help='Print debug messages to screen'
)
parser.add_argument(
'-e', '--emulated-pty',
action='store_true',
help='Use PTY emulation with escape sequences for input (enables desktop/X/Wayland usage)'
)
parser.add_argument(
'-E', '--emulated-evdev',
action='store_true',
help='Use PTY emulation with evdev for input (single instance)'
)
try:
args = parser.parse_args()
# Only do format validation, let file existence be handled by the config initialization
if args.options:
for option in args.options.split(';'):
if option and ('#' not in option or '=' not in option):
parser.error(f"Invalid option format: {option}\nExpected format: SECTION#SETTING=VALUE")
if args.emulated_pty and args.emulated_evdev:
parser.error("Cannot use both --emulated-pty and --emulated-evdev simultaneously")
return args
except Exception as e:
print(f"Error parsing arguments: {str(e)}", file=sys.stderr)
return None
def proceed(self):
if not self.initialized:
if not self.isInitialized:
return
self.environment['runtime']['eventManager'].startMainEventLoop()
self.shutdown()
def handleInput(self, event):
#startTime = time.time()
self.environment['runtime']['debug'].writeDebugOut('DEBUG INPUT fenrirMan:' + str(event),debug.debugLevel.INFO)
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'])
@ -113,6 +54,7 @@ class fenrirManager():
if self.environment['runtime']['inputManager'].noKeyPressed():
self.environment['runtime']['inputManager'].clearLastDeepInput()
if self.environment['runtime']['screenManager'].isSuspendingScreen():
self.environment['runtime']['inputManager'].writeEventBuffer()
else:
@ -132,6 +74,7 @@ class fenrirManager():
self.environment['runtime']['inputManager'].clearEventBuffer()
else:
self.environment['runtime']['inputManager'].writeEventBuffer()
if self.environment['runtime']['inputManager'].noKeyPressed():
self.modifierInput = False
self.singleKeyCommand = False
@ -139,73 +82,59 @@ class fenrirManager():
self.environment['runtime']['inputManager'].handleDeviceGrab()
if self.environment['input']['keyForeward'] > 0:
self.environment['input']['keyForeward'] -=1
self.environment['input']['keyForeward'] -= 1
self.environment['runtime']['commandManager'].executeDefaultTrigger('onKeyInput')
#print('handleInput:',time.time() - startTime)
def handleByteInput(self, event):
if not event['Data']:
return
if event['Data'] == b'':
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']:
def handleExecuteCommand(self, event):
if not event['Data'] or event['Data'] == '':
return
if event['Data'] == '':
return
command = event['Data']
currentCommand = event['Data']
# special modes
if self.environment['runtime']['helpManager'].isTutorialMode():
if self.environment['runtime']['commandManager'].commandExists( command, 'help'):
self.environment['runtime']['commandManager'].executeCommand( command, 'help')
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( command, 'vmenu-navigation'):
self.environment['runtime']['commandManager'].executeCommand( command, 'vmenu-navigation')
if self.environment['runtime']['commandManager'].commandExists(currentCommand, 'vmenu-navigation'):
self.environment['runtime']['commandManager'].executeCommand(currentCommand, 'vmenu-navigation')
return
# default
self.environment['runtime']['commandManager'].executeCommand( command, 'commands')
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']['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']['vmenuManager'].getActive():
return
self.environment['runtime']['commandManager'].executeDefaultTrigger('onScreenChanged')
self.environment['runtime']['screenDriver'].getCurrScreen()
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(), \
self.environment['runtime']['applicationManager'].getCurrentApplication())
'''
# timout for the last keypress
if time.time() - self.environment['runtime']['inputManager'].getLastInputTime() >= 0.3:
self.environment['runtime']['inputManager'].clearLastDeepInput()
# has cursor changed?
if self.environment['runtime']['cursorManager'].isCursorVerticalMove() or \
self.environment['runtime']['cursorManager'].isCursorHorizontalMove():
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):
try:
self.environment['runtime']['inputManager'].setLastDetectedDevices(event['Data'])
@ -214,26 +143,27 @@ class fenrirManager():
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)
#self.environment['runtime']['outputManager'].brailleText(flush=False)
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
# 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)
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():
@ -252,7 +182,8 @@ class fenrirManager():
if self.singleKeyCommand:
self.environment['runtime']['eventManager'].putToEventQueue(fenrirEventType.ExecuteCommand, self.command)
self.command = ''
def setProcessName(self, name = 'fenrir'):
def setProcessName(self, name='fenrir'):
"""Attempts to set the process name to 'fenrir'."""
try:
from setproctitle import setproctitle
@ -273,12 +204,14 @@ class fenrirManager():
pass
return False
def shutdownRequest(self):
try:
self.environment['runtime']['eventManager'].stopMainEventLoop()
except:
pass
def captureSignal(self, siginit, frame):
def captureSignal(self, sigInit, frame):
self.shutdownRequest()
def shutdown(self):
@ -287,10 +220,10 @@ class fenrirManager():
self.environment['runtime']['outputManager'].presentText(_("Quit Fenrir"), soundIcon='ScreenReaderOff', interrupt=True)
self.environment['runtime']['eventManager'].cleanEventQueue()
time.sleep(0.6)
for currManager in self.environment['general']['managerList']:
if self.environment['runtime'][currManager]:
self.environment['runtime'][currManager].shutdown()
del self.environment['runtime'][currManager]
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