Fixed version for master branch.
This commit is contained in:
commit
7a87fb51bb
10
install.sh
10
install.sh
@ -1,12 +1,11 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#Basic install script for Fenrir.
|
||||
read -p "This will install Fenrir. Press ctrl+C to cancel, or enter to continue." continue
|
||||
read -rp "This will install Fenrir. Press ctrl+C to cancel, or enter to continue."
|
||||
|
||||
# Fenrir main application
|
||||
install -m755 -d /opt/fenrirscreenreader
|
||||
cp -af src/* /opt/fenrirscreenreader
|
||||
|
||||
ln -fs /opt/fenrirscreenreader/fenrir-daemon /usr/bin/fenrir-daemon
|
||||
ln -fs /opt/fenrirscreenreader/fenrir /usr/bin/fenrir
|
||||
# tools
|
||||
install -m755 -d /usr/share/fenrirscreenreader/tools
|
||||
@ -33,8 +32,9 @@ cp -af config/sound/template /usr/share/sounds/fenrirscreenreader/template
|
||||
# config
|
||||
if [ -f "/etc/fenrirscreenreader/settings/settings.conf" ]; then
|
||||
echo "Do you want to overwrite your current global settings? (y/n)"
|
||||
read yn
|
||||
if [ $yn = "Y" -o $yn = "y" ]; then
|
||||
read -r yn
|
||||
yn="${yn:0:1}"
|
||||
if [[ "${yn^}" == "Y" ]]; then
|
||||
mv /etc/fenrirscreenreader/settings/settings.conf /etc/fenrirscreenreader/settings/settings.conf.bak
|
||||
echo "Your old settings.conf has been backed up to settings.conf.bak."
|
||||
install -m644 -D "config/settings/settings.conf" /etc/fenrirscreenreader/settings/settings.conf
|
||||
|
@ -3,6 +3,6 @@ daemonize>=2.5.0
|
||||
dbus-python>=1.2.8
|
||||
pyudev>=0.21.0
|
||||
pexpect
|
||||
ppyperclip
|
||||
pyperclip
|
||||
pyte>=0.7.0
|
||||
rapidfuzz>=2.0.0
|
||||
|
@ -11,6 +11,14 @@ class cursorManager():
|
||||
pass
|
||||
def initialize(self, environment):
|
||||
self.env = environment
|
||||
def shouldProcessNumpadCommands(self):
|
||||
"""
|
||||
Check if numpad commands should be processed based on numlock state
|
||||
Return True if numlock is OFF (commands should work)
|
||||
Return False if numlock is ON (let keys type numbers)
|
||||
"""
|
||||
# Return False if numlock is ON
|
||||
return not self.env['input']['newNumLock']
|
||||
def shutdown(self):
|
||||
pass
|
||||
def clearMarks(self):
|
||||
|
@ -42,6 +42,25 @@ class inputDriver():
|
||||
if not self._initialized:
|
||||
return True
|
||||
return True
|
||||
|
||||
def forceUngrab(self):
|
||||
"""Emergency method to release grabbed devices in case of failure"""
|
||||
if not self._initialized:
|
||||
return True
|
||||
try:
|
||||
# Try standard ungrab first
|
||||
return self.ungrabAllDevices()
|
||||
except Exception as e:
|
||||
# Just log the failure and inform the user
|
||||
if hasattr(self, 'env') and 'runtime' in self.env and 'debug' in self.env['runtime']:
|
||||
self.env['runtime']['debug'].writeDebugOut(
|
||||
f"Emergency device release failed: {str(e)}",
|
||||
debug.debugLevel.ERROR
|
||||
)
|
||||
else:
|
||||
print(f"Emergency device release failed: {str(e)}")
|
||||
return False
|
||||
|
||||
def hasIDevices(self):
|
||||
if not self._initialized:
|
||||
return False
|
||||
|
@ -49,6 +49,7 @@ class inputManager():
|
||||
return event
|
||||
def setExecuteDeviceGrab(self, newExecuteDeviceGrab = True):
|
||||
self.executeDeviceGrab = newExecuteDeviceGrab
|
||||
|
||||
def handleDeviceGrab(self, force = False):
|
||||
if force:
|
||||
self.setExecuteDeviceGrab()
|
||||
@ -61,17 +62,38 @@ class inputManager():
|
||||
if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'):
|
||||
self.executeDeviceGrab = False
|
||||
return
|
||||
|
||||
# Add maximum retries to prevent infinite loops
|
||||
maxRetries = 5
|
||||
retryCount = 0
|
||||
grabTimeout = 3 # Timeout in seconds
|
||||
startTime = time.time()
|
||||
|
||||
if self.env['runtime']['screenManager'].getCurrScreenIgnored():
|
||||
while not self.ungrabAllDevices():
|
||||
retryCount += 1
|
||||
if retryCount >= maxRetries or (time.time() - startTime) > grabTimeout:
|
||||
self.env['runtime']['debug'].writeDebugOut("Failed to ungrab devices after multiple attempts", debug.debugLevel.ERROR)
|
||||
# Force a release of devices if possible through alternative means
|
||||
try:
|
||||
self.env['runtime']['inputDriver'].forceUngrab()
|
||||
except:
|
||||
pass
|
||||
break
|
||||
time.sleep(0.25)
|
||||
self.env['runtime']['debug'].writeDebugOut("retry ungrabAllDevices " ,debug.debugLevel.WARNING)
|
||||
self.env['runtime']['debug'].writeDebugOut("All devices ungrabbed" ,debug.debugLevel.INFO)
|
||||
self.env['runtime']['debug'].writeDebugOut(f"retry ungrabAllDevices {retryCount}/{maxRetries}", debug.debugLevel.WARNING)
|
||||
else:
|
||||
while not self.grabAllDevices():
|
||||
retryCount += 1
|
||||
if retryCount >= maxRetries or (time.time() - startTime) > grabTimeout:
|
||||
self.env['runtime']['debug'].writeDebugOut("Failed to grab devices after multiple attempts", debug.debugLevel.ERROR)
|
||||
# Continue without grabbing input - limited functionality but not locked
|
||||
break
|
||||
time.sleep(0.25)
|
||||
self.env['runtime']['debug'].writeDebugOut("retry grabAllDevices" ,debug.debugLevel.WARNING)
|
||||
self.env['runtime']['debug'].writeDebugOut("All devices grabbed" ,debug.debugLevel.INFO)
|
||||
self.env['runtime']['debug'].writeDebugOut(f"retry grabAllDevices {retryCount}/{maxRetries}", debug.debugLevel.WARNING)
|
||||
|
||||
self.executeDeviceGrab = False
|
||||
|
||||
def sendKeys(self, keyMacro):
|
||||
for e in keyMacro:
|
||||
key = ''
|
||||
@ -252,17 +274,39 @@ class inputManager():
|
||||
def getCurrShortcut(self, inputSequence = None):
|
||||
shortcut = []
|
||||
shortcut.append(self.env['input']['shortcutRepeat'])
|
||||
|
||||
numpadKeys = ['KEY_KP0', 'KEY_KP1', 'KEY_KP2', 'KEY_KP3', 'KEY_KP4',
|
||||
'KEY_KP5', 'KEY_KP6', 'KEY_KP7', 'KEY_KP8', 'KEY_KP9',
|
||||
'KEY_KPDOT', 'KEY_KPPLUS', 'KEY_KPMINUS', 'KEY_KPASTERISK',
|
||||
'KEY_KPSLASH', 'KEY_KPENTER', 'KEY_KPEQUAL']
|
||||
if inputSequence:
|
||||
# Check if any key in the sequence is a numpad key and numlock is ON
|
||||
# If numlock is ON and any key in the sequence is a numpad key, return an empty shortcut
|
||||
if not self.env['runtime']['cursorManager'].shouldProcessNumpadCommands():
|
||||
for key in inputSequence:
|
||||
if key in numpadKeys:
|
||||
# Return an empty/invalid shortcut that won't match any command
|
||||
return "[]"
|
||||
|
||||
shortcut.append(inputSequence)
|
||||
else:
|
||||
# Same check for current input
|
||||
|
||||
if not self.env['runtime']['cursorManager'].shouldProcessNumpadCommands():
|
||||
for key in self.env['input']['currInput']:
|
||||
if key in numpadKeys:
|
||||
# Return an empty/invalid shortcut that won't match any command
|
||||
return "[]"
|
||||
|
||||
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)):
|
||||
if self.env['input']['shortcutRepeat'] > 1 and not self.shortcutExists(str(shortcut)):
|
||||
shortcut = []
|
||||
self.env['input']['shortcutRepeat'] = 1
|
||||
shortcut.append(self.env['input']['shortcutRepeat'])
|
||||
shortcut.append(self.env['input']['currInput'])
|
||||
self.env['runtime']['debug'].writeDebugOut("currShortcut " + str(shortcut) ,debug.debugLevel.INFO)
|
||||
self.env['runtime']['debug'].writeDebugOut("currShortcut " + str(shortcut), debug.debugLevel.INFO)
|
||||
return str(shortcut)
|
||||
|
||||
def currKeyIsModifier(self):
|
||||
|
@ -4,5 +4,5 @@
|
||||
# Fenrir TTY screen reader
|
||||
# By Chrys, Storm Dragon, and contributers.
|
||||
|
||||
version = "2025.03.02"
|
||||
version = "2025.04.14"
|
||||
codeName = "master"
|
||||
|
Loading…
x
Reference in New Issue
Block a user