Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remote Access #17580

Merged
merged 207 commits into from
Mar 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
207 commits
Select commit Hold shift + click to select a range
e483ed1
Add NVDA Remote functionality to core NVDA
ctoth Dec 24, 2024
3d38ad2
Fix failed certificate callback
ctoth Dec 27, 2024
e0a8946
refactor: simplify remote speech handling using extension points
ctoth Dec 28, 2024
4b7eac9
Warn, not error for unknown message types
ctoth Dec 28, 2024
927d4f1
refactor: remove NVDA patcher system and integrate braille handling d…
ctoth Dec 28, 2024
77366a0
Remove unused `CallbackManager` and patcher modules
ctoth Dec 28, 2024
258106d
Improve logic for callback registration
ctoth Dec 28, 2024
ced7345
fix: prevent duplicate callback registration and improve callback lif…
ctoth Dec 28, 2024
afa53b3
Improve logging
ctoth Dec 28, 2024
1378815
Add missing @alwaysCallAfter decorators
ctoth Dec 28, 2024
1820d93
Fix braille input
ctoth Dec 29, 2024
7ac87d3
feat(remoteClient): add TypedDict for PortCheckResponse
ctoth Dec 29, 2024
542c174
Fix translator note comment
ctoth Dec 29, 2024
aaa5428
refactor: migrate remote config to use main config system (#350)
ctoth Dec 29, 2024
d8cb51c
refactor: Remote Client: Ensure consistent feedback for deafblind users
ctoth Dec 29, 2024
8f6cf6f
Naming and typing fixes
ctoth Dec 29, 2024
2aaa3ea
Add `pre_speechQueued` to the table of extension points and export it…
ctoth Dec 29, 2024
1d26a7e
docs: add remote access documentation to user guide
ctoth Dec 29, 2024
d7ed00e
feat(remoteClient): make RemoteMenu conditional on secure desktop status
ctoth Dec 29, 2024
a230d8a
feat: block remote connection actions in secure mode and rename for c…
ctoth Dec 29, 2024
14c208f
Use playWaveFile directly for remote sounds
ctoth Dec 29, 2024
3147cf8
Fix secure desktop check
ctoth Dec 29, 2024
2f474ef
Don't write config after receiving MOTD
ctoth Dec 29, 2024
14468e3
Add .wav suffix to cues
ctoth Dec 29, 2024
c9a0a38
Better handle wave files
ctoth Dec 29, 2024
1541727
Added Remote Certificate Manager to self-sign certificates for the bu…
ctoth Dec 31, 2024
0a62d5d
Add cryptography dependency to requirements.txt
ctoth Dec 31, 2024
3cc3c42
Hidden import of CFFI to satisfy py2exe per pyca/cryptography#5122
ctoth Dec 31, 2024
d0ee2bb
security: Improve certificate handling for self-hosted remote connect…
ctoth Jan 3, 2025
aa2f6e5
fix: Update SSL socket configuration and connection settings
ctoth Jan 3, 2025
ed1fba9
fix: Change localhost binding from IP to hostname in secure desktop r…
ctoth Jan 4, 2025
a1cc380
feat: Add comprehensive logging to SecureDesktopHandler module
ctoth Jan 4, 2025
94e12e4
feat: Add comprehensive logging to server module for improved monitor…
ctoth Jan 4, 2025
f40eade
refactor: Replace localhost with 127.0.0.1 and remove SSL socket wrap…
ctoth Jan 4, 2025
b2ee2d2
refactor: Simplify logging and formatting in server and secureDesktop…
ctoth Jan 4, 2025
f620309
Use the Enum's value
ctoth Jan 4, 2025
75190d5
Remove old static certificate
ctoth Jan 4, 2025
9f6fbad
Ch-ch-ch-ch-changes
ctoth Jan 4, 2025
ec5f2d3
Braille secure desktop fix
ctoth Jan 4, 2025
1c1511e
Better logging
ctoth Jan 5, 2025
536f250
Use enum
ctoth Jan 5, 2025
f89daf4
Fix logging in server module
ctoth Jan 5, 2025
1ca2b34
We don't need to register these Braille callbacks for anything but th…
ctoth Jan 5, 2025
f04591b
fix: Enforce TLS 1.2 minimum version for secure socket connections
ctoth Jan 5, 2025
7589838
Include reference to PR in changelog.
ctoth Jan 5, 2025
78bd453
fix: Update SSL context configuration for TLS 1.2 protocol
ctoth Jan 5, 2025
ccd466d
refactor: Rename variables and methods to follow camelCase convention
ctoth Jan 12, 2025
4970137
Unmute remote speech when controlling the remote machine
ctoth Jan 12, 2025
dc43343
Added support for TOR hidden services (.onion addresses) per nvdaremo…
ctoth Jan 12, 2025
cffd9d8
Update docs
ctoth Jan 13, 2025
f8a7e11
Move contents of `socket_utils` into `protocol` module
ctoth Jan 13, 2025
ff3be26
Camel-case input module
ctoth Jan 13, 2025
d41ac91
Add copyright notices to all remote modules
ctoth Jan 16, 2025
0d0859f
connection_info -> connectionInfo
ctoth Jan 16, 2025
742f1f8
refactor: Add ABCMeta to Serializer for abstract base class definition
ctoth Jan 16, 2025
fb58036
globalVars.remoteClient -> remoteClient.client per review
ctoth Jan 18, 2025
23317c1
remoteClient: Rename global 'client' variable to 'remoteClient'
ctoth Jan 23, 2025
f6f7da8
refactor(bridge): use RemoteMessageType enum for excluded messages
ctoth Jan 23, 2025
a62a94f
refactor: switch to StrEnum for connection enums
ctoth Jan 23, 2025
bdad80a
Standardize clipboard wave file naming per review
ctoth Jan 23, 2025
b12bfd4
Move alwaysCallAfter decorator to guiHelper module
ctoth Jan 23, 2025
39f9ff3
Handle cases where the client is called (for instance by a gesture) a…
ctoth Jan 23, 2025
68a1ebf
Update anchor
ctoth Jan 23, 2025
3244d0b
Update Remote menu documentation
ctoth Jan 25, 2025
cd2be77
Update version mismatch error
ctoth Jan 25, 2025
2a17049
refactor: Simplify Remote URL handling via slave + NVDA helper
ctoth Jan 26, 2025
ea4dd51
Add handleRemoteURL interface to nvdaControllerInternal
ctoth Jan 27, 2025
654ce8d
Add handleRemoteURL function to nvdaControllerInternal
ctoth Jan 27, 2025
0e352a5
refactor: Move beepSequence functionality to tones.py
ctoth Jan 27, 2025
2b6af90
camel-case URL Handler
ctoth Jan 27, 2025
e736fb0
Update remote toggle gesture to NVDA+F11
ctoth Jan 28, 2025
7102dda
Migrate remote settings into main config file
ctoth Jan 28, 2025
ac92db4
Update Docstring
ctoth Jan 29, 2025
99a154c
Remove unnecessary import
ctoth Jan 29, 2025
6a387f9
Log when no remote.ini is found
ctoth Jan 29, 2025
f0170df
Document mode in confspec
ctoth Jan 29, 2025
f564a08
Add min/max to mode
ctoth Jan 29, 2025
399975c
Already Connected message
ctoth Jan 29, 2025
07e9f92
fix message
ctoth Jan 29, 2025
9058dc3
Add docs and types to remoteClient.connectionInfo
ctoth Jan 29, 2025
1a37d36
Copyright headers
ctoth Jan 29, 2025
12baa5b
camelCase settings attributes
ctoth Jan 29, 2025
8b5d913
Remove trailing whitespace from nvdaControllerInternal_handleRemoteUR…
ctoth Jan 29, 2025
3fd0ce8
Upcase `RemoteConnectionType` enum constants and add types and docstr…
ctoth Jan 29, 2025
97942f9
Use f-string for ipv6
ctoth Jan 29, 2025
715dbe2
f-string for host:port
ctoth Jan 29, 2025
530dfb9
Improve transport guard
ctoth Jan 31, 2025
b47c258
Improve filter guard
ctoth Jan 31, 2025
fe7b4a4
Update copy link script
ctoth Jan 31, 2025
8307fca
docs: Update documentation to Sphinx-style docstrings
ctoth Jan 31, 2025
63543f2
docs: Update docstrings to use Sphinx-style formatting
ctoth Jan 31, 2025
3fa9992
Use dict and set typing directly
ctoth Jan 31, 2025
3f01593
f-string
ctoth Jan 31, 2025
c5f9298
Sphinx-style docs for `LocalMachine`
ctoth Jan 31, 2025
2240854
URL Handler casing
ctoth Feb 1, 2025
02f6c5c
Serializer Docstrings and import organization
ctoth Feb 1, 2025
6f06127
f-string
ctoth Feb 1, 2025
730ed6d
Camel-case cues
ctoth Feb 1, 2025
fcab4c2
f-string
ctoth Feb 1, 2025
c579ac1
f-string
ctoth Feb 1, 2025
54389b0
Improve docs
ctoth Feb 1, 2025
a9e4e58
refactor: Update type hints to use modern Python syntax
ctoth Feb 1, 2025
9aef15b
refactor: Update type hints for TCPTransport methods
ctoth Feb 1, 2025
bd44223
Naming and casing
ctoth Feb 1, 2025
0c8e632
Script naming
ctoth Feb 1, 2025
ad93804
Script naming
ctoth Feb 1, 2025
b41ddf2
f-string
ctoth Feb 1, 2025
4ca4181
Fix session imports
ctoth Feb 1, 2025
28f6e25
Fix version mismatch log
ctoth Feb 1, 2025
9a03336
F-string
ctoth Feb 2, 2025
ddcf880
refactor: improve type hints and documentation
ctoth Feb 2, 2025
bb1653d
Rename handleChannel_joined to handleChannelJoined
ctoth Feb 2, 2025
02d8fe4
Typing for script gesture
ctoth Feb 2, 2025
cb188f1
Standardizing sphinx-style docs
ctoth Feb 2, 2025
92ff5b0
camel-case process_key_input
ctoth Feb 2, 2025
d7b75d5
Docs and typing for transport and session
ctoth Feb 2, 2025
0c0df36
Sphinx-style docs for `RelayTransport`
ctoth Feb 2, 2025
79ad5d9
Docstring update
ctoth Feb 3, 2025
387a91d
Better typing for URL Handler
ctoth Feb 3, 2025
a516090
Fix registry handler type annotations and variable naming in url handler
ctoth Feb 3, 2025
79ef0f9
refactor: standardize naming conventions and type hints in RemoteClie…
ctoth Feb 3, 2025
5410b99
secureDesktop: Create dedicated NVDA directory for IPC files
ctoth Feb 3, 2025
5714783
Sphinx-style docs for server
ctoth Feb 3, 2025
e489eef
Apply feedback from server review
ctoth Feb 3, 2025
45886f8
refactor: Improve type hints and client ID generation
ctoth Feb 3, 2025
31f0292
Add explanatory comment
ctoth Feb 3, 2025
d7a2849
refactor: modernize type hints in remoteClient server
ctoth Feb 3, 2025
d24fca5
Add message if sending clipboard fails
ctoth Feb 4, 2025
dfa9d7e
Proper method to get temp path
ctoth Feb 4, 2025
0467889
docs: improve secure desktop module documentation
ctoth Feb 4, 2025
0880a78
Mark the global `RemoteClient` reference as private
ctoth Feb 6, 2025
0c74ae3
tests: Add comprehensive unit tests for remote client functionality
ctoth Feb 10, 2025
067d340
Renamed remoteClient.session.SlaveSession to remoteClient.session.Fol…
SaschaCowley Feb 11, 2025
c7dad5b
Renamed slaveSession to followerSession on remoteClient.client.Remote…
SaschaCowley Feb 11, 2025
5d0dfd1
Renamed remoteClient.session.MasterSession to remoteClient.session.Le…
SaschaCowley Feb 11, 2025
ab6fbd7
Renamed slaveTransport to followerTransport in remoteClient.client.Re…
SaschaCowley Feb 11, 2025
23cb747
Renamed masterTransport to leaderTransport in remoteClient.client.Rem…
SaschaCowley Feb 11, 2025
f387125
Renamed disconnectAsMaster to disconnectAsLeader in remoteClient.clie…
SaschaCowley Feb 11, 2025
5378f72
Renamed disconnectAsSlave to disconnectAsFollower in remoteClient.cli…
SaschaCowley Feb 11, 2025
70f95ba
Renamed onConnectAsMasterFailed to onConnectAsLeaderFailed in remoteC…
SaschaCowley Feb 11, 2025
1540e24
Renamed connectAsMaster to connectAsLeader in remoteClient.client.Rem…
SaschaCowley Feb 11, 2025
3aede4b
Renamed onConnectedAsMaster to onConnectedAsLeader in remoteClient.cl…
SaschaCowley Feb 11, 2025
ac72298
Renamed onDisconnectingAsMaster to onDisconnectingAsLeader in remoteC…
SaschaCowley Feb 11, 2025
ba2425d
Renamed onDisconnectedAsMaster to onDisconnectedAsLeader in remoteCli…
SaschaCowley Feb 11, 2025
d813d1e
Renamed connectAsSlave to connectAsFollower in remoteClient.client.Re…
SaschaCowley Feb 11, 2025
81ef31b
Renamed onConnectedAsSlave to onConnectedAsFollower in remoteClient.c…
SaschaCowley Feb 11, 2025
3e5f1b3
Renamed onDisconnectedAsSlave to onDisconnectedAsFollower in remoteCl…
SaschaCowley Feb 11, 2025
32dbf6b
Renamed onMasterCertificateFailed to onLeaderCertificateFailed in rem…
SaschaCowley Feb 11, 2025
2e557b0
Renamed onSlaveCertificateFailed to onFollowerCertificateFailed in re…
SaschaCowley Feb 11, 2025
41b03d4
Renamed ConnectionMode.MASTER to ConnectionMode.LEADER in remoteClien…
SaschaCowley Feb 11, 2025
68ef128
Renamed ConnectionMode.SLAVE to ConnectionMode.FOLLOWER in remoteClie…
SaschaCowley Feb 11, 2025
8ecc6d0
Renamed _onMasterDisplayChange to _onLeaderDisplayChange in remoteCli…
SaschaCowley Feb 11, 2025
bbb07a2
Renamed masters to leaders in remoteClient.session.FollowerSession
SaschaCowley Feb 11, 2025
576b68e
Renamed masterDisplaySizes to leaderDisplaySizes in remoteClient.sess…
SaschaCowley Feb 11, 2025
6c8c714
Renamed hasBrailleMasters to hasBrailleLeaders in remoteClient.sessio…
SaschaCowley Feb 11, 2025
8071eeb
Move remote tests into test_remote folder
ctoth Feb 11, 2025
8b1d834
Renamed slaves to followers in remoteClient.session.LeaderSession
SaschaCowley Feb 11, 2025
f74a781
Replaced instances of master with leader in comments, docstrings and …
SaschaCowley Feb 11, 2025
c14c858
Replaced instances of slave with follower in comments, docstrings and…
SaschaCowley Feb 11, 2025
8af09b8
Renamed hasSlaves to hasFollowers in remoteClient.session.LeaderSessi…
SaschaCowley Feb 11, 2025
fe5f0dd
Fixed more comments
SaschaCowley Feb 11, 2025
baf65f1
Replaced hardcoded "master" and "slave" with ConnectionMode.LEADER an…
SaschaCowley Feb 11, 2025
d26187c
Replaced hardcoded "master" with ConnectionMode.LEADER in handleClie…
SaschaCowley Feb 11, 2025
937dc7f
Replaced existing instances of master and slave with leader and follo…
SaschaCowley Feb 11, 2025
8dd7554
Merge branch 'remote' into removeMasterSlave
SaschaCowley Feb 14, 2025
9e01097
Merge pull request #1 from nvda-art/removeMasterSlave
ctoth Feb 15, 2025
dfbbbec
Update copyright headers
SaschaCowley Feb 24, 2025
0215cf9
Fixed some type hints
SaschaCowley Feb 24, 2025
44ccf1f
Improved type hints for alwaysCallAfter
SaschaCowley Feb 24, 2025
a0e48f3
Fix issues in settings dialogs
SaschaCowley Feb 24, 2025
b19f716
Fixes to client
SaschaCowley Feb 24, 2025
0c06432
Improvements in connection info
SaschaCowley Feb 24, 2025
0b8f0e1
Typing and documentation fixes in bridge
SaschaCowley Feb 24, 2025
3ed56fa
Fixes to dialogs
SaschaCowley Feb 24, 2025
9c5f5c0
Fix some issues in dialogs
SaschaCowley Feb 24, 2025
d55f9d9
Typing and documentation fixes to input
SaschaCowley Feb 24, 2025
8260b8b
Documentation improvements in local machine
SaschaCowley Feb 24, 2025
e008763
Code clean-up in menu and serializer
SaschaCowley Feb 24, 2025
4a04794
Fixes to server
SaschaCowley Feb 24, 2025
32d1711
Clean up in session
SaschaCowley Feb 24, 2025
7a4f270
Misc clean-up
SaschaCowley Feb 24, 2025
12f4654
Applied suggestions in server
SaschaCowley Feb 25, 2025
5df5771
Added manual testing instructions of remote feature to tests/manual/r…
daiverd Feb 25, 2025
c2b4daf
Fixes to transport
SaschaCowley Feb 25, 2025
b61601e
Extract global variable
SaschaCowley Feb 25, 2025
458f1b7
Improvements to user guide
SaschaCowley Feb 25, 2025
671c078
Merge branch 'remote' of https://github.com/nvda-art/nvda into remote
SaschaCowley Feb 25, 2025
cb0586c
refactor: Improve transport run method
ctoth Mar 1, 2025
ea2243c
refactor: narrow type annotation for transport.send() to only accept …
ctoth Mar 1, 2025
a41edc4
Remove early return in cues preventing message
ctoth Mar 1, 2025
2415c32
rename and camel-case
ctoth Mar 1, 2025
2ff8d3c
Remove unused local_beep
ctoth Mar 1, 2025
dbbd4c2
Improve handleCertificateFailed method documentation and error handling
ctoth Mar 2, 2025
e879c2f
Fix logging port
ctoth Mar 2, 2025
2f85daa
refactor(server): clarify socket listen backlog parameter
ctoth Mar 4, 2025
1f4eeaf
Improve code clarity and documentation in remote client code
ctoth Mar 4, 2025
3eee73a
Remove unused logging from url handler
ctoth Mar 4, 2025
ad6e912
Fixed several instances of snake_case
SaschaCowley Mar 5, 2025
c5a2416
Change to disconnected
SaschaCowley Mar 5, 2025
b95b615
Made select timeout a constant
SaschaCowley Mar 5, 2025
96ef469
Update local relay server certificate
SaschaCowley Mar 7, 2025
d8793f4
Update changes
SaschaCowley Mar 7, 2025
320365b
Merge branch 'master' into remote
SaschaCowley Mar 7, 2025
a758b58
lint fixes to Remote manual test plan
SaschaCowley Mar 7, 2025
4cf3785
minor updates to tests
SaschaCowley Mar 7, 2025
8ccb259
Make some constants enums and document where they come from
SaschaCowley Mar 7, 2025
759cfd3
Fixed name of RemoteMessageType.PING
SaschaCowley Mar 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This file is a part of the NVDA project.
URL: http://www.nvda-project.org/
Copyright 2006-2010 NVDA contributers.
Copyright 2006-2025 NVDA contributers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2.0, as published by
the Free Software Foundation.
Expand All @@ -23,6 +23,7 @@ interface NvdaControllerInternal {
[fault_status,comm_status] logMessage();
[fault_status,comm_status] vbufChangeNotify();
[fault_status,comm_status] installAddonPackageFromPath();
[fault_status,comm_status] handleRemoteURL();
[fault_status,comm_status] drawFocusRectNotify();
[fault_status,comm_status] reportLiveRegion();
[fault_status,comm_status] openConfigDirectory();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This file is a part of the NVDA project.
URL: http://www.nvda-project.org/
Copyright 2006-2018 NV Access Limited, rui Batista, Google LLC.
Copyright 2006-2025 NV Access Limited, rui Batista, Google LLC, Christopher Toth.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2.0, as published by
the Free Software Foundation.
Expand Down Expand Up @@ -102,4 +102,10 @@ interface NvdaControllerInternal {
* Asks NVDA to open currently used configuration directory.
*/
error_status_t __stdcall openConfigDirectory();

/**
* Handles a remote URL request from the slave process.
* @param url The nvdaremote:// URL to process.
*/
error_status_t __stdcall handleRemoteURL([in,string] const wchar_t* url);
};
7 changes: 6 additions & 1 deletion nvdaHelper/local/nvdaControllerInternal.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This file is a part of the NVDA project.
URL: http://www.nvda-project.org/
Copyright 2006-2018 NV Access Limited, rui Batista, Google LLC.
Copyright 2006-2025 NV Access Limited, rui Batista, Google LLC, Christopher Toth.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2.0, as published by
the Free Software Foundation.
Expand Down Expand Up @@ -70,6 +70,11 @@ error_status_t __stdcall nvdaControllerInternal_installAddonPackageFromPath(cons
return _nvdaControllerInternal_installAddonPackageFromPath(addonPath);
}

error_status_t(__stdcall *_nvdaControllerInternal_handleRemoteURL)(const wchar_t*);
error_status_t __stdcall nvdaControllerInternal_handleRemoteURL(const wchar_t* url) {
return _nvdaControllerInternal_handleRemoteURL(url);
}

error_status_t(__stdcall *_nvdaControllerInternal_drawFocusRectNotify)(const long, const long, const long, const long, const long);
error_status_t __stdcall nvdaControllerInternal_drawFocusRectNotify(const long hwnd, const long left, const long top, const long right, const long bottom) {
return _nvdaControllerInternal_drawFocusRectNotify(hwnd,left,top,right,bottom);
Expand Down
1 change: 1 addition & 0 deletions nvdaHelper/local/nvdaHelperLocal.def
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ EXPORTS
_nvdaControllerInternal_logMessage
_nvdaControllerInternal_typedCharacterNotify
_nvdaControllerInternal_installAddonPackageFromPath
_nvdaControllerInternal_handleRemoteURL
_nvdaControllerInternal_drawFocusRectNotify
_nvdaController_brailleMessage
_nvdaController_cancelSpeech
Expand Down
1 change: 1 addition & 0 deletions nvdaHelper/remote/nvdaHelperRemote.def
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ EXPORTS
nvdaControllerInternal_logMessage
nvdaControllerInternal_vbufChangeNotify
nvdaControllerInternal_installAddonPackageFromPath
nvdaControllerInternal_handleRemoteURL
nvdaController_testIfRunning
nvdaController_speakText
nvdaController_cancelSpeech
Expand Down
1 change: 1 addition & 0 deletions projectDocs/dev/developerGuide/developerGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -1384,6 +1384,7 @@ For examples of how to define and use new extension points, please see the code
|`Action` |`pre_speechCanceled` |Triggered before speech is canceled.|
|`Action` |`pre_speech` |Triggered before NVDA handles prepared speech.|
|`Action` |`post_speechPaused` |Triggered when speech is paused or resumed.|
|`Action` |`pre_speechQueued` |Triggered after speech is processed and normalized and directly before it is enqueued.|
|`Filter` |`filter_speechSequence` |Allows components or add-ons to filter speech sequence before it passes to the synth driver.|

### synthDriverHandler {#synthDriverHandlerExtPts}
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ SCons==4.8.1

# NVDA's runtime dependencies
comtypes==1.4.6
cryptography==44.0.0
pyserial==3.5
wxPython==4.2.2
configobj @ git+https://github.com/DiffSK/configobj@8be54629ee7c26acb5c865b74c76284e80f3aa31#egg=configobj
Expand Down
28 changes: 27 additions & 1 deletion source/NVDAHelper.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# A part of NonVisual Desktop Access (NVDA)
# Copyright (C) 2008-2023 NV Access Limited, Peter Vagner, Davy Kager, Mozilla Corporation, Google LLC,
# Copyright (C) 2008-2025 NV Access Limited, Peter Vagner, Davy Kager, Mozilla Corporation, Google LLC,
# Leonard de Ruijter
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.
Expand Down Expand Up @@ -687,6 +687,31 @@ def nvdaControllerInternal_openConfigDirectory():
return 0


@WINFUNCTYPE(c_long, c_wchar_p)
def nvdaControllerInternal_handleRemoteURL(url):
"""Handles a remote URL request from the slave process.

:param url: The nvdaremote:// URL to process
:return: 0 on success, -1 on failure
"""
from remoteClient import connectionInfo, _remoteClient as client

try:
if not client:
log.error("No RemoteClient instance available")
return -1
# Queue the URL handling on the main thread
queueHandler.queueFunction(
queueHandler.eventQueue,
client.verifyAndConnect,
connectionInfo.ConnectionInfo.fromURL(url),
)
return 0
except Exception:
log.error("Error handling remote URL", exc_info=True)
return -1


class _RemoteLoader:
def __init__(self, loaderDir: str):
# Create a pipe so we can write to stdin of the loader process.
Expand Down Expand Up @@ -776,6 +801,7 @@ def initialize() -> None:
),
("nvdaControllerInternal_drawFocusRectNotify", nvdaControllerInternal_drawFocusRectNotify),
("nvdaControllerInternal_openConfigDirectory", nvdaControllerInternal_openConfigDirectory),
("nvdaControllerInternal_handleRemoteURL", nvdaControllerInternal_handleRemoteURL),
]:
try:
_setDllFuncPointer(localLib, "_%s" % name, func)
Expand Down
3 changes: 2 additions & 1 deletion source/config/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# A part of NonVisual Desktop Access (NVDA)
# Copyright (C) 2006-2024 NV Access Limited, Aleksey Sadovoy, Peter Vágner, Rui Batista, Zahari Yurukov,
# Copyright (C) 2006-2025 NV Access Limited, Aleksey Sadovoy, Peter Vágner, Rui Batista, Zahari Yurukov,
# Joseph Lee, Babbage B.V., Łukasz Golonka, Julien Cochuyt, Cyrille Bougot
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.
Expand Down Expand Up @@ -526,6 +526,7 @@ class ConfigManager(object):
"update",
"development",
"addonStore",
"remote",
}
"""
Sections that only apply to the base configuration;
Expand Down
20 changes: 19 additions & 1 deletion source/config/configSpec.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#: provide an upgrade step (@see profileUpgradeSteps.py). An upgrade step does not need to be added when
#: just adding a new element to (or removing from) the schema, only when old versions of the config
#: (conforming to old schema versions) will not work correctly with the new schema.
latestSchemaVersion = 15
latestSchemaVersion = 16

#: The configuration specification string
#: @type: String
Expand Down Expand Up @@ -344,6 +344,24 @@
# UpdateChannel values:
# same channel (default), any channel, do not update, stable, beta & dev, beta, dev
defaultUpdateChannel = integer(0, 6, default=0)

# Remote Settings
[remote]
[[connections]]
last_connected = list(default=list())
[[controlserver]]
autoconnect = boolean(default=False)
self_hosted = boolean(default=False)
connection_type = integer(default=0, min=0, max=1) # 0: follower, 1: leader
host = string(default="")
port = integer(default=6837)
key = string(default="")
[[seen_motds]]
__many__ = string(default="")
[[trusted_certs]]
__many__ = string(default="")
[[ui]]
play_sounds = boolean(default=True)
"""

