mirror of
https://github.com/onyx-and-iris/nvda-voicemeeter.git
synced 2026-04-18 23:33:31 +00:00
Compare commits
4 Commits
5b4a76c484
...
d54995dbf1
| Author | SHA1 | Date | |
|---|---|---|---|
| d54995dbf1 | |||
| bc0b25032a | |||
| 2a86c05bea | |||
| aae62fa136 |
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "nvda-voicemeeter"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
description = "A Voicemeeter app compatible with NVDA"
|
||||
authors = [{ name = "Onyx and Iris", email = "code@onyxandiris.online" }]
|
||||
dependencies = [
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
import ctypes as ct
|
||||
import platform
|
||||
import winreg
|
||||
from pathlib import Path
|
||||
|
||||
from .errors import NVDAVMError
|
||||
|
||||
BITS = 64 if ct.sizeof(ct.c_void_p) == 8 else 32
|
||||
try:
|
||||
import winreg
|
||||
except ImportError as e:
|
||||
ERR_MSG = 'winreg module not found, only Windows OS supported'
|
||||
raise NVDAVMError(ERR_MSG) from e
|
||||
|
||||
# Defense against edge cases where winreg imports but we're not on Windows
|
||||
if platform.system() != 'Windows':
|
||||
raise NVDAVMError('Only Windows OS supported')
|
||||
|
||||
BITS = 64 if ct.sizeof(ct.c_void_p) == 8 else 32
|
||||
|
||||
REG_KEY = '\\'.join(
|
||||
filter(
|
||||
None,
|
||||
@@ -43,4 +49,4 @@ if not controller_path.exists():
|
||||
|
||||
DLL_PATH = controller_path / f'x{64 if BITS == 64 else 86}' / 'nvdaControllerClient.dll'
|
||||
|
||||
libc = ct.CDLL(str(DLL_PATH))
|
||||
libc = ct.WinDLL(str(DLL_PATH))
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
from enum import IntEnum
|
||||
|
||||
from .cdll import libc
|
||||
from .errors import NVDAVMCAPIError
|
||||
|
||||
|
||||
class ServerState(IntEnum):
|
||||
RUNNING = 0
|
||||
UNAVAILABLE = 1722
|
||||
|
||||
|
||||
class CBindings:
|
||||
bind_test_if_running = libc.nvdaController_testIfRunning
|
||||
bind_speak_text = libc.nvdaController_speakText
|
||||
@@ -18,7 +25,10 @@ class CBindings:
|
||||
class Nvda(CBindings):
|
||||
@property
|
||||
def is_running(self):
|
||||
return self.call(self.bind_test_if_running) == 0
|
||||
return (
|
||||
self.call(self.bind_test_if_running, ok=(ServerState.RUNNING, ServerState.UNAVAILABLE))
|
||||
== ServerState.RUNNING
|
||||
)
|
||||
|
||||
def speak(self, text):
|
||||
self.call(self.bind_speak_text, text)
|
||||
|
||||
@@ -35,7 +35,7 @@ class Popup:
|
||||
self.logger.debug(f'values::{values}')
|
||||
if event in (psg.WIN_CLOSED, 'Cancel'):
|
||||
break
|
||||
match parsed_cmd := self.window.parser.match.parseString(event):
|
||||
match parsed_cmd := self.window.parser.match.parse_string(event):
|
||||
case [[button], ['FOCUS', 'IN']]:
|
||||
if values['Browse']:
|
||||
filepath = values['Browse']
|
||||
@@ -105,7 +105,7 @@ class Popup:
|
||||
self.logger.debug(f'values::{values}')
|
||||
if event in (psg.WIN_CLOSED, 'Cancel'):
|
||||
break
|
||||
match parsed_cmd := self.window.parser.match.parseString(event):
|
||||
match parsed_cmd := self.window.parser.match.parse_string(event):
|
||||
case [[button], ['FOCUS', 'IN']]:
|
||||
self.window.nvda.speak(button)
|
||||
case [_, ['KEY', 'ENTER']]:
|
||||
@@ -227,7 +227,7 @@ class Popup:
|
||||
self.logger.debug(f'values::{values}')
|
||||
if event in (psg.WIN_CLOSED, 'Exit'):
|
||||
break
|
||||
match parsed_cmd := self.window.parser.match.parseString(event):
|
||||
match parsed_cmd := self.window.parser.match.parse_string(event):
|
||||
case [['ASIO', 'INPUT', 'SPINBOX'], [in_num, channel]]:
|
||||
index = util.get_asio_input_spinbox_index(int(channel), int(in_num[-1]))
|
||||
val = values[f'ASIO INPUT SPINBOX||{in_num} {channel}']
|
||||
@@ -331,7 +331,7 @@ class Popup:
|
||||
self.logger.debug(f'values::{values}')
|
||||
if event in (psg.WIN_CLOSED, 'Exit'):
|
||||
break
|
||||
match parsed_cmd := self.window.parser.match.parseString(event):
|
||||
match parsed_cmd := self.window.parser.match.parse_string(event):
|
||||
case [['COMPRESSOR'], ['SLIDER', param]]:
|
||||
setattr(self.window.vm.strip[index].comp, param.lower(), values[event])
|
||||
case [['COMPRESSOR'], ['SLIDER', param], ['FOCUS', 'IN']]:
|
||||
@@ -661,7 +661,7 @@ class Popup:
|
||||
self.logger.debug(f'values::{values}')
|
||||
if event in (psg.WIN_CLOSED, 'Exit'):
|
||||
break
|
||||
match parsed_cmd := self.window.parser.match.parseString(event):
|
||||
match parsed_cmd := self.window.parser.match.parse_string(event):
|
||||
case [['GATE'], ['SLIDER', param]]:
|
||||
setattr(self.window.vm.strip[index].gate, param.lower(), values[event])
|
||||
case [['GATE'], ['SLIDER', param], ['FOCUS', 'IN']]:
|
||||
|
||||
@@ -6,6 +6,7 @@ import FreeSimpleGUI as psg
|
||||
|
||||
from . import configuration, models, util
|
||||
from .builder import Builder
|
||||
from .errors import NVDAVMError
|
||||
from .nvda import Nvda
|
||||
from .parser import Parser
|
||||
from .popup import Popup
|
||||
@@ -25,6 +26,10 @@ class NVDAVMWindow(psg.Window):
|
||||
self.kind = self.vm.kind
|
||||
self.logger = logger.getChild(type(self).__name__)
|
||||
self.logger.debug(f'loaded with theme: {psg.theme()}')
|
||||
self.nvda = Nvda()
|
||||
if not self.nvda.is_running:
|
||||
self.logger.error('NVDA is not running. Exiting...')
|
||||
raise NVDAVMError('NVDA is not running')
|
||||
self.cache = {
|
||||
'hw_ins': models._make_hardware_ins_cache(self.vm),
|
||||
'hw_outs': models._make_hardware_outs_cache(self.vm),
|
||||
@@ -34,7 +39,6 @@ class NVDAVMWindow(psg.Window):
|
||||
'asio': models._make_patch_asio_cache(self.vm),
|
||||
'insert': models._make_patch_insert_cache(self.vm),
|
||||
}
|
||||
self.nvda = Nvda()
|
||||
self.parser = Parser()
|
||||
self.popup = Popup(self)
|
||||
self.builder = Builder(self)
|
||||
|
||||
Reference in New Issue
Block a user