Separate menu entries for some settings, improves usability. Fixed device detection for devices that do not contain what they do in their name, e.g. numpads that are not listed as numpads. This hopefully fixes a bug with some external numpads.
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Fenrir TTY screen reader
|
||||
# By Chrys, Storm Dragon, and contributors.
|
||||
|
||||
import time
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
|
||||
class command:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def initialize(self, environment):
|
||||
self.env = environment
|
||||
|
||||
def shutdown(self):
|
||||
pass
|
||||
|
||||
def get_description(self):
|
||||
return _("Handles delayed retry for tab completion detection")
|
||||
|
||||
def run(self):
|
||||
"""Check for and process pending tab completions with slight delay"""
|
||||
# Only process if we have tab completion state
|
||||
if "tabCompletion" not in self.env["commandBuffer"]:
|
||||
return
|
||||
|
||||
tab_state = self.env["commandBuffer"]["tabCompletion"]
|
||||
pending = tab_state.get("pendingCompletion")
|
||||
|
||||
if not pending:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
# Process pending completion after 50ms delay
|
||||
if current_time - pending["timestamp"] < 0.05:
|
||||
return
|
||||
|
||||
# Check if screen delta is now available
|
||||
if not self.env["runtime"]["ScreenManager"].is_delta():
|
||||
# Give up after 200ms total
|
||||
if current_time - pending["timestamp"] > 0.2:
|
||||
tab_state["pendingCompletion"] = None
|
||||
tab_state["retryCount"] = 0
|
||||
return
|
||||
|
||||
# Process the delayed completion
|
||||
delta_text = self.env["screen"]["new_delta"]
|
||||
x_move = pending["x_move"]
|
||||
|
||||
# Use the same flexible matching logic as main tab completion
|
||||
match_found = self._is_flexible_completion_match(x_move, delta_text)
|
||||
|
||||
if not match_found:
|
||||
# Try pattern-based detection as final fallback
|
||||
match_found = self._detect_completion_patterns(delta_text)
|
||||
|
||||
if match_found and delta_text:
|
||||
# Mark that we've handled this delta to prevent duplicate announcements
|
||||
tab_state["lastProcessedDelta"] = delta_text
|
||||
tab_state["lastProcessedTime"] = current_time
|
||||
|
||||
# Filter and announce the completion
|
||||
curr_delta = delta_text
|
||||
if (len(curr_delta.strip()) != len(curr_delta) and
|
||||
curr_delta.strip() != ""):
|
||||
curr_delta = curr_delta.strip()
|
||||
|
||||
if curr_delta:
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
curr_delta, interrupt=True, announce_capital=True, flush=False
|
||||
)
|
||||
|
||||
# Clear pending completion
|
||||
tab_state["pendingCompletion"] = None
|
||||
tab_state["retryCount"] = 0
|
||||
|
||||
def _is_flexible_completion_match(self, x_move, delta_text):
|
||||
"""Use flexible matching (duplicated from main command for heartbeat use)"""
|
||||
if not delta_text:
|
||||
return False
|
||||
|
||||
delta_len = len(delta_text)
|
||||
|
||||
# Exact match
|
||||
if x_move == delta_len:
|
||||
return True
|
||||
|
||||
# Flexible range: allow ±2 characters difference
|
||||
if abs(x_move - delta_len) <= 2 and delta_len > 0:
|
||||
return True
|
||||
|
||||
# For longer completions, allow proportional variance
|
||||
if delta_len > 10 and abs(x_move - delta_len) <= (delta_len * 0.2):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _detect_completion_patterns(self, delta_text):
|
||||
"""Detect common tab completion patterns (duplicated from main command)"""
|
||||
if not delta_text:
|
||||
return False
|
||||
|
||||
delta_stripped = delta_text.strip()
|
||||
|
||||
# File extension completion
|
||||
if '.' in delta_stripped and delta_stripped.count('.') <= 2:
|
||||
return True
|
||||
|
||||
# Path completion
|
||||
if '/' in delta_stripped or '\\' in delta_stripped:
|
||||
return True
|
||||
|
||||
# Command parameter completion
|
||||
if delta_stripped.startswith('-') and len(delta_stripped) > 1:
|
||||
return True
|
||||
|
||||
# Word boundary completion
|
||||
if delta_stripped.isalnum() and len(delta_stripped) >= 2:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def set_callback(self, callback):
|
||||
pass
|
@@ -147,3 +147,18 @@ class config_command:
|
||||
except Exception as e:
|
||||
self.present_text(f"Failed to create basic defaults: {str(e)}")
|
||||
return False
|
||||
|
||||
def get_setting(self, section, setting, default=None):
|
||||
"""Get setting value from settings manager"""
|
||||
try:
|
||||
return self.env["runtime"]["SettingsManager"].get_setting(section, setting)
|
||||
except Exception:
|
||||
return default
|
||||
|
||||
def set_setting(self, section, setting, value):
|
||||
"""Set setting value via settings manager"""
|
||||
try:
|
||||
self.env["runtime"]["SettingsManager"].set_setting(section, setting, value)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set punctuation to All (every punctuation mark)"
|
||||
|
||||
def run(self):
|
||||
current_level = self.get_setting("general", "punctuationLevel", "some")
|
||||
|
||||
if current_level.lower() == "all":
|
||||
self.present_text("Punctuation level already set to All")
|
||||
return
|
||||
|
||||
success = self.set_setting("general", "punctuationLevel", "all")
|
||||
|
||||
if success:
|
||||
self.present_text("Punctuation level set to All - every punctuation mark will be spoken")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change punctuation level")
|
||||
self.play_sound("Error")
|
@@ -1,54 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set punctuation verbosity level"
|
||||
|
||||
def run(self):
|
||||
current_level = self.get_setting("general", "punctuationLevel", "some")
|
||||
|
||||
# Present current level
|
||||
level_descriptions = {
|
||||
"none": "None - no punctuation spoken",
|
||||
"some": "Some - basic punctuation only",
|
||||
"most": "Most - detailed punctuation",
|
||||
"all": "All - every punctuation mark",
|
||||
}
|
||||
|
||||
current_description = level_descriptions.get(current_level, "Unknown")
|
||||
self.present_text(f"Current punctuation level: {current_description}")
|
||||
|
||||
# Cycle through the four levels
|
||||
levels = ["none", "some", "most", "all"]
|
||||
try:
|
||||
current_index = levels.index(current_level)
|
||||
next_index = (current_index + 1) % len(levels)
|
||||
new_level = levels[next_index]
|
||||
except ValueError:
|
||||
new_level = "some" # Default to some
|
||||
|
||||
success = self.set_setting("general", "punctuationLevel", new_level)
|
||||
|
||||
if success:
|
||||
new_description = level_descriptions[new_level]
|
||||
self.present_text(f"Punctuation level set to: {new_description}")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change punctuation level")
|
||||
self.play_sound("Error")
|
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set punctuation to Most (detailed punctuation)"
|
||||
|
||||
def run(self):
|
||||
current_level = self.get_setting("general", "punctuationLevel", "some")
|
||||
|
||||
if current_level.lower() == "most":
|
||||
self.present_text("Punctuation level already set to Most")
|
||||
return
|
||||
|
||||
success = self.set_setting("general", "punctuationLevel", "most")
|
||||
|
||||
if success:
|
||||
self.present_text("Punctuation level set to Most - detailed punctuation will be spoken")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change punctuation level")
|
||||
self.play_sound("Error")
|
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set punctuation to None (no punctuation spoken)"
|
||||
|
||||
def run(self):
|
||||
current_level = self.get_setting("general", "punctuationLevel", "some")
|
||||
|
||||
if current_level.lower() == "none":
|
||||
self.present_text("Punctuation level already set to None")
|
||||
return
|
||||
|
||||
success = self.set_setting("general", "punctuationLevel", "none")
|
||||
|
||||
if success:
|
||||
self.present_text("Punctuation level set to None - no punctuation will be spoken")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change punctuation level")
|
||||
self.play_sound("Error")
|
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set punctuation to Some (basic punctuation only)"
|
||||
|
||||
def run(self):
|
||||
current_level = self.get_setting("general", "punctuationLevel", "some")
|
||||
|
||||
if current_level.lower() == "some":
|
||||
self.present_text("Punctuation level already set to Some")
|
||||
return
|
||||
|
||||
success = self.set_setting("general", "punctuationLevel", "some")
|
||||
|
||||
if success:
|
||||
self.present_text("Punctuation level set to Some - basic punctuation will be spoken")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change punctuation level")
|
||||
self.play_sound("Error")
|
@@ -1,85 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Select keyboard layout (desktop or laptop)"
|
||||
|
||||
def run(self):
|
||||
current_layout = self.get_setting(
|
||||
"keyboard", "keyboardLayout", "desktop"
|
||||
)
|
||||
|
||||
# Present current layout
|
||||
self.present_text(f"Current keyboard layout: {current_layout}")
|
||||
|
||||
# Find available keyboard layouts
|
||||
keyboard_path = "/etc/fenrirscreenreader/keyboard"
|
||||
if not os.path.isdir(keyboard_path):
|
||||
# Development path
|
||||
keyboard_path = os.path.join(
|
||||
os.path.dirname(self.settings_file), "..", "keyboard"
|
||||
)
|
||||
|
||||
available_layouts = self.get_available_layouts(keyboard_path)
|
||||
|
||||
if len(available_layouts) > 1:
|
||||
# Cycle through available layouts
|
||||
try:
|
||||
current_index = available_layouts.index(current_layout)
|
||||
next_index = (current_index + 1) % len(available_layouts)
|
||||
new_layout = available_layouts[next_index]
|
||||
except ValueError:
|
||||
# Current layout not found, use first available
|
||||
new_layout = available_layouts[0]
|
||||
|
||||
success = self.set_setting(
|
||||
"keyboard", "keyboardLayout", new_layout
|
||||
)
|
||||
|
||||
if success:
|
||||
self.present_text(f"Keyboard layout changed to: {new_layout}")
|
||||
self.present_text(
|
||||
"Please restart Fenrir for this change to take effect."
|
||||
)
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change keyboard layout")
|
||||
self.play_sound("Error")
|
||||
else:
|
||||
self.present_text("Only default keyboard layout is available")
|
||||
self.play_sound("Cancel")
|
||||
|
||||
def get_available_layouts(self, keyboard_path):
|
||||
"""Find available keyboard layout files"""
|
||||
layouts = []
|
||||
|
||||
if os.path.isdir(keyboard_path):
|
||||
try:
|
||||
for file in os.listdir(keyboard_path):
|
||||
if file.endswith(".conf") and not file.startswith("."):
|
||||
layout_name = file[:-5] # Remove .conf extension
|
||||
layouts.append(layout_name)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Ensure we have at least the default layouts
|
||||
if not layouts:
|
||||
layouts = ["desktop", "laptop"]
|
||||
|
||||
return sorted(layouts)
|
@@ -1,55 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set character echo mode"
|
||||
|
||||
def run(self):
|
||||
current_mode = self.get_setting("keyboard", "charEchoMode", "1")
|
||||
|
||||
# Present current mode
|
||||
mode_descriptions = {
|
||||
"0": "None - no character echo",
|
||||
"1": "Always - echo all typed characters",
|
||||
"2": "Caps Lock - echo only when caps lock is on",
|
||||
}
|
||||
|
||||
current_description = mode_descriptions.get(current_mode, "Unknown")
|
||||
self.present_text(
|
||||
f"Current character echo mode: {current_description}"
|
||||
)
|
||||
|
||||
# Cycle through the three modes
|
||||
modes = ["0", "1", "2"]
|
||||
try:
|
||||
current_index = modes.index(current_mode)
|
||||
next_index = (current_index + 1) % len(modes)
|
||||
new_mode = modes[next_index]
|
||||
except ValueError:
|
||||
new_mode = "1" # Default to always
|
||||
|
||||
success = self.set_setting("keyboard", "charEchoMode", new_mode)
|
||||
|
||||
if success:
|
||||
new_description = mode_descriptions[new_mode]
|
||||
self.present_text(f"Character echo mode set to: {new_description}")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change character echo mode")
|
||||
self.play_sound("Error")
|
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set character echo to Always (echo all typed characters)"
|
||||
|
||||
def run(self):
|
||||
current_mode = self.get_setting("keyboard", "charEchoMode", "1")
|
||||
|
||||
if current_mode == "1":
|
||||
self.present_text("Character echo already set to Always")
|
||||
return
|
||||
|
||||
success = self.set_setting("keyboard", "charEchoMode", "1")
|
||||
|
||||
if success:
|
||||
self.present_text("Character echo set to Always - all typed characters will be spoken")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change character echo mode")
|
||||
self.play_sound("Error")
|
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set character echo to Caps Lock (echo only when caps lock is on)"
|
||||
|
||||
def run(self):
|
||||
current_mode = self.get_setting("keyboard", "charEchoMode", "1")
|
||||
|
||||
if current_mode == "2":
|
||||
self.present_text("Character echo already set to Caps Lock mode")
|
||||
return
|
||||
|
||||
success = self.set_setting("keyboard", "charEchoMode", "2")
|
||||
|
||||
if success:
|
||||
self.present_text("Character echo set to Caps Lock mode - characters will be spoken only when caps lock is on")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change character echo mode")
|
||||
self.play_sound("Error")
|
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set character echo to None (no character echo)"
|
||||
|
||||
def run(self):
|
||||
current_mode = self.get_setting("keyboard", "charEchoMode", "1")
|
||||
|
||||
if current_mode == "0":
|
||||
self.present_text("Character echo already set to None")
|
||||
return
|
||||
|
||||
success = self.set_setting("keyboard", "charEchoMode", "0")
|
||||
|
||||
if success:
|
||||
self.present_text("Character echo set to None - no typed characters will be spoken")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change character echo mode")
|
||||
self.play_sound("Error")
|
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set keyboard layout to Desktop"
|
||||
|
||||
def run(self):
|
||||
current_layout = self.get_setting("keyboard", "keyboardLayout", "desktop")
|
||||
|
||||
if current_layout.lower() == "desktop":
|
||||
self.present_text("Keyboard layout already set to Desktop")
|
||||
return
|
||||
|
||||
success = self.set_setting("keyboard", "keyboardLayout", "desktop")
|
||||
|
||||
if success:
|
||||
self.present_text("Keyboard layout set to Desktop")
|
||||
self.present_text("Please restart Fenrir for this change to take effect")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change keyboard layout")
|
||||
self.play_sound("Error")
|
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set keyboard layout to Laptop"
|
||||
|
||||
def run(self):
|
||||
current_layout = self.get_setting("keyboard", "keyboardLayout", "desktop")
|
||||
|
||||
if current_layout.lower() == "laptop":
|
||||
self.present_text("Keyboard layout already set to Laptop")
|
||||
return
|
||||
|
||||
success = self.set_setting("keyboard", "keyboardLayout", "laptop")
|
||||
|
||||
if success:
|
||||
self.present_text("Keyboard layout set to Laptop")
|
||||
self.present_text("Please restart Fenrir for this change to take effect")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change keyboard layout")
|
||||
self.play_sound("Error")
|
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set keyboard layout to PTY (terminal emulation)"
|
||||
|
||||
def run(self):
|
||||
current_layout = self.get_setting("keyboard", "keyboardLayout", "desktop")
|
||||
|
||||
if current_layout.lower() == "pty":
|
||||
self.present_text("Keyboard layout already set to PTY")
|
||||
return
|
||||
|
||||
success = self.set_setting("keyboard", "keyboardLayout", "pty")
|
||||
|
||||
if success:
|
||||
self.present_text("Keyboard layout set to PTY for terminal emulation")
|
||||
self.present_text("Please restart Fenrir for this change to take effect")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change keyboard layout")
|
||||
self.play_sound("Error")
|
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set keyboard layout to PTY2 (alternative terminal layout)"
|
||||
|
||||
def run(self):
|
||||
current_layout = self.get_setting("keyboard", "keyboardLayout", "desktop")
|
||||
|
||||
if current_layout.lower() == "pty2":
|
||||
self.present_text("Keyboard layout already set to PTY2")
|
||||
return
|
||||
|
||||
success = self.set_setting("keyboard", "keyboardLayout", "pty2")
|
||||
|
||||
if success:
|
||||
self.present_text("Keyboard layout set to PTY2 alternative terminal layout")
|
||||
self.present_text("Please restart Fenrir for this change to take effect")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change keyboard layout")
|
||||
self.play_sound("Error")
|
@@ -1,51 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set screen text encoding"
|
||||
|
||||
def run(self):
|
||||
current_encoding = self.get_setting("screen", "encoding", "auto")
|
||||
|
||||
# Present current encoding
|
||||
self.present_text(f"Current screen encoding: {current_encoding}")
|
||||
|
||||
# Cycle through available encodings
|
||||
encodings = ["auto", "utf-8", "cp1252", "iso-8859-1"]
|
||||
try:
|
||||
current_index = encodings.index(current_encoding)
|
||||
next_index = (current_index + 1) % len(encodings)
|
||||
new_encoding = encodings[next_index]
|
||||
except ValueError:
|
||||
new_encoding = "auto" # Default to auto
|
||||
|
||||
success = self.set_setting("screen", "encoding", new_encoding)
|
||||
|
||||
if success:
|
||||
self.present_text(f"Screen encoding set to: {new_encoding}")
|
||||
if new_encoding == "auto":
|
||||
self.present_text(
|
||||
"Fenrir will automatically detect text encoding"
|
||||
)
|
||||
else:
|
||||
self.present_text(f"Fenrir will use {new_encoding} encoding")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change screen encoding")
|
||||
self.play_sound("Error")
|
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set screen encoding to Auto (automatic detection)"
|
||||
|
||||
def run(self):
|
||||
current_encoding = self.get_setting("screen", "encoding", "auto")
|
||||
|
||||
if current_encoding.lower() == "auto":
|
||||
self.present_text("Screen encoding already set to Auto")
|
||||
return
|
||||
|
||||
success = self.set_setting("screen", "encoding", "auto")
|
||||
|
||||
if success:
|
||||
self.present_text("Screen encoding set to Auto - Fenrir will automatically detect text encoding")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change screen encoding")
|
||||
self.play_sound("Error")
|
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set screen encoding to CP1252 (Windows Western European)"
|
||||
|
||||
def run(self):
|
||||
current_encoding = self.get_setting("screen", "encoding", "auto")
|
||||
|
||||
if current_encoding.lower() == "cp1252":
|
||||
self.present_text("Screen encoding already set to CP1252")
|
||||
return
|
||||
|
||||
success = self.set_setting("screen", "encoding", "cp1252")
|
||||
|
||||
if success:
|
||||
self.present_text("Screen encoding set to CP1252 - Windows Western European encoding")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change screen encoding")
|
||||
self.play_sound("Error")
|
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set screen encoding to ISO-8859-1 (Latin-1)"
|
||||
|
||||
def run(self):
|
||||
current_encoding = self.get_setting("screen", "encoding", "auto")
|
||||
|
||||
if current_encoding.lower() == "iso-8859-1":
|
||||
self.present_text("Screen encoding already set to ISO-8859-1")
|
||||
return
|
||||
|
||||
success = self.set_setting("screen", "encoding", "iso-8859-1")
|
||||
|
||||
if success:
|
||||
self.present_text("Screen encoding set to ISO-8859-1 - Latin-1 encoding")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change screen encoding")
|
||||
self.play_sound("Error")
|
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from fenrirscreenreader.core.i18n import _
|
||||
|
||||
# Load base configuration class
|
||||
_base_path = os.path.join(os.path.dirname(__file__), "..", "config_base.py")
|
||||
_spec = importlib.util.spec_from_file_location("config_base", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
config_command = _module.config_command
|
||||
|
||||
|
||||
class command(config_command):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_description(self):
|
||||
return "Set screen encoding to UTF-8 (Unicode)"
|
||||
|
||||
def run(self):
|
||||
current_encoding = self.get_setting("screen", "encoding", "auto")
|
||||
|
||||
if current_encoding.lower() == "utf-8":
|
||||
self.present_text("Screen encoding already set to UTF-8")
|
||||
return
|
||||
|
||||
success = self.set_setting("screen", "encoding", "utf-8")
|
||||
|
||||
if success:
|
||||
self.present_text("Screen encoding set to UTF-8 - Unicode text encoding")
|
||||
self.play_sound("Accept")
|
||||
else:
|
||||
self.present_text("Failed to change screen encoding")
|
||||
self.play_sound("Error")
|
@@ -4,5 +4,5 @@
|
||||
# Fenrir TTY screen reader
|
||||
# By Chrys, Storm Dragon, and contributors.
|
||||
|
||||
version = "2025.08.31"
|
||||
version = "2025.09.12"
|
||||
code_name = "testing"
|
||||
|
@@ -438,11 +438,25 @@ class driver(inputDriver):
|
||||
debug.DebugLevel.INFO,
|
||||
)
|
||||
continue
|
||||
if len(cap[event_type.EV_KEY]) < 60:
|
||||
# Check if device has numpad keys - use lower threshold for dedicated numpads
|
||||
numpad_keys = [
|
||||
evdev.ecodes.KEY_KP0, evdev.ecodes.KEY_KP1, evdev.ecodes.KEY_KP2,
|
||||
evdev.ecodes.KEY_KP3, evdev.ecodes.KEY_KP4, evdev.ecodes.KEY_KP5,
|
||||
evdev.ecodes.KEY_KP6, evdev.ecodes.KEY_KP7, evdev.ecodes.KEY_KP8,
|
||||
evdev.ecodes.KEY_KP9, evdev.ecodes.KEY_KPPLUS, evdev.ecodes.KEY_KPMINUS,
|
||||
evdev.ecodes.KEY_KPASTERISK, evdev.ecodes.KEY_KPSLASH, evdev.ecodes.KEY_KPENTER,
|
||||
evdev.ecodes.KEY_KPDOT
|
||||
]
|
||||
|
||||
has_numpad_keys = any(key in cap[event_type.EV_KEY] for key in numpad_keys)
|
||||
min_key_threshold = 10 if has_numpad_keys else 60
|
||||
|
||||
if len(cap[event_type.EV_KEY]) < min_key_threshold:
|
||||
threshold_type = "numpad" if has_numpad_keys else "keyboard"
|
||||
self.env["runtime"][
|
||||
"DebugManager"
|
||||
].write_debug_out(
|
||||
"Device Skipped (< 60 keys):"
|
||||
f"Device Skipped (< {min_key_threshold} keys for {threshold_type}):"
|
||||
+ curr_device.name,
|
||||
debug.DebugLevel.INFO,
|
||||
)
|
||||
|
Reference in New Issue
Block a user