Skip to content

Commit

Permalink
Try to implement NVDA controller via pipe (NVDAControlEx add-on).
Browse files Browse the repository at this point in the history
  • Loading branch information
m1maker committed Jan 26, 2025
1 parent 066f774 commit da573fa
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 9 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ if(WIN32)
target_sources(${PROJECT_NAME}_obj PRIVATE
"SRC/Encoding.h" "SRC/Encoding.cpp"
"SRC/NVDA.h" "SRC/NVDA.cpp" "SRC/SAPI.h" "SRC/SAPI.cpp"
"Dep/blastspeak.h" "Dep/blastspeak.c" "Dep/fsapi.h" "Dep/fsapi.c"
"Dep/blastspeak.h" "Dep/blastspeak.c" "Dep/fsapi.h" "Dep/fsapi.c" "Dep/nvda_control.h" "Dep/nvda_control.c"
"SRC/Jaws.h" "SRC/Jaws.cpp" "SRC/UIA.cpp"
"Dep/UIAProvider.h" "Dep/UIAProvider.cpp" "Dep/wasapi.h" "Dep/wasapi.cpp")
elseif(APPLE)
Expand Down
11 changes: 10 additions & 1 deletion Dep/nvda_control.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#include "nvda_control.h"

#ifdef __cplusplus
extern "C" {
#endif


// Connects to the NVDA named pipe
HANDLE nvda_connect() {
HANDLE hPipe = CreateFile(
Expand Down Expand Up @@ -38,7 +43,6 @@ int nvda_send_command(HANDLE hPipe, const char* command) {
);

if (!result) {
fprintf(stderr, "Failed to send command. Error: %lu\n", GetLastError());
return -1;
}

Expand Down Expand Up @@ -77,3 +81,8 @@ int nvda_pause_speech(HANDLE hPipe, int pause) {
int nvda_cancel_speech(HANDLE hPipe) {
return nvda_send_command(hPipe, "cancelSpeech");
}

#ifdef __cplusplus
}
#endif

12 changes: 11 additions & 1 deletion Dep/nvda_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif



// Named pipe name
#define NVDA_PIPE_NAME L"\\\\.\\pipe\\NVDAControlPipe"
Expand All @@ -14,7 +19,7 @@
* Connects to the NVDA named pipe.
* Returns a handle to the pipe if successful, or INVALID_HANDLE_VALUE on failure.
*/
HANDLE nvda_connect();
HANDLE nvda_connect(void);

/**
* Disconnects from the NVDA named pipe.
Expand Down Expand Up @@ -69,4 +74,9 @@ int nvda_pause_speech(HANDLE hPipe, int pause);
*/
int nvda_cancel_speech(HANDLE hPipe);

#ifdef __cplusplus
}
#endif


#endif // NVDA_CONTROL_H
28 changes: 22 additions & 6 deletions SRC/NVDA.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
#include "Encoding.h"
#include "NVDA.h"
#include <windows.h>
#include "../Dep/nvda_control.h"

bool NVDA::Initialize() {
pipe = nvda_connect();
if (pipe != INVALID_HANDLE_VALUE)
return true;
lib = LoadLibraryW(L"nvdaControllerClient.dll");
if (lib == nullptr)return false;
nvdaController_speakText = (NVDAController_speakText)GetProcAddress(lib, "nvdaController_speakText");
Expand All @@ -13,6 +17,10 @@ bool NVDA::Initialize() {
return true;
}
bool NVDA::Uninitialize() {
if (pipe != INVALID_HANDLE_VALUE) {
nvda_disconnect(pipe);
return true;
}
if (lib == nullptr)return false;
FreeLibrary(lib);
nvdaController_speakText = nullptr;
Expand All @@ -24,18 +32,22 @@ bool NVDA::Uninitialize() {
return true;
}
bool NVDA::GetActive() {
if (pipe != INVALID_HANDLE_VALUE)
return true;
if (lib == nullptr) return false;
if (nvdaController_testIfRunning) return (!!FindWindowW(L"wxWindowClassNR", L"NVDA") && nvdaController_testIfRunning() == 0);
return false;
}
bool NVDA::Speak(const char* text, bool interrupt) {
if (!GetActive())return false;
if (interrupt)
nvdaController_cancelSpeech();
if (interrupt) {
pipe == INVALID_HANDLE_VALUE ? nvdaController_cancelSpeech() : nvda_cancel_speech(pipe);
}
std::string text_str(text);
XmlEncode(text_str);
std::string final = "<speak>" + text_str + "</speak>";

if (pipe != INVALID_HANDLE_VALUE)
return nvda_speak_ssml(pipe, final.c_str()) == 0;
std::wstring out_ssml;
UnicodeConvert(final, out_ssml);
error_status_t result = nvdaController_speakSsml(out_ssml.c_str(), this->symbolLevel, 0, true);
Expand All @@ -52,7 +64,9 @@ bool NVDA::Speak(const char* text, bool interrupt) {
bool NVDA::SpeakSsml(const char* ssml, bool interrupt) {
if (!GetActive())return false;
if (interrupt)
nvdaController_cancelSpeech();
pipe == INVALID_HANDLE_VALUE ? nvdaController_cancelSpeech() : nvda_cancel_speech(pipe);
if (pipe != INVALID_HANDLE_VALUE)
return nvda_speak_ssml(pipe, ssml) == 0;
std::string text_str(ssml);
std::wstring out;
UnicodeConvert(ssml, out);
Expand All @@ -78,10 +92,12 @@ bool NVDA::Braille(const char* text) {
}
bool NVDA::StopSpeech() {
if (!GetActive())return false;
return nvdaController_cancelSpeech() == 0;
return pipe == INVALID_HANDLE_VALUE ? nvdaController_cancelSpeech() == 0 : nvda_cancel_speech(pipe) == 0;
}
bool NVDA::PauseSpeech() {
if (!GetActive())return false;
if (pipe != INVALID_HANDLE_VALUE)
return nvda_pause_speech(pipe, true);
INPUT input[2] = {};

input[0].type = INPUT_KEYBOARD;
Expand All @@ -97,5 +113,5 @@ bool NVDA::PauseSpeech() {
return true;
}
bool NVDA::ResumeSpeech() {
return PauseSpeech(); // Don't know how to do it
return pipe == INVALID_HANDLE_VALUE ? PauseSpeech() : nvda_pause_speech(pipe, false);
}
1 change: 1 addition & 0 deletions SRC/NVDA.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class NVDA : public Engine {

private:
HINSTANCE lib = nullptr;
HANDLE pipe = nullptr;
typedef error_status_t(__stdcall* NVDAController_speakText)(const wchar_t*);
typedef error_status_t(__stdcall* NVDAController_brailleMessage)(const wchar_t*);
typedef error_status_t(__stdcall* NVDAController_cancelSpeech)();
Expand Down

0 comments on commit da573fa

Please sign in to comment.