Files
fenrir/src/fenrirscreenreader/core/remoteManager.py

415 lines
16 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.
"""
Remote controll:
section<space>command<space>parameters
sections:command,setting
setting commands:
- set section#setting=value[;section#setting=value]
- reset
command commands:
- say text to speech
- interrupt
examples
settings:
settings set section#setting=value[,section#setting=value]
setting set speech#voice=de
setting reset
setting save /path/settings.conf
command:
command say this is a test
command interrupt
"""
import os
import time
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.eventData import FenrirEventType
from fenrirscreenreader.core.i18n import _
class RemoteManager:
def __init__(self):
# command controll
self.commandConst = "COMMAND "
self.sayConst = "SAY "
self.vmenuConst = "VMENU "
self.resetVmenuConst = "RESETVMENU"
self.interruptConst = "INTERRUPT"
self.quitAppConst = "QUITAPPLICATION"
self.tempDisableSpeechConst = "TEMPDISABLESPEECH"
self.defineWindowConst = "WINDOW "
self.resetWindowConst = "RESETWINDOW"
self.setClipboardConst = "CLIPBOARD "
self.exportClipboardConst = "EXPORTCLIPBOARD"
# setting controll
self.settingConst = "SETTING "
self.setSettingConst = "SET "
self.saveAsSettingConst = "SAVEAS "
self.saveSettingConst = "SAVE"
self.resetSettingConst = "RESET"
def initialize(self, environment):
self.env = environment
self.env["runtime"]["SettingsManager"].load_driver(
self.env["runtime"]["SettingsManager"].get_setting(
"remote", "driver"
),
"RemoteDriver",
)
def shutdown(self):
self.env["runtime"]["SettingsManager"].shutdown_driver("RemoteDriver")
def handle_settings_change_with_response(self, settings_text):
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
"remote", "enable_settings_remote"
):
return {
"success": False,
"message": "Settings remote control is disabled",
}
upper_settings_text = settings_text.upper()
try:
# set setting
if upper_settings_text.startswith(self.setSettingConst):
parameter_text = settings_text[len(self.setSettingConst) :]
self.set_settings(parameter_text)
return {
"success": True,
"message": f"Setting applied: {parameter_text}",
}
# save as setting
elif upper_settings_text.startswith(self.saveAsSettingConst):
parameter_text = settings_text[len(self.saveAsSettingConst) :]
self.save_settings(parameter_text)
return {
"success": True,
"message": f"Settings saved to: {parameter_text}",
}
# save setting
elif upper_settings_text == self.saveSettingConst:
self.save_settings()
return {"success": True, "message": "Settings saved"}
# reset setting
elif upper_settings_text == self.resetSettingConst:
self.reset_settings()
return {
"success": True,
"message": "Settings reset to defaults",
}
else:
return {
"success": False,
"message": f"Unknown settings command: {settings_text}",
}
except Exception as e:
return {"success": False, "message": f"Settings error: {str(e)}"}
def handle_settings_change(self, settings_text):
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
"remote", "enable_settings_remote"
):
return
upper_settings_text = settings_text.upper()
# set setting
if upper_settings_text.startswith(self.setSettingConst):
parameter_text = settings_text[len(self.setSettingConst) :]
self.set_settings(parameter_text)
# save as setting
elif upper_settings_text.startswith(self.saveAsSettingConst):
parameter_text = settings_text[len(self.saveAsSettingConst) :]
self.save_settings(parameter_text)
# save setting
elif upper_settings_text == self.saveSettingConst:
self.save_settings()
# reset setting
elif upper_settings_text == self.resetSettingConst:
self.reset_settings()
def handle_command_execution_with_response(self, command_text):
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
"remote", "enable_command_remote"
):
return {
"success": False,
"message": "Command remote control is disabled",
}
upper_command_text = command_text.upper()
try:
# say
if upper_command_text.startswith(self.sayConst):
parameter_text = command_text[len(self.sayConst) :]
self.say(parameter_text)
return {
"success": True,
"message": f"Speaking: {parameter_text[:50]}{'...' if len(parameter_text) > 50 else ''}",
}
# interrupt
elif upper_command_text == self.interruptConst:
self.interrupt_speech()
return {"success": True, "message": "Speech interrupted"}
# temp disable speech
elif upper_command_text == self.tempDisableSpeechConst:
self.temp_disable_speech()
return {
"success": True,
"message": "Speech temporarily disabled",
}
# set vmenu
elif upper_command_text.startswith(self.vmenuConst):
parameter_text = command_text[len(self.vmenuConst) :]
self.set_vmenu(parameter_text)
return {
"success": True,
"message": f"VMenu set to: {parameter_text}",
}
# reset vmenu
elif upper_command_text == self.resetVmenuConst:
self.reset_vmenu()
return {"success": True, "message": "VMenu reset"}
# quit fenrir
elif upper_command_text == self.quitAppConst:
self.quit_fenrir()
return {"success": True, "message": "Fenrir shutting down"}
# define window
elif upper_command_text.startswith(self.defineWindowConst):
parameter_text = command_text[len(self.defineWindowConst) :]
self.define_window(parameter_text)
return {
"success": True,
"message": f"Window defined: {parameter_text}",
}
# reset window
elif upper_command_text == self.resetWindowConst:
self.reset_window()
return {"success": True, "message": "Window reset"}
# set clipboard
elif upper_command_text.startswith(self.setClipboardConst):
parameter_text = command_text[len(self.setClipboardConst) :]
self.set_clipboard(parameter_text)
return {
"success": True,
"message": f"Clipboard set: {parameter_text[:50]}{'...' if len(parameter_text) > 50 else ''}",
}
elif upper_command_text.startswith(self.exportClipboardConst):
self.export_clipboard()
return {
"success": True,
"message": "Clipboard exported to file",
}
else:
return {
"success": False,
"message": f"Unknown command: {command_text}",
}
except Exception as e:
return {"success": False, "message": f"Command error: {str(e)}"}
def handle_command_execution(self, command_text):
if not self.env["runtime"]["SettingsManager"].get_setting_as_bool(
"remote", "enable_command_remote"
):
return
upper_command_text = command_text.upper()
# say
if upper_command_text.startswith(self.sayConst):
parameter_text = command_text[len(self.sayConst) :]
self.say(parameter_text)
# interrupt
elif upper_command_text == self.interruptConst:
self.interrupt_speech()
# temp disable speech
elif upper_command_text == self.tempDisableSpeechConst:
self.temp_disable_speech()
# set vmenu
elif upper_command_text.startswith(self.vmenuConst):
parameter_text = command_text[len(self.vmenuConst) :]
self.set_vmenu(parameter_text)
# reset vmenu
elif upper_command_text == self.resetVmenuConst:
self.reset_vmenu()
# quit fenrir
elif upper_command_text == self.quitAppConst:
self.quit_fenrir()
# define window
elif upper_command_text.startswith(self.defineWindowConst):
parameter_text = command_text[len(self.defineWindowConst) :]
self.define_window(parameter_text)
# reset window
elif upper_command_text == self.resetWindowConst:
self.reset_window()
# set clipboard
elif upper_command_text.startswith(self.setClipboardConst):
parameter_text = command_text[len(self.setClipboardConst) :]
self.set_clipboard(parameter_text)
elif upper_command_text.startswith(self.exportClipboardConst):
self.export_clipboard()
def temp_disable_speech(self):
self.env["runtime"]["OutputManager"].temp_disable_speech()
def set_vmenu(self, vmenu=""):
self.env["runtime"]["VmenuManager"].set_curr_menu(vmenu)
def reset_vmenu(self):
self.env["runtime"]["VmenuManager"].set_curr_menu()
def set_clipboard(self, text=""):
self.env["runtime"]["MemoryManager"].add_value_to_first_index(
"clipboardHistory", text
)
def quit_fenrir(self):
self.env["runtime"]["EventManager"].stop_main_event_loop()
def define_window(self, window_text):
start = {}
end = {}
try:
window_list = window_text.split(" ")
if len(window_list) < 4:
return
start["x"] = int(window_list[0])
start["y"] = int(window_list[1])
end["x"] = int(window_list[2])
end["y"] = int(window_list[3])
self.env["runtime"]["CursorManager"].set_window_for_application(
start, end
)
except Exception as e:
pass
def reset_window(self):
self.env["runtime"]["CursorManager"].clear_window_for_application()
def say(self, text):
if not text:
return
if text == "":
return
self.env["runtime"]["OutputManager"].speak_text(text)
def interrupt_speech(self):
self.env["runtime"]["OutputManager"].interrupt_output()
def export_clipboard(self):
clipboard_file_path = self.env["runtime"][
"SettingsManager"
].get_setting("general", "clipboard_export_path")
clipboard_file_path = clipboard_file_path.replace(
"$user", self.env["general"]["curr_user"]
)
clipboard_file_path = clipboard_file_path.replace(
"$USER", self.env["general"]["curr_user"]
)
clipboard_file_path = clipboard_file_path.replace(
"$User", self.env["general"]["curr_user"]
)
clipboard_file = open(clipboard_file_path, "w")
try:
if self.env["runtime"]["MemoryManager"].is_index_list_empty(
"clipboardHistory"
):
self.env["runtime"]["OutputManager"].present_text(
_("clipboard empty"), interrupt=True
)
return
clipboard = self.env["runtime"][
"MemoryManager"
].get_index_list_element("clipboardHistory")
# Fenrir will crash if the clipboard variable is type None
if clipboard is not None:
clipboard_file.write(clipboard)
else:
clipboard_file.write("")
clipboard_file.close()
os.chmod(clipboard_file_path, 0o644)
self.env["runtime"]["OutputManager"].present_text(
_("clipboard exported to file"), interrupt=True
)
except Exception as e:
self.env["runtime"]["DebugManager"].write_debug_out(
"export_clipboard_to_file:run: Filepath:"
+ clipboard_file
+ " trace:"
+ str(e),
debug.DebugLevel.ERROR,
)
def save_settings(self, setting_config_path=None):
if not setting_config_path:
setting_config_path = self.env["runtime"][
"SettingsManager"
].get_settings_file()
if setting_config_path == "":
return
self.env["runtime"]["SettingsManager"].save_settings(
setting_config_path
)
def reset_settings(self):
self.env["runtime"]["SettingsManager"].reset_setting_arg_dict()
def set_settings(self, settingsArgs):
self.env["runtime"]["SettingsManager"].parse_setting_args(settingsArgs)
self.env["runtime"]["ScreenManager"].update_screen_ignored()
self.env["runtime"]["InputManager"].handle_device_grab(force=True)
def handle_remote_incomming_with_response(self, event_data):
if not event_data:
return {"success": False, "message": "No data received"}
upper_event_data = event_data.upper()
self.env["runtime"]["DebugManager"].write_debug_out(
"RemoteManager:handle_remote_incomming_with_response: event: "
+ str(event_data),
debug.DebugLevel.INFO,
)
try:
if upper_event_data.startswith(self.settingConst):
settings_text = event_data[len(self.settingConst) :]
return self.handle_settings_change_with_response(settings_text)
elif upper_event_data.startswith(self.commandConst):
command_text = event_data[len(self.commandConst) :]
return self.handle_command_execution_with_response(
command_text
)
else:
return {
"success": False,
"message": "Unknown command format. Use 'COMMAND ...' or 'SETTING ...'",
}
except Exception as e:
return {"success": False, "message": f"Exception: {str(e)}"}
def handle_remote_incomming(self, event_data):
if not event_data:
return
upper_event_data = event_data.upper()
self.env["runtime"]["DebugManager"].write_debug_out(
"RemoteManager:handle_remote_incomming: event: " + str(event_data),
debug.DebugLevel.INFO,
)
if upper_event_data.startswith(self.settingConst):
settings_text = event_data[len(self.settingConst) :]
self.handle_settings_change(settings_text)
elif upper_event_data.startswith(self.commandConst):
command_text = event_data[len(self.commandConst) :]
self.handle_command_execution(command_text)