diff --git a/pyproject.toml b/pyproject.toml index aecb192..9dbd663 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "nvda_voicemeeter" -version = "0.5.0" +version = "0.5.1a1" description = "A Voicemeeter app compatible with NVDA" authors = [ { name = "onyx-and-iris", email = "code@onyxandiris.online" }, diff --git a/src/nvda_voicemeeter/builder.py b/src/nvda_voicemeeter/builder.py index a441c23..674e05b 100644 --- a/src/nvda_voicemeeter/builder.py +++ b/src/nvda_voicemeeter/builder.py @@ -478,18 +478,26 @@ class Builder: """tab3 row represents bus composite toggle""" def add_strip_outputs(layout): - params = ["MONO", "EQ", "MUTE", "MODE"] + params = ["MONO", "EQ", "MUTE"] if self.vm.kind.name == "basic": params.remove("EQ") - label = {"MODE": "BUSMODE"} + busmodes = [util._bus_mode_map[mode] for mode in util.get_bus_modes(self.vm)] layout.append( [ - psg.Button( - label.get(param, param.capitalize()), - size=(12 if param == "MODE" else 6, 2), - key=f"BUS {i}||{param}", - ) - for param in params + *[ + psg.Button( + param.capitalize(), + size=(6, 2), + key=f"BUS {i}||{param}", + ) + for param in params + ], + psg.ButtonMenu( + "BUSMODE", + size=(12, 2), + menu_def=["", busmodes], + key=f"BUS {i}||MODE", + ), ] ) diff --git a/src/nvda_voicemeeter/util.py b/src/nvda_voicemeeter/util.py index 78f0fa6..23f4c84 100644 --- a/src/nvda_voicemeeter/util.py +++ b/src/nvda_voicemeeter/util.py @@ -111,6 +111,24 @@ def get_channel_identifier_list(vm) -> list: return identifiers +_bus_mode_map = { + "normal": "Normal", + "amix": "Mix Down A", + "bmix": "Mix Down B", + "repeat": "Stereo Repeat", + "composite": "Composite", + "tvmix": "Up Mix TV", + "upmix21": "Up Mix 2.1", + "upmix41": "Up Mix 4.1", + "upmix61": "Up Mix 6.1", + "centeronly": "Center Only", + "lfeonly": "Low Frequency Effect Only", + "rearonly": "Rear Only", +} + +_bus_mode_map_reversed = dict((reversed(item) for item in _bus_mode_map.items())) + + def get_bus_modes(vm) -> list: if vm.kind.name == "basic": return [ diff --git a/src/nvda_voicemeeter/window.py b/src/nvda_voicemeeter/window.py index 5fcfac1..1e9ce8b 100644 --- a/src/nvda_voicemeeter/window.py +++ b/src/nvda_voicemeeter/window.py @@ -57,6 +57,7 @@ class NVDAVMWindow(psg.Window): self[f"STRIP {i}||SLIDER LIMIT"].Widget.config(**slider_opts) for i in range(self.kind.num_bus): self[f"BUS {i}||SLIDER GAIN"].Widget.config(**slider_opts) + self[f"BUS {i}||MODE"].Widget.config(**buttonmenu_opts) if self.kind.name != "basic": for i in range(self.kind.phys_out): self[f"ASIO CHECKBOX||IN{i + 1} 0"].Widget.config(state="readonly") @@ -260,13 +261,16 @@ class NVDAVMWindow(psg.Window): self[f"STRIP {i}||SLIDER {param}"].bind("", "||KEY CTRL SHIFT R") # Bus Params - params = ["MONO", "EQ", "MUTE", "MODE"] + params = ["MONO", "EQ", "MUTE"] if self.vm.kind.name == "basic": params.remove("EQ") for i in range(self.kind.num_bus): for param in params: self[f"BUS {i}||{param}"].bind("", "||FOCUS IN") self[f"BUS {i}||{param}"].bind("", "||KEY ENTER") + self[f"BUS {i}||MODE"].bind("", "||FOCUS IN") + self[f"BUS {i}||MODE"].bind("", "||KEY SPACE", propagate=False) + self[f"BUS {i}||MODE"].bind("", "||KEY ENTER", propagate=False) # Bus Sliders for i in range(self.kind.num_bus): @@ -300,7 +304,7 @@ class NVDAVMWindow(psg.Window): self.logger.debug(f"values::{values}") if event in (psg.WIN_CLOSED, "Exit"): break - elif event.endswith("MODE"): + elif not event.startswith("BUS") and event.endswith("MODE"): mode = event self.nvda.speak(f"{mode} enabled") continue @@ -1002,40 +1006,27 @@ class NVDAVMWindow(psg.Window): "on" if val else "off", ) case "MODE": - bus_modes = util.get_bus_modes(self.vm) - next_index = bus_modes.index(val) + 1 - if next_index == len(bus_modes): - next_index = 0 - next_bus = bus_modes[next_index] - phonetic = { - "amix": "Mix Down A", - "bmix": "Mix Down B", - "repeat": "Stereo Repeat", - "tvmix": "Up Mix TV", - "upmix21": "Up Mix 2.1", - "upmix41": "Up Mix 4.1", - "upmix61": "Up Mix 6.1", - "centeronly": "Center Only", - "lfeonly": "Low Frequency Effect Only", - "rearonly": "Rear Only", - } - setattr(self.vm.bus[int(index)].mode, next_bus, True) - self.cache["bus"][event] = next_bus + chosen = util._bus_mode_map_reversed[values[event]] + setattr(self.vm.bus[int(index)].mode, chosen, True) + self.cache["bus"][event] = chosen self.TKroot.after( 200, self.nvda.speak, - phonetic.get(next_bus, next_bus), + util._bus_mode_map[chosen], ) case [["BUS", index], [param], ["FOCUS", "IN"]]: if self.find_element_with_focus() is not None: 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} {val}") + self.nvda.speak(f"{label} bus{param} {util._bus_mode_map[val]}") else: - self.nvda.speak(f"{label} bus {param} {'on' if val else 'off'}") + self.nvda.speak(f"{label} bus{param} {'on' if val else 'off'}") case [["BUS", index], [param], ["KEY", "ENTER"]]: - self.find_element_with_focus().click() + if param == "MODE": + util.open_context_menu_for_buttonmenu(self, f"BUS {index}||MODE") + else: + self.find_element_with_focus().click() # Bus Sliders case [["BUS", index], ["SLIDER", "GAIN"]]: