add braille support

This commit is contained in:
onyx-and-iris 2026-03-20 02:33:12 +00:00
parent 2e3ba66b5a
commit 7f327b4cce
3 changed files with 104 additions and 88 deletions

View File

@ -50,3 +50,7 @@ class Nvda:
def braille_message(self, text: str) -> None: def braille_message(self, text: str) -> None:
self._bindings.braille_message(text) self._bindings.braille_message(text)
def speak_and_braille(self, text: str) -> None:
self.speak(text)
self.braille_message(text)

View File

@ -40,7 +40,7 @@ class Popup:
if values['Browse']: if values['Browse']:
filepath = values['Browse'] filepath = values['Browse']
break break
self.window.nvda.speak(button) self.window.nvda.speak_and_braille(button)
case [_, ['KEY', 'ENTER']]: case [_, ['KEY', 'ENTER']]:
popup.find_element_with_focus().click() popup.find_element_with_focus().click()
self.logger.debug(f'parsed::{parsed_cmd}') self.logger.debug(f'parsed::{parsed_cmd}')
@ -107,7 +107,7 @@ class Popup:
break break
match parsed_cmd := self.window.parser.match.parse_string(event): match parsed_cmd := self.window.parser.match.parse_string(event):
case [[button], ['FOCUS', 'IN']]: case [[button], ['FOCUS', 'IN']]:
self.window.nvda.speak(button) self.window.nvda.speak_and_braille(button)
case [_, ['KEY', 'ENTER']]: case [_, ['KEY', 'ENTER']]:
popup.find_element_with_focus().click() popup.find_element_with_focus().click()
case ['Ok']: case ['Ok']:
@ -233,21 +233,21 @@ class Popup:
val = values[f'ASIO INPUT SPINBOX||{in_num} {channel}'] val = values[f'ASIO INPUT SPINBOX||{in_num} {channel}']
self.window.vm.patch.asio[index].set(val) self.window.vm.patch.asio[index].set(val)
channel = ('left', 'right')[int(channel)] 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']]: case [['ASIO', 'INPUT', 'SPINBOX'], [in_num, channel], ['FOCUS', 'IN']]:
if self.popup.find_element_with_focus() is not None: if self.popup.find_element_with_focus() is not None:
val = values[f'ASIO INPUT SPINBOX||{in_num} {channel}'] val = values[f'ASIO INPUT SPINBOX||{in_num} {channel}']
channel = ('left', 'right')[int(channel)] channel = ('left', 'right')[int(channel)]
num = int(in_num[-1]) 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]]: case [['ASIO', 'OUTPUT', param, 'SPINBOX'], [index]]:
target = getattr(self.window.vm.patch, param)[int(index)] target = getattr(self.window.vm.patch, param)[int(index)]
target.set(values[event]) 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']]: case [['ASIO', 'OUTPUT', param, 'SPINBOX'], [index], ['FOCUS', 'IN']]:
if self.popup.find_element_with_focus() is not None: if self.popup.find_element_with_focus() is not None:
val = values[f'ASIO OUTPUT {param} SPINBOX||{index}'] 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}' f'Patch BUS to A1 ASIO Outputs OUT {param} channel {int(index) + 1} {val}'
) )
case ['BUFFER MME' | 'BUFFER WDM' | 'BUFFER KS' | 'BUFFER ASIO']: case ['BUFFER MME' | 'BUFFER WDM' | 'BUFFER KS' | 'BUFFER ASIO']:
@ -263,15 +263,15 @@ class Popup:
driver = event.split()[1] driver = event.split()[1]
self.window.vm.set(f'option.buffer.{driver.lower()}', val) self.window.vm.set(f'option.buffer.{driver.lower()}', val)
self.window.TKroot.after( 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']]: case [['BUFFER', driver], ['FOCUS', 'IN']]:
val = int(self.window.vm.get(f'option.buffer.{driver.lower()}')) 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']]: case [['BUFFER', driver], ['KEY', 'SPACE' | 'ENTER']]:
util.open_context_menu_for_buttonmenu(self.popup, f'BUFFER {driver}') util.open_context_menu_for_buttonmenu(self.popup, f'BUFFER {driver}')
case [[button], ['FOCUS', 'IN']]: case [[button], ['FOCUS', 'IN']]:
self.window.nvda.speak(button) self.window.nvda.speak_and_braille(button)
case [_, ['KEY', 'ENTER']]: case [_, ['KEY', 'ENTER']]:
self.popup.find_element_with_focus().click() self.popup.find_element_with_focus().click()
self.logger.debug(f'parsed::{parsed_cmd}') self.logger.debug(f'parsed::{parsed_cmd}')
@ -337,7 +337,7 @@ class Popup:
case [['COMPRESSOR'], ['SLIDER', param]]: case [['COMPRESSOR'], ['SLIDER', param]]:
setattr(self.window.vm.strip[index].comp, param.lower(), values[event]) setattr(self.window.vm.strip[index].comp, param.lower(), values[event])
case [['COMPRESSOR'], ['SLIDER', param], ['FOCUS', 'IN']]: 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 [ case [
['COMPRESSOR'], ['COMPRESSOR'],
['SLIDER', param], ['SLIDER', param],
@ -364,9 +364,9 @@ class Popup:
setattr(self.window.vm.strip[index].comp, param.lower(), val) setattr(self.window.vm.strip[index].comp, param.lower(), val)
self.popup[f'COMPRESSOR||SLIDER {param}'].update(value=val) self.popup[f'COMPRESSOR||SLIDER {param}'].update(value=val)
if param == 'KNEE': if param == 'KNEE':
self.window.nvda.speak(str(round(val, 2))) self.window.nvda.speak_and_braille(str(round(val, 2)))
else: else:
self.window.nvda.speak(str(round(val, 1))) self.window.nvda.speak_and_braille(str(round(val, 1)))
else: else:
self.window.vm.event.pdirty = True self.window.vm.event.pdirty = True
case [ case [
@ -399,9 +399,9 @@ class Popup:
setattr(self.window.vm.strip[index].comp, param.lower(), val) setattr(self.window.vm.strip[index].comp, param.lower(), val)
self.popup[f'COMPRESSOR||SLIDER {param}'].update(value=val) self.popup[f'COMPRESSOR||SLIDER {param}'].update(value=val)
if param == 'KNEE': if param == 'KNEE':
self.window.nvda.speak(str(round(val, 2))) self.window.nvda.speak_and_braille(str(round(val, 2)))
else: else:
self.window.nvda.speak(str(round(val, 1))) self.window.nvda.speak_and_braille(str(round(val, 1)))
else: else:
self.window.vm.event.pdirty = True self.window.vm.event.pdirty = True
case [ case [
@ -430,9 +430,9 @@ class Popup:
setattr(self.window.vm.strip[index].comp, param.lower(), val) setattr(self.window.vm.strip[index].comp, param.lower(), val)
self.popup[f'COMPRESSOR||SLIDER {param}'].update(value=val) self.popup[f'COMPRESSOR||SLIDER {param}'].update(value=val)
if param == 'KNEE': if param == 'KNEE':
self.window.nvda.speak(str(round(val, 2))) self.window.nvda.speak_and_braille(str(round(val, 2)))
else: else:
self.window.nvda.speak(str(round(val, 1))) self.window.nvda.speak_and_braille(str(round(val, 1)))
else: else:
self.window.vm.event.pdirty = True self.window.vm.event.pdirty = True
case [ case [
@ -453,7 +453,7 @@ class Popup:
val = util.check_bounds(val, (0, 5000)) val = util.check_bounds(val, (0, 5000))
self.window.vm.strip[index].comp.release = val self.window.vm.strip[index].comp.release = val
self.popup[f'COMPRESSOR||SLIDER {param}'].update(value=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: else:
self.window.vm.event.pdirty = True self.window.vm.event.pdirty = True
case [ case [
@ -474,7 +474,7 @@ class Popup:
val = util.check_bounds(val, (0, 5000)) val = util.check_bounds(val, (0, 5000))
self.window.vm.strip[index].comp.release = val self.window.vm.strip[index].comp.release = val
self.popup[f'COMPRESSOR||SLIDER {param}'].update(value=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: else:
self.window.vm.event.pdirty = True self.window.vm.event.pdirty = True
@ -485,7 +485,7 @@ class Popup:
self.window.vm.strip[index].comp.gainout = values[event] self.window.vm.strip[index].comp.gainout = values[event]
case [['COMPRESSOR'], ['SLIDER', 'INPUT' | 'OUTPUT' as direction, 'GAIN'], ['FOCUS', 'IN']]: case [['COMPRESSOR'], ['SLIDER', 'INPUT' | 'OUTPUT' as direction, 'GAIN'], ['FOCUS', 'IN']]:
label = f'{direction} GAIN' 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 [ case [
['COMPRESSOR'], ['COMPRESSOR'],
['SLIDER', 'INPUT' | 'OUTPUT' as direction, 'GAIN'], ['SLIDER', 'INPUT' | 'OUTPUT' as direction, 'GAIN'],
@ -510,7 +510,7 @@ class Popup:
else: else:
self.window.vm.strip[index].comp.gainout = val self.window.vm.strip[index].comp.gainout = val
self.popup[f'COMPRESSOR||SLIDER {direction} GAIN'].update(value=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: else:
self.window.vm.event.pdirty = True self.window.vm.event.pdirty = True
case [ case [
@ -537,7 +537,7 @@ class Popup:
else: else:
self.window.vm.strip[index].comp.gainout = val self.window.vm.strip[index].comp.gainout = val
self.popup[f'COMPRESSOR||SLIDER {direction} GAIN'].update(value=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: else:
self.window.vm.event.pdirty = True self.window.vm.event.pdirty = True
case [ case [
@ -564,7 +564,7 @@ class Popup:
else: else:
self.window.vm.strip[index].comp.gainout = val self.window.vm.strip[index].comp.gainout = val
self.popup[f'COMPRESSOR||SLIDER {direction} GAIN'].update(value=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: else:
self.window.vm.event.pdirty = True self.window.vm.event.pdirty = True
@ -578,7 +578,7 @@ class Popup:
else: else:
self.window.vm.strip[index].comp.gainout = 0 self.window.vm.strip[index].comp.gainout = 0
self.popup[f'COMPRESSOR||SLIDER {direction} GAIN'].update(value=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']]: case [['COMPRESSOR'], ['SLIDER', param], ['KEY', 'CTRL', 'SHIFT', 'R']]:
match param: match param:
case 'RATIO': case 'RATIO':
@ -593,19 +593,19 @@ class Popup:
val = 0.5 val = 0.5
setattr(self.window.vm.strip[index].comp, param.lower(), val) setattr(self.window.vm.strip[index].comp, param.lower(), val)
self.popup[f'COMPRESSOR||SLIDER {param}'].update(value=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']: case ['MAKEUP']:
val = not self.window.vm.strip[index].comp.makeup val = not self.window.vm.strip[index].comp.makeup
self.window.vm.strip[index].comp.makeup = val 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']]: case [[button], ['FOCUS', 'IN']]:
if button == 'MAKEUP': 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"}' f'{button} {"on" if self.window.vm.strip[index].comp.makeup else "off"}'
) )
else: else:
self.window.nvda.speak(button) self.window.nvda.speak_and_braille(button)
case [_, ['KEY', 'ENTER']]: case [_, ['KEY', 'ENTER']]:
self.popup.find_element_with_focus().click() self.popup.find_element_with_focus().click()
self.logger.debug(f'parsed::{parsed_cmd}') self.logger.debug(f'parsed::{parsed_cmd}')
@ -673,7 +673,9 @@ class Popup:
'DAMPING': 'Damping Max', 'DAMPING': 'Damping Max',
'BPSIDECHAIN': 'BP Sidechain', '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 [ case [
['GATE'], ['GATE'],
@ -695,9 +697,9 @@ class Popup:
setattr(self.window.vm.strip[index].gate, param.lower(), val) setattr(self.window.vm.strip[index].gate, param.lower(), val)
self.popup[f'GATE||SLIDER {param}'].update(value=val) self.popup[f'GATE||SLIDER {param}'].update(value=val)
if param == 'BPSIDECHAIN': if param == 'BPSIDECHAIN':
self.window.nvda.speak(str(int(val))) self.window.nvda.speak_and_braille(str(int(val)))
else: else:
self.window.nvda.speak(str(round(val, 1))) self.window.nvda.speak_and_braille(str(round(val, 1)))
else: else:
self.window.vm.event.pdirty = True self.window.vm.event.pdirty = True
case [ case [
@ -720,9 +722,9 @@ class Popup:
setattr(self.window.vm.strip[index].gate, param.lower(), val) setattr(self.window.vm.strip[index].gate, param.lower(), val)
self.popup[f'GATE||SLIDER {param}'].update(value=val) self.popup[f'GATE||SLIDER {param}'].update(value=val)
if param == 'BPSIDECHAIN': if param == 'BPSIDECHAIN':
self.window.nvda.speak(str(int(val))) self.window.nvda.speak_and_braille(str(int(val)))
else: else:
self.window.nvda.speak(str(round(val, 1))) self.window.nvda.speak_and_braille(str(round(val, 1)))
else: else:
self.window.vm.event.pdirty = True self.window.vm.event.pdirty = True
case [ case [
@ -745,9 +747,9 @@ class Popup:
setattr(self.window.vm.strip[index].gate, param.lower(), val) setattr(self.window.vm.strip[index].gate, param.lower(), val)
self.popup[f'GATE||SLIDER {param}'].update(value=val) self.popup[f'GATE||SLIDER {param}'].update(value=val)
if param == 'BPSIDECHAIN': if param == 'BPSIDECHAIN':
self.window.nvda.speak(str(int(val))) self.window.nvda.speak_and_braille(str(int(val)))
else: else:
self.window.nvda.speak(str(round(val, 1))) self.window.nvda.speak_and_braille(str(round(val, 1)))
else: else:
self.window.vm.event.pdirty = True self.window.vm.event.pdirty = True
case [ case [
@ -769,9 +771,9 @@ class Popup:
setattr(self.window.vm.strip[index].gate, param.lower(), val) setattr(self.window.vm.strip[index].gate, param.lower(), val)
self.popup[f'GATE||SLIDER {param}'].update(value=val) self.popup[f'GATE||SLIDER {param}'].update(value=val)
if param == 'BPSIDECHAIN': if param == 'BPSIDECHAIN':
self.window.nvda.speak(str(int(val))) self.window.nvda.speak_and_braille(str(int(val)))
else: else:
self.window.nvda.speak(str(round(val, 1))) self.window.nvda.speak_and_braille(str(round(val, 1)))
else: else:
self.window.vm.event.pdirty = True self.window.vm.event.pdirty = True
case [ case [
@ -793,9 +795,9 @@ class Popup:
setattr(self.window.vm.strip[index].gate, param.lower(), val) setattr(self.window.vm.strip[index].gate, param.lower(), val)
self.popup[f'GATE||SLIDER {param}'].update(value=val) self.popup[f'GATE||SLIDER {param}'].update(value=val)
if param == 'BPSIDECHAIN': if param == 'BPSIDECHAIN':
self.window.nvda.speak(str(int(val))) self.window.nvda.speak_and_braille(str(int(val)))
else: else:
self.window.nvda.speak(str(round(val, 1))) self.window.nvda.speak_and_braille(str(round(val, 1)))
else: else:
self.window.vm.event.pdirty = True self.window.vm.event.pdirty = True
case [['GATE'], ['SLIDER', param], ['KEY', 'CTRL', 'SHIFT', 'R']]: case [['GATE'], ['SLIDER', param], ['KEY', 'CTRL', 'SHIFT', 'R']]:
@ -814,10 +816,10 @@ class Popup:
val = 1000 val = 1000
setattr(self.window.vm.strip[index].gate, param.lower(), val) setattr(self.window.vm.strip[index].gate, param.lower(), val)
self.popup[f'GATE||SLIDER {param}'].update(value=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']]: case [[button], ['FOCUS', 'IN']]:
self.window.nvda.speak(button) self.window.nvda.speak_and_braille(button)
case [_, ['KEY', 'ENTER']]: case [_, ['KEY', 'ENTER']]:
self.popup.find_element_with_focus().click() self.popup.find_element_with_focus().click()

View File

@ -78,7 +78,7 @@ class NVDAVMWindow(psg.Window):
self.logger.debug(f'config {defaultconfig} loaded') self.logger.debug(f'config {defaultconfig} loaded')
self.TKroot.after( self.TKroot.after(
200, 200,
self.nvda.speak, self.nvda.speak_and_braille,
f'config {defaultconfig.stem} has been loaded', f'config {defaultconfig.stem} has been loaded',
) )
except json.JSONDecodeError: except json.JSONDecodeError:
@ -306,12 +306,12 @@ class NVDAVMWindow(psg.Window):
break break
elif event in util.get_slider_modes(): elif event in util.get_slider_modes():
mode = event mode = event
self.nvda.speak(f'{mode} enabled') self.nvda.speak_and_braille(f'{mode} enabled')
self.logger.debug(f'entered slider mode {mode}') self.logger.debug(f'entered slider mode {mode}')
continue continue
elif event == 'ESCAPE': elif event == 'ESCAPE':
if mode: 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}') self.logger.debug(f'exited from slider mode {mode}')
mode = None mode = None
continue continue
@ -331,7 +331,7 @@ class NVDAVMWindow(psg.Window):
# Focus tabgroup # Focus tabgroup
case ['CTRL-TAB'] | ['CTRL-SHIFT-TAB']: case ['CTRL-TAB'] | ['CTRL-SHIFT-TAB']:
self['tabgroup'].set_focus() self['tabgroup'].set_focus()
self.nvda.speak(f'{values["tabgroup"]}') self.nvda.speak_and_braille(f'{values["tabgroup"]}')
# Quick Navigation # Quick Navigation
case ['CTRL-1' | 'CTRL-2' | 'CTRL-3' | 'CTRL-4' | 'CTRL-5' | 'CTRL-6' | 'CTRL-7' | 'CTRL-8' as bind]: 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']]: case [['ENGINE', 'RESTART'], ['END']]:
self.TKroot.after( self.TKroot.after(
200, 200,
self.nvda.speak, self.nvda.speak_and_braille,
'Audio Engine restarted', 'Audio Engine restarted',
) )
case [['Save', 'Settings'], ['MENU']]: case [['Save', 'Settings'], ['MENU']]:
@ -487,7 +487,7 @@ class NVDAVMWindow(psg.Window):
self.logger.debug(f'saving config file to {filepath}') self.logger.debug(f'saving config file to {filepath}')
self.TKroot.after( self.TKroot.after(
200, 200,
self.nvda.speak, self.nvda.speak_and_braille,
f'config file {filepath.stem} has been saved', f'config file {filepath.stem} has been saved',
) )
case [['Load', 'Settings'], ['MENU']]: case [['Load', 'Settings'], ['MENU']]:
@ -506,7 +506,7 @@ class NVDAVMWindow(psg.Window):
self.TKroot.after(i, self.on_pdirty) self.TKroot.after(i, self.on_pdirty)
self.TKroot.after( self.TKroot.after(
200, 200,
self.nvda.speak, self.nvda.speak_and_braille,
f'config file {filepath.stem} has been loaded', f'config file {filepath.stem} has been loaded',
) )
case [['Load', 'Settings', 'on', 'Startup'], ['MENU']]: case [['Load', 'Settings', 'on', 'Startup'], ['MENU']]:
@ -522,7 +522,7 @@ class NVDAVMWindow(psg.Window):
configuration.set('default_config', str(filepath)) configuration.set('default_config', str(filepath))
self.TKroot.after( self.TKroot.after(
200, 200,
self.nvda.speak, self.nvda.speak_and_braille,
f'config {filepath.stem} set as default on startup', f'config {filepath.stem} set as default on startup',
) )
else: else:
@ -536,7 +536,7 @@ class NVDAVMWindow(psg.Window):
configuration.set('default_theme', chosen) configuration.set('default_theme', chosen)
self.TKroot.after( self.TKroot.after(
200, 200,
self.nvda.speak, self.nvda.speak_and_braille,
f'theme {chosen} selected.', f'theme {chosen} selected.',
) )
self.logger.debug(f'theme {chosen} selected') self.logger.debug(f'theme {chosen} selected')
@ -544,13 +544,13 @@ class NVDAVMWindow(psg.Window):
# Tabs # Tabs
case ['tabgroup'] | [['tabgroup'], ['FOCUS', 'IN']]: case ['tabgroup'] | [['tabgroup'], ['FOCUS', 'IN']]:
if self.find_element_with_focus() is None: 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']]: case [['tabgroup'], tabname] | [['tabgroup'], tabname, ['FOCUS', 'IN']]:
if self.find_element_with_focus() is None: if self.find_element_with_focus() is None:
name = ' '.join(tabname) 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']]: case [['tabgroup'], _, ['KEY', 'SHIFT', 'TAB']]:
self.nvda.speak(values['tabgroup']) self.nvda.speak_and_braille(values['tabgroup'])
# Hardware In # Hardware In
case [['HARDWARE', 'IN'], [key]]: case [['HARDWARE', 'IN'], [key]]:
@ -559,18 +559,22 @@ class NVDAVMWindow(psg.Window):
match selection.split(':'): match selection.split(':'):
case [device_name]: case [device_name]:
setattr(self.vm.strip[index].device, 'wdm', '') 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]: case [driver, device_name]:
setattr(self.vm.strip[index].device, driver, device_name.lstrip()) setattr(self.vm.strip[index].device, driver, device_name.lstrip())
phonetic = {'mme': 'em em e'} phonetic = {'mme': 'em em e'}
self.TKroot.after( self.TKroot.after(
200, 200,
self.nvda.speak, self.nvda.speak_and_braille,
f'HARDWARE IN {key} set {phonetic.get(driver, driver)} {device_name}', f'HARDWARE IN {key} set {phonetic.get(driver, driver)} {device_name}',
) )
case [['HARDWARE', 'IN'], [key], ['FOCUS', 'IN']]: case [['HARDWARE', 'IN'], [key], ['FOCUS', 'IN']]:
if self.find_element_with_focus() is not None: 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']]: case [['HARDWARE', 'IN'], [key], ['KEY', 'SPACE' | 'ENTER']]:
util.open_context_menu_for_buttonmenu(self, f'HARDWARE IN||{key}') util.open_context_menu_for_buttonmenu(self, f'HARDWARE IN||{key}')
@ -581,18 +585,22 @@ class NVDAVMWindow(psg.Window):
match selection.split(':'): match selection.split(':'):
case [device_name]: case [device_name]:
setattr(self.vm.bus[index].device, 'wdm', '') 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]: case [driver, device_name]:
setattr(self.vm.bus[index].device, driver, device_name.lstrip()) setattr(self.vm.bus[index].device, driver, device_name.lstrip())
phonetic = {'mme': 'em em e'} phonetic = {'mme': 'em em e'}
self.TKroot.after( self.TKroot.after(
200, 200,
self.nvda.speak, self.nvda.speak_and_braille,
f'HARDWARE OUT {key} set {phonetic.get(driver, driver)} {device_name}', f'HARDWARE OUT {key} set {phonetic.get(driver, driver)} {device_name}',
) )
case [['HARDWARE', 'OUT'], [key], ['FOCUS', 'IN']]: case [['HARDWARE', 'OUT'], [key], ['FOCUS', 'IN']]:
if self.find_element_with_focus() is not None: 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']]: case [['HARDWARE', 'OUT'], [key], ['KEY', 'SPACE' | 'ENTER']]:
util.open_context_menu_for_buttonmenu(self, f'HARDWARE OUT||{key}') 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}'] val = values[f'PATCH COMPOSITE||{key}']
index = int(key[-1]) - 1 index = int(key[-1]) - 1
self.vm.patch.composite[index].set(util.get_patch_composite_list(self.kind).index(val) + 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']]: case [['PATCH', 'COMPOSITE'], [key], ['FOCUS', 'IN']]:
if self.find_element_with_focus() is not None: if self.find_element_with_focus() is not None:
if values[f'PATCH COMPOSITE||{key}']: if values[f'PATCH COMPOSITE||{key}']:
@ -615,7 +623,7 @@ class NVDAVMWindow(psg.Window):
except IndexError as e: except IndexError as e:
val = comp_list[-1] val = comp_list[-1]
self.logger.error(f'{type(e).__name__}: {e}') 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']]: case [['PATCH', 'COMPOSITE'], [key], ['KEY', 'SPACE' | 'ENTER']]:
util.open_context_menu_for_buttonmenu(self, f'PATCH COMPOSITE||{key}') 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}'] val = values[f'INSERT CHECKBOX||{in_num} {channel}']
self.vm.patch.insert[index].on = val 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']]: case [['INSERT', 'CHECKBOX'], [in_num, channel], ['FOCUS', 'IN']]:
if self.find_element_with_focus() is not None: if self.find_element_with_focus() is not None:
index = util.get_insert_checkbox_index( index = util.get_insert_checkbox_index(
@ -639,7 +647,7 @@ class NVDAVMWindow(psg.Window):
val = values[f'INSERT CHECKBOX||{in_num} {channel}'] val = values[f'INSERT CHECKBOX||{in_num} {channel}']
channel = util._patch_insert_channels[int(channel)] channel = util._patch_insert_channels[int(channel)]
num = int(in_num[-1]) 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']]: case [['INSERT', 'CHECKBOX'], [in_num, channel], ['KEY', 'ENTER']]:
val = not values[f'INSERT CHECKBOX||{in_num} {channel}'] val = not values[f'INSERT CHECKBOX||{in_num} {channel}']
self.write_event_value(f'INSERT CHECKBOX||{in_num} {channel}', val) self.write_event_value(f'INSERT CHECKBOX||{in_num} {channel}', val)
@ -649,7 +657,7 @@ class NVDAVMWindow(psg.Window):
if values['tabgroup'] == 'tab||Settings': if values['tabgroup'] == 'tab||Settings':
self.popup.advanced_settings(title='Advanced Settings') self.popup.advanced_settings(title='Advanced Settings')
case [['ADVANCED', 'SETTINGS'], ['FOCUS', 'IN']]: case [['ADVANCED', 'SETTINGS'], ['FOCUS', 'IN']]:
self.nvda.speak('ADVANCED SETTINGS') self.nvda.speak_and_braille('ADVANCED SETTINGS')
case [['ADVANCED', 'SETTINGS'], ['KEY', 'ENTER']]: case [['ADVANCED', 'SETTINGS'], ['KEY', 'ENTER']]:
self.find_element_with_focus().click() self.find_element_with_focus().click()
@ -663,28 +671,30 @@ class NVDAVMWindow(psg.Window):
next_val = 0 next_val = 0
self.vm.strip[int(index)].k = next_val self.vm.strip[int(index)].k = next_val
self.cache['strip'][f'STRIP {index}||{param}'] = 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): case output if param in util._get_bus_assignments(self.kind):
val = not self.cache['strip'][f'STRIP {index}||{output}'] val = not self.cache['strip'][f'STRIP {index}||{output}']
setattr(self.vm.strip[int(index)], output, val) setattr(self.vm.strip[int(index)], output, val)
self.cache['strip'][f'STRIP {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 _: case _:
val = not self.cache['strip'][f'STRIP {index}||{param}'] val = not self.cache['strip'][f'STRIP {index}||{param}']
setattr(self.vm.strip[int(index)], param.lower(), val) setattr(self.vm.strip[int(index)], param.lower(), val)
self.cache['strip'][f'STRIP {index}||{param}'] = 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']]: case [['STRIP', index], [param], ['FOCUS', 'IN']]:
if self.find_element_with_focus() is not None: if self.find_element_with_focus() is not None:
val = self.cache['strip'][f'STRIP {index}||{param}'] val = self.cache['strip'][f'STRIP {index}||{param}']
phonetic = {'KARAOKE': 'karaoke'} phonetic = {'KARAOKE': 'karaoke'}
label = self.cache['labels'][f'STRIP {index}||LABEL'] label = self.cache['labels'][f'STRIP {index}||LABEL']
if param == 'KARAOKE': 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}"]]}' f'{label} {phonetic.get(param, param)} {["off", "k m", "k 1", "k 2", "k v"][self.cache["strip"][f"STRIP {int(index)}||{param}"]]}'
) )
else: 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']]: case [['STRIP', index], [param], ['KEY', 'ENTER']]:
self.find_element_with_focus().click() self.find_element_with_focus().click()
@ -737,7 +747,7 @@ class NVDAVMWindow(psg.Window):
if self.find_element_with_focus() is not None: if self.find_element_with_focus() is not None:
val = values[f'STRIP {index}||SLIDER {param}'] val = values[f'STRIP {index}||SLIDER {param}']
label = self.cache['labels'][f'STRIP {index}||LABEL'] 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 [ case [
['STRIP', index], ['STRIP', index],
[ [
@ -805,7 +815,7 @@ class NVDAVMWindow(psg.Window):
val = util.check_bounds(val, (-40, 12)) val = util.check_bounds(val, (-40, 12))
self.vm.strip[int(index)].limit = val self.vm.strip[int(index)].limit = val
self[f'STRIP {index}||SLIDER {param}'].update(value=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: else:
self.vm.event.pdirty = True self.vm.event.pdirty = True
case [ case [
@ -873,9 +883,9 @@ class NVDAVMWindow(psg.Window):
self.vm.strip[int(index)].limit = val self.vm.strip[int(index)].limit = val
self[f'STRIP {index}||SLIDER {param}'].update(value=val) self[f'STRIP {index}||SLIDER {param}'].update(value=val)
if param == 'LIMIT': if param == 'LIMIT':
self.nvda.speak(str(int(val))) self.nvda.speak_and_braille(str(int(val)))
else: else:
self.nvda.speak(str(round(val, 1))) self.nvda.speak_and_braille(str(round(val, 1)))
else: else:
self.vm.event.pdirty = True self.vm.event.pdirty = True
case [ case [
@ -943,9 +953,9 @@ class NVDAVMWindow(psg.Window):
self.vm.strip[int(index)].limit = val self.vm.strip[int(index)].limit = val
self[f'STRIP {index}||SLIDER {param}'].update(value=val) self[f'STRIP {index}||SLIDER {param}'].update(value=val)
if param == 'LIMIT': if param == 'LIMIT':
self.nvda.speak(str(int(val))) self.nvda.speak_and_braille(str(int(val)))
else: else:
self.nvda.speak(str(round(val, 1))) self.nvda.speak_and_braille(str(round(val, 1)))
else: else:
self.vm.event.pdirty = True self.vm.event.pdirty = True
case [['STRIP', index], ['SLIDER', param], ['KEY', 'CTRL', 'SHIFT', 'R']]: case [['STRIP', index], ['SLIDER', param], ['KEY', 'CTRL', 'SHIFT', 'R']]:
@ -966,7 +976,7 @@ class NVDAVMWindow(psg.Window):
case 'LIMIT': case 'LIMIT':
self.vm.strip[int(index)].limit = 12 self.vm.strip[int(index)].limit = 12
self[f'STRIP {index}||SLIDER {param}'].update(value=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 # Bus Params
case [['BUS', index], [param]]: case [['BUS', index], [param]]:
@ -979,7 +989,7 @@ class NVDAVMWindow(psg.Window):
self.cache['bus'][event] = val self.cache['bus'][event] = val
self.TKroot.after( self.TKroot.after(
200, 200,
self.nvda.speak, self.nvda.speak_and_braille,
'on' if val else 'off', 'on' if val else 'off',
) )
case 'MUTE': case 'MUTE':
@ -988,7 +998,7 @@ class NVDAVMWindow(psg.Window):
self.cache['bus'][event] = val self.cache['bus'][event] = val
self.TKroot.after( self.TKroot.after(
200, 200,
self.nvda.speak, self.nvda.speak_and_braille,
'on' if val else 'off', 'on' if val else 'off',
) )
case 'MONO': case 'MONO':
@ -997,7 +1007,7 @@ class NVDAVMWindow(psg.Window):
self.cache['bus'][event] = chosen self.cache['bus'][event] = chosen
self.TKroot.after( self.TKroot.after(
200, 200,
self.nvda.speak, self.nvda.speak_and_braille,
f'mono {chosen}', f'mono {chosen}',
) )
case 'MODE': case 'MODE':
@ -1006,7 +1016,7 @@ class NVDAVMWindow(psg.Window):
self.cache['bus'][event] = chosen self.cache['bus'][event] = chosen
self.TKroot.after( self.TKroot.after(
200, 200,
self.nvda.speak, self.nvda.speak_and_braille,
util._bus_mode_map[chosen], util._bus_mode_map[chosen],
) )
case [['BUS', index], [param], ['FOCUS', 'IN']]: case [['BUS', index], [param], ['FOCUS', 'IN']]:
@ -1014,15 +1024,15 @@ class NVDAVMWindow(psg.Window):
label = self.cache['labels'][f'BUS {index}||LABEL'] label = self.cache['labels'][f'BUS {index}||LABEL']
val = self.cache['bus'][f'BUS {index}||{param}'] val = self.cache['bus'][f'BUS {index}||{param}']
if param == 'MODE': 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': elif param == 'MONO':
busmode = util.get_bus_mono()[val] busmode = util.get_bus_mono()[val]
if busmode in ('on', 'off'): if busmode in ('on', 'off'):
self.nvda.speak(f'{label} {param} {busmode}') self.nvda.speak_and_braille(f'{label} {param} {busmode}')
else: else:
self.nvda.speak(f'{label} {busmode}') self.nvda.speak_and_braille(f'{label} {busmode}')
else: 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']]: case [['BUS', index], [param], ['KEY', 'SPACE' | 'ENTER']]:
if param == 'MODE': if param == 'MODE':
util.open_context_menu_for_buttonmenu(self, f'BUS {index}||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: if self.find_element_with_focus() is not None:
label = self.cache['labels'][f'BUS {index}||LABEL'] label = self.cache['labels'][f'BUS {index}||LABEL']
val = values[f'BUS {index}||SLIDER GAIN'] 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']]: case [['BUS', index], ['SLIDER', 'GAIN'], ['FOCUS', 'OUT']]:
pass pass
case [ case [
@ -1059,7 +1069,7 @@ class NVDAVMWindow(psg.Window):
val = util.check_bounds(val, (-60, 12)) val = util.check_bounds(val, (-60, 12))
self.vm.bus[int(index)].gain = val self.vm.bus[int(index)].gain = val
self[f'BUS {index}||SLIDER GAIN'].update(value=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: else:
self.vm.event.pdirty = True self.vm.event.pdirty = True
case [ case [
@ -1078,7 +1088,7 @@ class NVDAVMWindow(psg.Window):
val = util.check_bounds(val, (-60, 12)) val = util.check_bounds(val, (-60, 12))
self.vm.bus[int(index)].gain = val self.vm.bus[int(index)].gain = val
self[f'BUS {index}||SLIDER GAIN'].update(value=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: else:
self.vm.event.pdirty = True self.vm.event.pdirty = True
case [ case [
@ -1097,13 +1107,13 @@ class NVDAVMWindow(psg.Window):
val = util.check_bounds(val, (-60, 12)) val = util.check_bounds(val, (-60, 12))
self.vm.bus[int(index)].gain = val self.vm.bus[int(index)].gain = val
self[f'BUS {index}||SLIDER GAIN'].update(value=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: else:
self.vm.event.pdirty = True self.vm.event.pdirty = True
case [['BUS', index], ['SLIDER', 'GAIN'], ['KEY', 'CTRL', 'SHIFT', 'R']]: case [['BUS', index], ['SLIDER', 'GAIN'], ['KEY', 'CTRL', 'SHIFT', 'R']]:
self.vm.bus[int(index)].gain = 0 self.vm.bus[int(index)].gain = 0
self[f'BUS {index}||SLIDER GAIN'].update(value=0) self[f'BUS {index}||SLIDER GAIN'].update(value=0)
self.nvda.speak(str(0)) self.nvda.speak_and_braille(str(0))
# Unknown # Unknown
case _: case _: