-
Notifications
You must be signed in to change notification settings - Fork 5
/
AppDelegate.m
195 lines (149 loc) · 5.33 KB
/
AppDelegate.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//
// AppDelegate.m
// Transcode
//
// Created by flamefork on 22.08.08.
// Copyright 2008 Flamefork. All rights reserved.
//
#import "AppDelegate.h"
#import "KeyDiscriminant.h"
AXUIElementRef AXUIElementGetChild(AXUIElementRef element, NSUInteger atIndex, bool notEmpty, NSString *withTitle)
{
NSArray *children;
AXUIElementCopyAttributeValue(element, kAXChildrenAttribute, (CFTypeRef *)&children);
if (!children) return NULL;
NSUInteger i, count = [children count];
if (!count) return NULL;
if (!notEmpty && !withTitle) {
return (AXUIElementRef)[children objectAtIndex:atIndex];
}
for (i = 0; i < count; i++) {
AXUIElementRef result = (AXUIElementRef)[children objectAtIndex:i];
if (notEmpty) {
NSArray *subchildren;
AXUIElementCopyAttributeValue(result, kAXChildrenAttribute, (CFTypeRef *)&subchildren);
if (!subchildren || ![subchildren count]) continue;
}
if (withTitle) {
NSString *s;
AXUIElementCopyAttributeValue(result, kAXTitleAttribute, (CFTypeRef *)&s);
if (!s || ![s isEqualToString:withTitle]) continue;
}
return result;
}
return NULL;
}
bool useService(AXUIElementRef application, Transcoder *transcoder) {
AXUIElementRef uiElement;
CFBooleanRef boolValue;
AXUIElementCopyAttributeValue(application, kAXMenuBarAttribute, (CFTypeRef *)&uiElement); // Menu bar
if (!uiElement) return FALSE;
uiElement = AXUIElementGetChild(uiElement, 1, FALSE, nil); // Application menu bar item
if (!uiElement) return FALSE;
uiElement = AXUIElementGetChild(uiElement, 0, FALSE, nil); // Application menu
if (!uiElement) return FALSE;
uiElement = AXUIElementGetChild(uiElement, 0, TRUE, nil); // Services menu item
if (!uiElement) return FALSE;
uiElement = AXUIElementGetChild(uiElement, 0, FALSE, nil); // Services menu
if (!uiElement) return FALSE;
uiElement = AXUIElementGetChild(uiElement, 0, FALSE, @"Transcode"); // Transcode menu item
if (!uiElement) return FALSE;
AXUIElementCopyAttributeValue(uiElement, kAXEnabledAttribute, (CFTypeRef *)&boolValue); // Is Transcode action enabled?
if (!CFBooleanGetValue(boolValue)) return FALSE;
AXUIElementPerformAction(uiElement, kAXPressAction); // At last!!!
return TRUE;
}
bool useKeyboardEvents(AXUIElementRef application, Transcoder *transcoder) {
AXUIElementRef uiElement;
NSString *s;
AXUIElementCopyAttributeValue(application, kAXFocusedUIElementAttribute, (CFTypeRef *)&uiElement);
if (!uiElement) return FALSE;
AXUIElementCopyAttributeValue(uiElement, kAXSelectedTextAttribute, (CFTypeRef *)&s);
if (!s) return FALSE;
NSArray *keyDiscriminants;
keyDiscriminants = [transcoder decode:s];
[transcoder switchLayout];
KeyDiscriminant *kd;
for (kd in keyDiscriminants) {
[kd sendToApplication:application];
}
return TRUE;
}
OSStatus hotkeyHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void *userData)
{
Transcoder *transcoder = (Transcoder *)userData;
AXUIElementRef application;
AXUIElementCopyAttributeValue(AXUIElementCreateSystemWide(), kAXFocusedApplicationAttribute, (CFTypeRef *)&application);
if (application) {
if(useService(application, transcoder)) {
return noErr;
}
if (useKeyboardEvents(application, transcoder)) {
return noErr;
}
}
// If nothing helps - just switch this f***ing layout
[transcoder switchLayout];
return noErr;
}
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[self checkAXAPIEnabled];
transcoder = [[Transcoder alloc] init];
[transcoder retain];
[transcoder createLayouts];
EventTypeSpec eventType;
eventType.eventClass = kEventClassKeyboard;
eventType.eventKind = kEventHotKeyPressed;
EventHotKeyID hotkeyId;
hotkeyId.signature = 'htk1';
hotkeyId.id = 1;
EventHotKeyRef hotkeyRef;
EventHandlerUPP handlerUPP;
handlerUPP = NewEventHandlerUPP(&hotkeyHandler);
InstallApplicationEventHandler(handlerUPP, 1, &eventType, (void *)transcoder, NULL);
RegisterEventHotKey(49, cmdKey, hotkeyId, GetApplicationEventTarget(), 0, &hotkeyRef);
[NSApp setServicesProvider:self];
NSUpdateDynamicServices();
}
- (void)checkAXAPIEnabled
{
if(!AXAPIEnabled())
{
int result = NSRunAlertPanel(@"Enable Access for Assistive Devices." , @"To continue, please enable access for assistive devices in the Universal Access pane in System Preferences. Then, relaunch the application." , @"Open System Preferences", @"Quit", nil);
if(result == NSAlertDefaultReturn) {
[[NSWorkspace sharedWorkspace]openFile:@"/System/Library/PreferencePanes/UniversalAccessPref.prefPane"];
}
[NSApp terminate:nil];
}
}
- (void)callTranscode:(NSPasteboard *)pboard
userData:(NSString *)userData
error:(NSString **)error
{
NSString *pboardString;
NSString *newString;
NSArray *types;
types = [pboard types];
if (![types containsObject:NSStringPboardType]) {
*error = @"Error: couldn't transcode text.";
return;
}
pboardString = [pboard stringForType:NSStringPboardType];
if (!pboardString) {
*error = @"Error: couldn't transcode text.";
return;
}
NSArray *decoded = [transcoder decode:pboardString];
[transcoder switchLayout];
newString = [transcoder encode:decoded];
if (!newString) {
*error = @"Error: couldn't transcode text.";
return;
}
types = [NSArray arrayWithObject:NSStringPboardType];
[pboard declareTypes:types owner:nil];
[pboard setString:newString forType:NSStringPboardType];
return;
}
@end