Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion Bindings/Python/sral.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from enum import IntEnum
import ctypes
import os
import sys
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this import was missing, and making it impossible to run this on Mac OS X, so including this now (it is used in the check below on line 10)


# --- Load the SRAL C Library ---
try:
Expand Down Expand Up @@ -28,7 +29,8 @@ class SRALEngine(IntEnum):
SAPI = 1 << 6
SPEECH_DISPATCHER = 1 << 7
VOICE_OVER = 1 << 8
AV_SPEECH = 1 << 9
NS_SPEECH = 1 << 9
AV_SPEECH = 1 << 10
Comment on lines +32 to +33
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NS_SPEECH was previously missing - it looks like we actually never updated these values to match the source library (which maybe we should change to read more directly?) - that's probably beyond the scope of this PR, but for now, these should at least match the options there


class SRALFeature(IntEnum):
"""
Expand Down
4 changes: 2 additions & 2 deletions Bindings/go/SRAL/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ const (
SAPIEngine
// SpeechDispatcherEngine — Speech Dispatcher, a common daemon for Linux systems.
SpeechDispatcherEngine
// NSSpeechEngine — Apple NSSpeechSynthesizer.
NSSpeechEngine
// VoiceOverEngine — Apple VoiceOver, the built-in screen reader on Apple platforms.
VoiceOverEngine
// NSSpeechEngine — Apple NSSpeechSynthesizer.
NSSpeechEngine
// AVSpeechEngine — AVFoundation Speech Synthesizer (AVSpeechSynthesizer) for Apple platforms.
AVSpeechEngine
// AllEngines is a bitmask of all supported engines.
Expand Down
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ endif()
target_link_libraries(${PROJECT_NAME}_static ${LIBS})
endif()
elseif (APPLE)
enable_language(OBJC)
enable_language(OBJCXX)
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
Expand All @@ -117,6 +118,14 @@ if (BUILD_SRAL_TEST)
"-framework Foundation"
"-framework AVFoundation"
)

add_executable(${PROJECT_NAME}_test_cocoa "Examples/ObjC/SRALCocoaExample.m" "Include/SRAL.h")
target_link_libraries(${PROJECT_NAME}_test_cocoa
${PROJECT_NAME}_static
"-framework AppKit"
"-framework Foundation"
"-framework AVFoundation"
)
endif()
else()
find_package(PkgConfig REQUIRED)
Expand Down
97 changes: 97 additions & 0 deletions Examples/ObjC/SRALCocoaExample.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#import <AppKit/AppKit.h>

#define SRAL_STATIC
#include <SRAL.h>

@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (strong) NSWindow *window;
@property (strong) NSTextField *engineLabel;
@property (strong) NSTextField *speakingLabel;
@property (strong) NSTimer *speakingTimer;
@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)notification {
NSRect frame = NSMakeRect(200, 200, 400, 200);
self.window = [[NSWindow alloc]
initWithContentRect:frame
styleMask:(NSWindowStyleMaskTitled |
NSWindowStyleMaskClosable |
NSWindowStyleMaskMiniaturizable)
backing:NSBackingStoreBuffered
defer:NO];
[self.window setTitle:@"SRAL Cocoa Example"];

self.engineLabel = [NSTextField labelWithString:@"Engine: (initializing...)"];
[self.engineLabel setFrame:NSMakeRect(20, 150, 360, 20)];
[[self.window contentView] addSubview:self.engineLabel];

self.speakingLabel = [NSTextField labelWithString:@"Speaking: No"];
[self.speakingLabel setFrame:NSMakeRect(20, 125, 360, 20)];
[[self.window contentView] addSubview:self.speakingLabel];

NSButton *speakButton = [NSButton buttonWithTitle:@"Speak"
target:self
action:@selector(speakClicked:)];
[speakButton setFrame:NSMakeRect(125, 70, 150, 40)];
[[self.window contentView] addSubview:speakButton];

if (!SRAL_Initialize(0)) {
[self.engineLabel setStringValue:@"Engine: Failed to initialize SRAL!"];
return;
}

int engine = SRAL_GetCurrentEngine();
const char *name = SRAL_GetEngineName(engine);
[self.engineLabel setStringValue:
[NSString stringWithFormat:@"Engine: %s", name ? name : "Unknown"]];

// Continuously poll engine and speaking status
self.speakingTimer = [NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:@selector(updateStatus:)
userInfo:nil
repeats:YES];

[self.window makeKeyAndOrderFront:nil];
[NSApp activateIgnoringOtherApps:YES];
}

- (void)speakClicked:(id)sender {
SRAL_Speak("Hello, this is a test of the SRAL library.", true);
}

- (void)updateStatus:(NSTimer *)timer {
int engine = SRAL_GetCurrentEngine();
const char *name = SRAL_GetEngineName(engine);
[self.engineLabel setStringValue:
[NSString stringWithFormat:@"Engine: %s", name ? name : "None"]];

[self.speakingLabel setStringValue:
SRAL_IsSpeaking() ? @"Speaking: Yes" : @"Speaking: No"];
Comment on lines +71 to +72
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note - for VoiceOver, this value is always "No" - VoiceOver has a "fire-and-forget" system, which is more a quirk of that system, than it is a failing of this system

}

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
return YES;
}

- (void)applicationWillTerminate:(NSNotification *)notification {
[self.speakingTimer invalidate];
SRAL_Uninitialize();
}

@end

int main(int argc, const char *argv[]) {
@autoreleasepool {
NSApplication *app = [NSApplication sharedApplication];
[app setActivationPolicy:NSApplicationActivationPolicyRegular];

AppDelegate *delegate = [[AppDelegate alloc] init];
[app setDelegate:delegate];

[app run];
}
return 0;
}
8 changes: 4 additions & 4 deletions Include/SRAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,14 @@ SRAL_ENGINE_SPEECH_DISPATCHER = 1 << 7,

// --- Apple Screen Readers (macOS, iOS, etc.) ---

SRAL_ENGINE_NS_SPEECH = 1 << 8,


/** @brief Apple VoiceOver, the built-in screen reader on macOS, iOS, and other Apple platforms. */

SRAL_ENGINE_VOICE_OVER = 1 << 9,
SRAL_ENGINE_VOICE_OVER = 1 << 8,

// --- Apple Speech Synthesis Engines (macOS, iOS, etc.) ---

SRAL_ENGINE_NS_SPEECH = 1 << 9,

/** @brief AVFoundation Speech Synthesizer (AVSpeechSynthesizer), for text-to-speech on Apple platforms. */
SRAL_ENGINE_AV_SPEECH = 1 << 10
};
Expand Down
2 changes: 2 additions & 0 deletions SRC/VoiceOver.mm
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
#if TARGET_OS_IOS || TARGET_OS_TV
return UIAccessibilityIsVoiceOverRunning() == YES ? true : false;
#elif TARGET_OS_OSX
// VoiceOver depends on a running NSApp, so return false if none is running
if (NSApp == nil) return false;
return [[NSWorkspace sharedWorkspace] isVoiceOverEnabled];
#endif
}
Expand Down
Loading