#: The configuration specification
Expand Down
50 changes: 44 additions & 6 deletions source/config/profileUpgradeSteps.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,22 @@
that no information is lost, while updating the ConfigObj to meet the requirements of the new schema.
"""

import os

import configobj.validate
from configobj import ConfigObj
from logHandler import log

from config.configFlags import (
NVDAKey,
ShowMessages,
TetherTo,
OutputMode,
ReportCellBorders,
ReportLineIndentation,
ReportTableHeaders,
ReportCellBorders,
OutputMode,
ShowMessages,
TetherTo,
TypingEcho,
)
import configobj.validate
from configobj import ConfigObj


def upgradeConfigFrom_0_to_1(profile: ConfigObj) -> None:
Expand Down Expand Up @@ -500,3 +503,38 @@ def _convertTypingEcho(profile: ConfigObj, key: str) -> None:
newValue = TypingEcho.EDIT_CONTROLS.value if oldValue else TypingEcho.OFF.value
profile["keyboard"][key] = newValue
log.debug(f"Converted '{key}' from {oldValue!r} to {newValue} ({TypingEcho(newValue).name}).")


def upgradeConfigFrom_15_to_16(profile: ConfigObj) -> None:
"""Migrate remote.ini settings into the main config."""
remoteIniPath = os.path.join(os.path.dirname(profile.filename), "remote.ini")
if not os.path.isfile(remoteIniPath):
log.debug(f"No remote.ini found, no action taken. Checked {remoteIniPath}")
return

try:
remoteConfig = ConfigObj(remoteIniPath, encoding="UTF-8")
log.debug(f"Loading remote config from {remoteIniPath}")
except Exception:
log.error("Error loading remote.ini", exc_info=True)
return

# Create remote section if it doesn't exist
if "remote" not in profile:
profile["remote"] = {}

# Copy all sections from remote.ini
for section in remoteConfig:
if section not in profile["remote"]:
profile["remote"][section] = {}
profile["remote"][section].update(remoteConfig[section])

try:
# Backup the old file just in case
backupPath = remoteIniPath + ".old"
if os.path.exists(backupPath):
os.unlink(backupPath)
os.rename(remoteIniPath, backupPath)
log.debug(f"Backed up remote.ini to {backupPath}")
except Exception:
log.error("Error backing up remote.ini after migration", exc_info=True)
9 changes: 8 additions & 1 deletion source/core.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# A part of NonVisual Desktop Access (NVDA)
# Copyright (C) 2006-2024 NV Access Limited, Aleksey Sadovoy, Christopher Toth, Joseph Lee, Peter Vágner,
# Copyright (C) 2006-2025 NV Access Limited, Aleksey Sadovoy, Christopher Toth, Joseph Lee, Peter Vágner,
# Derek Riemer, Babbage B.V., Zahari Yurukov, Łukasz Golonka, Cyrille Bougot, Julien Cochuyt
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.
Expand Down Expand Up @@ -897,6 +897,12 @@ def main():

log.debug("Initializing global plugin handler")
globalPluginHandler.initialize()

log.debug("Initializing remote client")
import remoteClient

remoteClient.initialize()

if globalVars.appArgs.install or globalVars.appArgs.installSilent:
import gui.installerGui

Expand Down Expand Up @@ -1049,6 +1055,7 @@ def _doPostNvdaStartupAction():
" This likely indicates NVDA is exiting due to WM_QUIT.",
)
queueHandler.pumpAll()
_terminate(remoteClient)
_terminate(gui)
config.saveOnExit()

Expand Down
70 changes: 69 additions & 1 deletion source/globalCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
import audio
from audio import appsVolume
from utils.displayString import DisplayStringEnum

import remoteClient

#: Script category for text review commands.
# Translators: The name of a category of NVDA commands.
Expand Down Expand Up @@ -121,6 +121,9 @@
#: Script category for audio streaming commands.
# Translators: The name of a category of NVDA commands.
SCRCAT_AUDIO = _("Audio")
#: Script category for Remote commands.
# Translators: The name of a category of NVDA commands.
SCRCAT_REMOTE = _("Remote")

# Translators: Reported when there are no settings to configure in synth settings ring
# (example: when there is no setting for language).
Expand Down Expand Up @@ -4914,6 +4917,71 @@ def script_toggleApplicationsVolumeAdjuster(self, gesture: "inputCore.InputGestu
def script_toggleApplicationsMute(self, gesture: "inputCore.InputGesture") -> None:
appsVolume._toggleAppsVolumeMute()

@script(
# Translators: Describes a command.
description=_("""Mute or unmute the speech coming from the remote computer"""),
category=SCRCAT_REMOTE,
)
def script_toggleRemoteMute(self, gesture: "inputCore.InputGesture"):
remoteClient._remoteClient.toggleMute()

@script(
gesture="kb:control+shift+NVDA+c",
category=SCRCAT_REMOTE,
# Translators: Documentation string for the script that sends the contents of the clipboard to the remote machine.
description=_("Sends the contents of the clipboard to the remote machine"),
)
def script_pushClipboard(self, gesture: "inputCore.InputGesture"):
remoteClient._remoteClient.pushClipboard()

@script(
# Translators: Documentation string for the script that copies a link to the remote session to the clipboard.
description=_("""Copies a link to the remote session to the clipboard"""),
category=SCRCAT_REMOTE,
)
def script_copyRemoteLink(self, gesture: "inputCore.InputGesture"):
remoteClient._remoteClient.copyLink()
# Translators: A message indicating that a link has been copied to the clipboard.
ui.message(_("Copied link"))

@script(
gesture="kb:alt+NVDA+pageDown",
category=SCRCAT_REMOTE,
# Translators: Documentation string for the script that disconnects a remote session.
description=_("Disconnect a remote session"),
)
@gui.blockAction.when(gui.blockAction.Context.SECURE_MODE)
def script_disconnectFromRemote(self, gesture: "inputCore.InputGesture"):
if not remoteClient._remoteClient.isConnected:
# Translators: A message indicating that the remote client is not connected.
ui.message(_("Not connected"))
return
remoteClient._remoteClient.disconnect()

@script(
gesture="kb:alt+NVDA+pageUp",
# Translators: Documentation string for the script that invokes the remote session.
description=_("""Connect to a remote computer"""),
category=SCRCAT_REMOTE,
)
@gui.blockAction.when(gui.blockAction.Context.MODAL_DIALOG_OPEN)
@gui.blockAction.when(gui.blockAction.Context.SECURE_MODE)
def script_connectToRemote(self, gesture: "inputCore.InputGesture"):
if remoteClient._remoteClient.isConnected() or remoteClient._remoteClient.connecting:
# Translators: A message indicating that the remote client is already connected.
ui.message(_("Already connected"))
return
remoteClient._remoteClient.doConnect()

@script(
# Translators: Documentation string for the script that toggles the control between guest and host machine.
description=_("Toggles the control between guest and host machine"),
category=SCRCAT_REMOTE,
gesture="kb:NVDA+f11",
)
def script_sendKeys(self, gesture: "inputCore.InputGesture"):
remoteClient._remoteClient.toggleRemoteKeyControl(gesture)


#: The single global commands instance.
#: @type: L{GlobalCommands}
Expand Down
Loading