From 7f327b4ccedf9f9c4d580405fd17085a7ce710be Mon Sep 17 00:00:00 2001 From: onyx-and-iris Date: Fri, 20 Mar 2026 02:33:12 +0000 Subject: [PATCH] add braille support --- src/nvda_voicemeeter/nvda.py | 4 ++ src/nvda_voicemeeter/popup.py | 82 ++++++++++++------------- src/nvda_voicemeeter/window.py | 106 ++++++++++++++++++--------------- 3 files changed, 104 insertions(+), 88 deletions(-) diff --git a/src/nvda_voicemeeter/nvda.py b/src/nvda_voicemeeter/nvda.py index 176a845..d37cf33 100644 --- a/src/nvda_voicemeeter/nvda.py +++ b/src/nvda_voicemeeter/nvda.py @@ -50,3 +50,7 @@ class Nvda: def braille_message(self, text: str) -> None: self._bindings.braille_message(text) + + def speak_and_braille(self, text: str) -> None: + self.speak(text) + self.braille_message(text) diff --git a/src/nvda_voicemeeter/popup.py b/src/nvda_voicemeeter/popup.py index f228d2b..c80ef66 100644 --- a/src/nvda_voicemeeter/popup.py +++ b/src/nvda_voicemeeter/popup.py @@ -40,7 +40,7 @@ class Popup: if values['Browse']: filepath = values['Browse'] break - self.window.nvda.speak(button) + self.window.nvda.speak_and_braille(button) case [_, ['KEY', 'ENTER']]: popup.find_element_with_focus().click() self.logger.debug(f'parsed::{parsed_cmd}') @@ -107,7 +107,7 @@ class Popup: break match parsed_cmd := self.window.parser.match.parse_string(event): case [[button], ['FOCUS', 'IN']]: - self.window.nvda.speak(button) + self.window.nvda.speak_and_braille(button) case [_, ['KEY', 'ENTER']]: popup.find_element_with_focus().click() case ['Ok']: @@ -233,21 +233,21 @@ class Popup: val = values[f'ASIO INPUT SPINBOX||{in_num} {channel}'] self.window.vm.patch.asio[index].set(val) channel = ('left', 'right')[int(channel)] - self.window.nvda.speak(str(val)) + self.window.nvda.speak_and_braille(str(val)) case [['ASIO', 'INPUT', 'SPINBOX'], [in_num, channel], ['FOCUS', 'IN']]: if self.popup.find_element_with_focus() is not None: val = values[f'ASIO INPUT SPINBOX||{in_num} {channel}'] channel = ('left', 'right')[int(channel)] num = int(in_num[-1]) - self.window.nvda.speak(f'Patch ASIO inputs to strips IN#{num} {channel} {val}') + self.window.nvda.speak_and_braille(f'Patch ASIO inputs to strips IN#{num} {channel} {val}') case [['ASIO', 'OUTPUT', param, 'SPINBOX'], [index]]: target = getattr(self.window.vm.patch, param)[int(index)] target.set(values[event]) - self.window.nvda.speak(str(values[event])) + self.window.nvda.speak_and_braille(str(values[event])) case [['ASIO', 'OUTPUT', param, 'SPINBOX'], [index], ['FOCUS', 'IN']]: if self.popup.find_element_with_focus() is not None: val = values[f'ASIO OUTPUT {param} SPINBOX||{index}'] - self.window.nvda.speak( + self.window.nvda.speak_and_braille( f'Patch BUS to A1 ASIO Outputs OUT {param} channel {int(index) + 1} {val}' ) case ['BUFFER MME' | 'BUFFER WDM' | 'BUFFER KS' | 'BUFFER ASIO']: @@ -263,15 +263,15 @@ class Popup: driver = event.split()[1] self.window.vm.set(f'option.buffer.{driver.lower()}', val) self.window.TKroot.after( - 200, self.window.nvda.speak, f'{driver} BUFFER {val if val else "default"}' + 200, self.window.nvda.speak_and_braille, f'{driver} BUFFER {val if val else "default"}' ) case [['BUFFER', driver], ['FOCUS', 'IN']]: val = int(self.window.vm.get(f'option.buffer.{driver.lower()}')) - self.window.nvda.speak(f'{driver} BUFFER {val if val else "default"}') + self.window.nvda.speak_and_braille(f'{driver} BUFFER {val if val else "default"}') case [['BUFFER', driver], ['KEY', 'SPACE' | 'ENTER']]: util.open_context_menu_for_buttonmenu(self.popup, f'BUFFER {driver}') case [[button], ['FOCUS', 'IN']]: - self.window.nvda.speak(button) + self.window.nvda.speak_and_braille(button) case [_, ['KEY', 'ENTER']]: self.popup.find_element_with_focus().click() self.logger.debug(f'parsed::{parsed_cmd}') @@ -337,7 +337,7 @@ class Popup: case [['COMPRESSOR'], ['SLIDER', param]]: setattr(self.window.vm.strip[index].comp, param.lower(), values[event]) case [['COMPRESSOR'], ['SLIDER', param], ['FOCUS', 'IN']]: - self.window.nvda.speak(f'{param} {values[f"COMPRESSOR||SLIDER {param}"]}') + self.window.nvda.speak_and_braille(f'{param} {values[f"COMPRESSOR||SLIDER {param}"]}') case [ ['COMPRESSOR'], ['SLIDER', param], @@ -364,9 +364,9 @@ class Popup: setattr(self.window.vm.strip[index].comp, param.lower(), val) self.popup[f'COMPRESSOR||SLIDER {param}'].update(value=val) if param == 'KNEE': - self.window.nvda.speak(str(round(val, 2))) + self.window.nvda.speak_and_braille(str(round(val, 2))) else: - self.window.nvda.speak(str(round(val, 1))) + self.window.nvda.speak_and_braille(str(round(val, 1))) else: self.window.vm.event.pdirty = True case [ @@ -399,9 +399,9 @@ class Popup: setattr(self.window.vm.strip[index].comp, param.lower(), val) self.popup[f'COMPRESSOR||SLIDER {param}'].update(value=val) if param == 'KNEE': - self.window.nvda.speak(str(round(val, 2))) + self.window.nvda.speak_and_braille(str(round(val, 2))) else: - self.window.nvda.speak(str(round(val, 1))) + self.window.nvda.speak_and_braille(str(round(val, 1))) else: self.window.vm.event.pdirty = True case [ @@ -430,9 +430,9 @@ class Popup: setattr(self.window.vm.strip[index].comp, param.lower(), val) self.popup[f'COMPRESSOR||SLIDER {param}'].update(value=val) if param == 'KNEE': - self.window.nvda.speak(str(round(val, 2))) + self.window.nvda.speak_and_braille(str(round(val, 2))) else: - self.window.nvda.speak(str(round(val, 1))) + self.window.nvda.speak_and_braille(str(round(val, 1))) else: self.window.vm.event.pdirty = True case [ @@ -453,7 +453,7 @@ class Popup: val = util.check_bounds(val, (0, 5000)) self.window.vm.strip[index].comp.release = val self.popup[f'COMPRESSOR||SLIDER {param}'].update(value=val) - self.window.nvda.speak(str(round(val, 1))) + self.window.nvda.speak_and_braille(str(round(val, 1))) else: self.window.vm.event.pdirty = True case [ @@ -474,7 +474,7 @@ class Popup: val = util.check_bounds(val, (0, 5000)) self.window.vm.strip[index].comp.release = val self.popup[f'COMPRESSOR||SLIDER {param}'].update(value=val) - self.window.nvda.speak(str(round(val, 1))) + self.window.nvda.speak_and_braille(str(round(val, 1))) else: self.window.vm.event.pdirty = True @@ -485,7 +485,7 @@ class Popup: self.window.vm.strip[index].comp.gainout = values[event] case [['COMPRESSOR'], ['SLIDER', 'INPUT' | 'OUTPUT' as direction, 'GAIN'], ['FOCUS', 'IN']]: label = f'{direction} GAIN' - self.window.nvda.speak(f'{label} {values[f"COMPRESSOR||SLIDER {label}"]}') + self.window.nvda.speak_and_braille(f'{label} {values[f"COMPRESSOR||SLIDER {label}"]}') case [ ['COMPRESSOR'], ['SLIDER', 'INPUT' | 'OUTPUT' as direction, 'GAIN'], @@ -510,7 +510,7 @@ class Popup: else: self.window.vm.strip[index].comp.gainout = val self.popup[f'COMPRESSOR||SLIDER {direction} GAIN'].update(value=val) - self.window.nvda.speak(str(round(val, 1))) + self.window.nvda.speak_and_braille(str(round(val, 1))) else: self.window.vm.event.pdirty = True case [ @@ -537,7 +537,7 @@ class Popup: else: self.window.vm.strip[index].comp.gainout = val self.popup[f'COMPRESSOR||SLIDER {direction} GAIN'].update(value=val) - self.window.nvda.speak(str(round(val, 1))) + self.window.nvda.speak_and_braille(str(round(val, 1))) else: self.window.vm.event.pdirty = True case [ @@ -564,7 +564,7 @@ class Popup: else: self.window.vm.strip[index].comp.gainout = val self.popup[f'COMPRESSOR||SLIDER {direction} GAIN'].update(value=val) - self.window.nvda.speak(str(round(val, 1))) + self.window.nvda.speak_and_braille(str(round(val, 1))) else: self.window.vm.event.pdirty = True @@ -578,7 +578,7 @@ class Popup: else: self.window.vm.strip[index].comp.gainout = 0 self.popup[f'COMPRESSOR||SLIDER {direction} GAIN'].update(value=0) - self.window.nvda.speak(str(0)) + self.window.nvda.speak_and_braille(str(0)) case [['COMPRESSOR'], ['SLIDER', param], ['KEY', 'CTRL', 'SHIFT', 'R']]: match param: case 'RATIO': @@ -593,19 +593,19 @@ class Popup: val = 0.5 setattr(self.window.vm.strip[index].comp, param.lower(), val) self.popup[f'COMPRESSOR||SLIDER {param}'].update(value=val) - self.window.nvda.speak(str(round(val, 1))) + self.window.nvda.speak_and_braille(str(round(val, 1))) case ['MAKEUP']: val = not self.window.vm.strip[index].comp.makeup self.window.vm.strip[index].comp.makeup = val - self.window.nvda.speak('on' if val else 'off') + self.window.nvda.speak_and_braille('on' if val else 'off') case [[button], ['FOCUS', 'IN']]: if button == 'MAKEUP': - self.window.nvda.speak( + self.window.nvda.speak_and_braille( f'{button} {"on" if self.window.vm.strip[index].comp.makeup else "off"}' ) else: - self.window.nvda.speak(button) + self.window.nvda.speak_and_braille(button) case [_, ['KEY', 'ENTER']]: self.popup.find_element_with_focus().click() self.logger.debug(f'parsed::{parsed_cmd}') @@ -673,7 +673,9 @@ class Popup: 'DAMPING': 'Damping Max', 'BPSIDECHAIN': 'BP Sidechain', } - self.window.nvda.speak(f'{label_map.get(param, param)} {values[f"GATE||SLIDER {param}"]}') + self.window.nvda.speak_and_braille( + f'{label_map.get(param, param)} {values[f"GATE||SLIDER {param}"]}' + ) case [ ['GATE'], @@ -695,9 +697,9 @@ class Popup: setattr(self.window.vm.strip[index].gate, param.lower(), val) self.popup[f'GATE||SLIDER {param}'].update(value=val) if param == 'BPSIDECHAIN': - self.window.nvda.speak(str(int(val))) + self.window.nvda.speak_and_braille(str(int(val))) else: - self.window.nvda.speak(str(round(val, 1))) + self.window.nvda.speak_and_braille(str(round(val, 1))) else: self.window.vm.event.pdirty = True case [ @@ -720,9 +722,9 @@ class Popup: setattr(self.window.vm.strip[index].gate, param.lower(), val) self.popup[f'GATE||SLIDER {param}'].update(value=val) if param == 'BPSIDECHAIN': - self.window.nvda.speak(str(int(val))) + self.window.nvda.speak_and_braille(str(int(val))) else: - self.window.nvda.speak(str(round(val, 1))) + self.window.nvda.speak_and_braille(str(round(val, 1))) else: self.window.vm.event.pdirty = True case [ @@ -745,9 +747,9 @@ class Popup: setattr(self.window.vm.strip[index].gate, param.lower(), val) self.popup[f'GATE||SLIDER {param}'].update(value=val) if param == 'BPSIDECHAIN': - self.window.nvda.speak(str(int(val))) + self.window.nvda.speak_and_braille(str(int(val))) else: - self.window.nvda.speak(str(round(val, 1))) + self.window.nvda.speak_and_braille(str(round(val, 1))) else: self.window.vm.event.pdirty = True case [ @@ -769,9 +771,9 @@ class Popup: setattr(self.window.vm.strip[index].gate, param.lower(), val) self.popup[f'GATE||SLIDER {param}'].update(value=val) if param == 'BPSIDECHAIN': - self.window.nvda.speak(str(int(val))) + self.window.nvda.speak_and_braille(str(int(val))) else: - self.window.nvda.speak(str(round(val, 1))) + self.window.nvda.speak_and_braille(str(round(val, 1))) else: self.window.vm.event.pdirty = True case [ @@ -793,9 +795,9 @@ class Popup: setattr(self.window.vm.strip[index].gate, param.lower(), val) self.popup[f'GATE||SLIDER {param}'].update(value=val) if param == 'BPSIDECHAIN': - self.window.nvda.speak(str(int(val))) + self.window.nvda.speak_and_braille(str(int(val))) else: - self.window.nvda.speak(str(round(val, 1))) + self.window.nvda.speak_and_braille(str(round(val, 1))) else: self.window.vm.event.pdirty = True case [['GATE'], ['SLIDER', param], ['KEY', 'CTRL', 'SHIFT', 'R']]: @@ -814,10 +816,10 @@ class Popup: val = 1000 setattr(self.window.vm.strip[index].gate, param.lower(), val) self.popup[f'GATE||SLIDER {param}'].update(value=val) - self.window.nvda.speak(str(round(val, 1))) + self.window.nvda.speak_and_braille(str(round(val, 1))) case [[button], ['FOCUS', 'IN']]: - self.window.nvda.speak(button) + self.window.nvda.speak_and_braille(button) case [_, ['KEY', 'ENTER']]: self.popup.find_element_with_focus().click() diff --git a/src/nvda_voicemeeter/window.py b/src/nvda_voicemeeter/window.py index a86e2a8..89cad0a 100644 --- a/src/nvda_voicemeeter/window.py +++ b/src/nvda_voicemeeter/window.py @@ -78,7 +78,7 @@ class NVDAVMWindow(psg.Window): self.logger.debug(f'config {defaultconfig} loaded') self.TKroot.after( 200, - self.nvda.speak, + self.nvda.speak_and_braille, f'config {defaultconfig.stem} has been loaded', ) except json.JSONDecodeError: @@ -306,12 +306,12 @@ class NVDAVMWindow(psg.Window): break elif event in util.get_slider_modes(): mode = event - self.nvda.speak(f'{mode} enabled') + self.nvda.speak_and_braille(f'{mode} enabled') self.logger.debug(f'entered slider mode {mode}') continue elif event == 'ESCAPE': if mode: - self.nvda.speak(f'{mode} disabled') + self.nvda.speak_and_braille(f'{mode} disabled') self.logger.debug(f'exited from slider mode {mode}') mode = None continue @@ -331,7 +331,7 @@ class NVDAVMWindow(psg.Window): # Focus tabgroup case ['CTRL-TAB'] | ['CTRL-SHIFT-TAB']: self['tabgroup'].set_focus() - self.nvda.speak(f'{values["tabgroup"]}') + self.nvda.speak_and_braille(f'{values["tabgroup"]}') # Quick Navigation case ['CTRL-1' | 'CTRL-2' | 'CTRL-3' | 'CTRL-4' | 'CTRL-5' | 'CTRL-6' | 'CTRL-7' | 'CTRL-8' as bind]: @@ -475,7 +475,7 @@ class NVDAVMWindow(psg.Window): case [['ENGINE', 'RESTART'], ['END']]: self.TKroot.after( 200, - self.nvda.speak, + self.nvda.speak_and_braille, 'Audio Engine restarted', ) case [['Save', 'Settings'], ['MENU']]: @@ -487,7 +487,7 @@ class NVDAVMWindow(psg.Window): self.logger.debug(f'saving config file to {filepath}') self.TKroot.after( 200, - self.nvda.speak, + self.nvda.speak_and_braille, f'config file {filepath.stem} has been saved', ) case [['Load', 'Settings'], ['MENU']]: @@ -506,7 +506,7 @@ class NVDAVMWindow(psg.Window): self.TKroot.after(i, self.on_pdirty) self.TKroot.after( 200, - self.nvda.speak, + self.nvda.speak_and_braille, f'config file {filepath.stem} has been loaded', ) case [['Load', 'Settings', 'on', 'Startup'], ['MENU']]: @@ -522,7 +522,7 @@ class NVDAVMWindow(psg.Window): configuration.set('default_config', str(filepath)) self.TKroot.after( 200, - self.nvda.speak, + self.nvda.speak_and_braille, f'config {filepath.stem} set as default on startup', ) else: @@ -536,7 +536,7 @@ class NVDAVMWindow(psg.Window): configuration.set('default_theme', chosen) self.TKroot.after( 200, - self.nvda.speak, + self.nvda.speak_and_braille, f'theme {chosen} selected.', ) self.logger.debug(f'theme {chosen} selected') @@ -544,13 +544,13 @@ class NVDAVMWindow(psg.Window): # Tabs case ['tabgroup'] | [['tabgroup'], ['FOCUS', 'IN']]: if self.find_element_with_focus() is None: - self.nvda.speak(f'{values["tabgroup"]}') + self.nvda.speak_and_braille(f'{values["tabgroup"]}') case [['tabgroup'], tabname] | [['tabgroup'], tabname, ['FOCUS', 'IN']]: if self.find_element_with_focus() is None: name = ' '.join(tabname) - self.nvda.speak(f'{values[f"tabgroup||{name}"]}') + self.nvda.speak_and_braille(f'{values[f"tabgroup||{name}"]}') case [['tabgroup'], _, ['KEY', 'SHIFT', 'TAB']]: - self.nvda.speak(values['tabgroup']) + self.nvda.speak_and_braille(values['tabgroup']) # Hardware In case [['HARDWARE', 'IN'], [key]]: @@ -559,18 +559,22 @@ class NVDAVMWindow(psg.Window): match selection.split(':'): case [device_name]: setattr(self.vm.strip[index].device, 'wdm', '') - self.TKroot.after(200, self.nvda.speak, f'HARDWARE IN {key} device selection removed') + self.TKroot.after( + 200, self.nvda.speak_and_braille, f'HARDWARE IN {key} device selection removed' + ) case [driver, device_name]: setattr(self.vm.strip[index].device, driver, device_name.lstrip()) phonetic = {'mme': 'em em e'} self.TKroot.after( 200, - self.nvda.speak, + self.nvda.speak_and_braille, f'HARDWARE IN {key} set {phonetic.get(driver, driver)} {device_name}', ) case [['HARDWARE', 'IN'], [key], ['FOCUS', 'IN']]: if self.find_element_with_focus() is not None: - self.nvda.speak(f'HARDWARE INPUT {key} {self.cache["hw_ins"][f"HARDWARE IN||{key}"]}') + self.nvda.speak_and_braille( + f'HARDWARE INPUT {key} {self.cache["hw_ins"][f"HARDWARE IN||{key}"]}' + ) case [['HARDWARE', 'IN'], [key], ['KEY', 'SPACE' | 'ENTER']]: util.open_context_menu_for_buttonmenu(self, f'HARDWARE IN||{key}') @@ -581,18 +585,22 @@ class NVDAVMWindow(psg.Window): match selection.split(':'): case [device_name]: setattr(self.vm.bus[index].device, 'wdm', '') - self.TKroot.after(200, self.nvda.speak, f'HARDWARE OUT {key} device selection removed') + self.TKroot.after( + 200, self.nvda.speak_and_braille, f'HARDWARE OUT {key} device selection removed' + ) case [driver, device_name]: setattr(self.vm.bus[index].device, driver, device_name.lstrip()) phonetic = {'mme': 'em em e'} self.TKroot.after( 200, - self.nvda.speak, + self.nvda.speak_and_braille, f'HARDWARE OUT {key} set {phonetic.get(driver, driver)} {device_name}', ) case [['HARDWARE', 'OUT'], [key], ['FOCUS', 'IN']]: if self.find_element_with_focus() is not None: - self.nvda.speak(f'HARDWARE OUT {key} {self.cache["hw_outs"][f"HARDWARE OUT||{key}"]}') + self.nvda.speak_and_braille( + f'HARDWARE OUT {key} {self.cache["hw_outs"][f"HARDWARE OUT||{key}"]}' + ) case [['HARDWARE', 'OUT'], [key], ['KEY', 'SPACE' | 'ENTER']]: util.open_context_menu_for_buttonmenu(self, f'HARDWARE OUT||{key}') @@ -601,7 +609,7 @@ class NVDAVMWindow(psg.Window): val = values[f'PATCH COMPOSITE||{key}'] index = int(key[-1]) - 1 self.vm.patch.composite[index].set(util.get_patch_composite_list(self.kind).index(val) + 1) - self.TKroot.after(200, self.nvda.speak, val) + self.TKroot.after(200, self.nvda.speak_and_braille, val) case [['PATCH', 'COMPOSITE'], [key], ['FOCUS', 'IN']]: if self.find_element_with_focus() is not None: if values[f'PATCH COMPOSITE||{key}']: @@ -615,7 +623,7 @@ class NVDAVMWindow(psg.Window): except IndexError as e: val = comp_list[-1] self.logger.error(f'{type(e).__name__}: {e}') - self.nvda.speak(f'Patch COMPOSITE {key[-1]} {val}') + self.nvda.speak_and_braille(f'Patch COMPOSITE {key[-1]} {val}') case [['PATCH', 'COMPOSITE'], [key], ['KEY', 'SPACE' | 'ENTER']]: util.open_context_menu_for_buttonmenu(self, f'PATCH COMPOSITE||{key}') @@ -628,7 +636,7 @@ class NVDAVMWindow(psg.Window): ) val = values[f'INSERT CHECKBOX||{in_num} {channel}'] self.vm.patch.insert[index].on = val - self.nvda.speak('on' if val else 'off') + self.nvda.speak_and_braille('on' if val else 'off') case [['INSERT', 'CHECKBOX'], [in_num, channel], ['FOCUS', 'IN']]: if self.find_element_with_focus() is not None: index = util.get_insert_checkbox_index( @@ -639,7 +647,7 @@ class NVDAVMWindow(psg.Window): val = values[f'INSERT CHECKBOX||{in_num} {channel}'] channel = util._patch_insert_channels[int(channel)] num = int(in_num[-1]) - self.nvda.speak(f'Patch INSERT IN#{num} {channel} {"on" if val else "off"}') + self.nvda.speak_and_braille(f'Patch INSERT IN#{num} {channel} {"on" if val else "off"}') case [['INSERT', 'CHECKBOX'], [in_num, channel], ['KEY', 'ENTER']]: val = not values[f'INSERT CHECKBOX||{in_num} {channel}'] self.write_event_value(f'INSERT CHECKBOX||{in_num} {channel}', val) @@ -649,7 +657,7 @@ class NVDAVMWindow(psg.Window): if values['tabgroup'] == 'tab||Settings': self.popup.advanced_settings(title='Advanced Settings') case [['ADVANCED', 'SETTINGS'], ['FOCUS', 'IN']]: - self.nvda.speak('ADVANCED SETTINGS') + self.nvda.speak_and_braille('ADVANCED SETTINGS') case [['ADVANCED', 'SETTINGS'], ['KEY', 'ENTER']]: self.find_element_with_focus().click() @@ -663,28 +671,30 @@ class NVDAVMWindow(psg.Window): next_val = 0 self.vm.strip[int(index)].k = next_val self.cache['strip'][f'STRIP {index}||{param}'] = next_val - self.nvda.speak(opts[next_val]) + self.nvda.speak_and_braille(opts[next_val]) case output if param in util._get_bus_assignments(self.kind): val = not self.cache['strip'][f'STRIP {index}||{output}'] setattr(self.vm.strip[int(index)], output, val) self.cache['strip'][f'STRIP {index}||{output}'] = val - self.nvda.speak('on' if val else 'off') + self.nvda.speak_and_braille('on' if val else 'off') case _: val = not self.cache['strip'][f'STRIP {index}||{param}'] setattr(self.vm.strip[int(index)], param.lower(), val) self.cache['strip'][f'STRIP {index}||{param}'] = val - self.nvda.speak('on' if val else 'off') + self.nvda.speak_and_braille('on' if val else 'off') case [['STRIP', index], [param], ['FOCUS', 'IN']]: if self.find_element_with_focus() is not None: val = self.cache['strip'][f'STRIP {index}||{param}'] phonetic = {'KARAOKE': 'karaoke'} label = self.cache['labels'][f'STRIP {index}||LABEL'] if param == 'KARAOKE': - self.nvda.speak( + self.nvda.speak_and_braille( f'{label} {phonetic.get(param, param)} {["off", "k m", "k 1", "k 2", "k v"][self.cache["strip"][f"STRIP {int(index)}||{param}"]]}' ) else: - self.nvda.speak(f'{label} {phonetic.get(param, param)} {"on" if val else "off"}') + self.nvda.speak_and_braille( + f'{label} {phonetic.get(param, param)} {"on" if val else "off"}' + ) case [['STRIP', index], [param], ['KEY', 'ENTER']]: self.find_element_with_focus().click() @@ -737,7 +747,7 @@ class NVDAVMWindow(psg.Window): if self.find_element_with_focus() is not None: val = values[f'STRIP {index}||SLIDER {param}'] label = self.cache['labels'][f'STRIP {index}||LABEL'] - self.nvda.speak(f'{label} {param} {int(val) if param == "LIMIT" else val}') + self.nvda.speak_and_braille(f'{label} {param} {int(val) if param == "LIMIT" else val}') case [ ['STRIP', index], [ @@ -805,7 +815,7 @@ class NVDAVMWindow(psg.Window): val = util.check_bounds(val, (-40, 12)) self.vm.strip[int(index)].limit = val self[f'STRIP {index}||SLIDER {param}'].update(value=val) - self.nvda.speak(str(round(val, 1))) + self.nvda.speak_and_braille(str(round(val, 1))) else: self.vm.event.pdirty = True case [ @@ -873,9 +883,9 @@ class NVDAVMWindow(psg.Window): self.vm.strip[int(index)].limit = val self[f'STRIP {index}||SLIDER {param}'].update(value=val) if param == 'LIMIT': - self.nvda.speak(str(int(val))) + self.nvda.speak_and_braille(str(int(val))) else: - self.nvda.speak(str(round(val, 1))) + self.nvda.speak_and_braille(str(round(val, 1))) else: self.vm.event.pdirty = True case [ @@ -943,9 +953,9 @@ class NVDAVMWindow(psg.Window): self.vm.strip[int(index)].limit = val self[f'STRIP {index}||SLIDER {param}'].update(value=val) if param == 'LIMIT': - self.nvda.speak(str(int(val))) + self.nvda.speak_and_braille(str(int(val))) else: - self.nvda.speak(str(round(val, 1))) + self.nvda.speak_and_braille(str(round(val, 1))) else: self.vm.event.pdirty = True case [['STRIP', index], ['SLIDER', param], ['KEY', 'CTRL', 'SHIFT', 'R']]: @@ -966,7 +976,7 @@ class NVDAVMWindow(psg.Window): case 'LIMIT': self.vm.strip[int(index)].limit = 12 self[f'STRIP {index}||SLIDER {param}'].update(value=12) - self.nvda.speak(f'{12 if param == "LIMIT" else 0}') + self.nvda.speak_and_braille(f'{12 if param == "LIMIT" else 0}') # Bus Params case [['BUS', index], [param]]: @@ -979,7 +989,7 @@ class NVDAVMWindow(psg.Window): self.cache['bus'][event] = val self.TKroot.after( 200, - self.nvda.speak, + self.nvda.speak_and_braille, 'on' if val else 'off', ) case 'MUTE': @@ -988,7 +998,7 @@ class NVDAVMWindow(psg.Window): self.cache['bus'][event] = val self.TKroot.after( 200, - self.nvda.speak, + self.nvda.speak_and_braille, 'on' if val else 'off', ) case 'MONO': @@ -997,7 +1007,7 @@ class NVDAVMWindow(psg.Window): self.cache['bus'][event] = chosen self.TKroot.after( 200, - self.nvda.speak, + self.nvda.speak_and_braille, f'mono {chosen}', ) case 'MODE': @@ -1006,7 +1016,7 @@ class NVDAVMWindow(psg.Window): self.cache['bus'][event] = chosen self.TKroot.after( 200, - self.nvda.speak, + self.nvda.speak_and_braille, util._bus_mode_map[chosen], ) case [['BUS', index], [param], ['FOCUS', 'IN']]: @@ -1014,15 +1024,15 @@ class NVDAVMWindow(psg.Window): label = self.cache['labels'][f'BUS {index}||LABEL'] val = self.cache['bus'][f'BUS {index}||{param}'] if param == 'MODE': - self.nvda.speak(f'{label} bus {param} {util._bus_mode_map[val]}') + self.nvda.speak_and_braille(f'{label} bus {param} {util._bus_mode_map[val]}') elif param == 'MONO': busmode = util.get_bus_mono()[val] if busmode in ('on', 'off'): - self.nvda.speak(f'{label} {param} {busmode}') + self.nvda.speak_and_braille(f'{label} {param} {busmode}') else: - self.nvda.speak(f'{label} {busmode}') + self.nvda.speak_and_braille(f'{label} {busmode}') else: - self.nvda.speak(f'{label} {param} {"on" if val else "off"}') + self.nvda.speak_and_braille(f'{label} {param} {"on" if val else "off"}') case [['BUS', index], [param], ['KEY', 'SPACE' | 'ENTER']]: if param == 'MODE': util.open_context_menu_for_buttonmenu(self, f'BUS {index}||MODE') @@ -1040,7 +1050,7 @@ class NVDAVMWindow(psg.Window): if self.find_element_with_focus() is not None: label = self.cache['labels'][f'BUS {index}||LABEL'] val = values[f'BUS {index}||SLIDER GAIN'] - self.nvda.speak(f'{label} gain {val}') + self.nvda.speak_and_braille(f'{label} gain {val}') case [['BUS', index], ['SLIDER', 'GAIN'], ['FOCUS', 'OUT']]: pass case [ @@ -1059,7 +1069,7 @@ class NVDAVMWindow(psg.Window): val = util.check_bounds(val, (-60, 12)) self.vm.bus[int(index)].gain = val self[f'BUS {index}||SLIDER GAIN'].update(value=val) - self.nvda.speak(str(round(val, 1))) + self.nvda.speak_and_braille(str(round(val, 1))) else: self.vm.event.pdirty = True case [ @@ -1078,7 +1088,7 @@ class NVDAVMWindow(psg.Window): val = util.check_bounds(val, (-60, 12)) self.vm.bus[int(index)].gain = val self[f'BUS {index}||SLIDER GAIN'].update(value=val) - self.nvda.speak(str(round(val, 1))) + self.nvda.speak_and_braille(str(round(val, 1))) else: self.vm.event.pdirty = True case [ @@ -1097,13 +1107,13 @@ class NVDAVMWindow(psg.Window): val = util.check_bounds(val, (-60, 12)) self.vm.bus[int(index)].gain = val self[f'BUS {index}||SLIDER GAIN'].update(value=val) - self.nvda.speak(str(round(val, 1))) + self.nvda.speak_and_braille(str(round(val, 1))) else: self.vm.event.pdirty = True case [['BUS', index], ['SLIDER', 'GAIN'], ['KEY', 'CTRL', 'SHIFT', 'R']]: self.vm.bus[int(index)].gain = 0 self[f'BUS {index}||SLIDER GAIN'].update(value=0) - self.nvda.speak(str(0)) + self.nvda.speak_and_braille(str(0)) # Unknown case _: