forked from fe9lix/CodingKeys
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAppService.m
More file actions
138 lines (106 loc) · 4.27 KB
/
AppService.m
File metadata and controls
138 lines (106 loc) · 4.27 KB
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
#import "AppService.h"
#import "HotKey.h"
static NSString * const KeysFileName = @"keys";
static NSString * const AboutURL = @"https://github.com/fe9lix/CodingKeys";
NSString * const AppServiceDidChangeHotKeys = @"AppServiceDidChangeHotKeys";
@interface AppService () <NSFilePresenter>
@property (nonatomic, strong) NSDictionary *hotKeysForAppName;
@property (nonatomic, strong) NSFileCoordinator *fileCoordinator;
@property (strong) NSURL *presentedItemURL;
@property (strong) NSOperationQueue *presentedItemOperationQueue;
@property (nonatomic, strong) NSTimer *timer;
@end
@implementation AppService
+ (AppService *)sharedService {
static AppService *sharedService = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedService = [[self alloc] init];
});
return sharedService;
}
- (id)init {
self = [super init];
if (self) {
[self setup];
}
return self;
}
- (void)setup {
[self setupHotKeysForAppName];
[self watchKeyFile];
}
- (void)setupHotKeysForAppName {
NSArray *keyMappings = [self loadKeyMappingsFile];
NSMutableDictionary *hotKeysForAppName = [NSMutableDictionary dictionary];
for (NSDictionary *keyMapping in keyMappings) {
NSString *key = keyMapping[@"key"];
NSDictionary *mapping = keyMapping[@"mapping"];
HotKey *hotKey = [[HotKey alloc] initWithKey:key
mapping:mapping];
for (NSString *appName in mapping) {
if (!hotKeysForAppName[appName]) {
hotKeysForAppName[appName] = [NSMutableArray array];
}
NSString *mappedKey = mapping[appName];
if (![mappedKey isEqualToString:key]) {
[hotKeysForAppName[appName] addObject:hotKey];
}
}
}
self.hotKeysForAppName = hotKeysForAppName;
}
- (NSArray *)loadKeyMappingsFile {
NSError *error;
NSString *jsonString = [NSString stringWithContentsOfFile:[self keysFilePath]
encoding:NSUTF8StringEncoding
error:&error];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
return [NSJSONSerialization JSONObjectWithData:jsonData
options:0
error:nil];
}
- (NSString *)keysFilePath {
return [[NSBundle mainBundle] pathForResource:KeysFileName
ofType:@"json"];
}
- (void)watchKeyFile {
self.presentedItemOperationQueue = [[NSOperationQueue alloc] init];
self.presentedItemOperationQueue.maxConcurrentOperationCount = 1;
self.presentedItemURL = [[NSBundle mainBundle] resourceURL];
self.fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:self];
[NSFileCoordinator addFilePresenter:self];
}
- (void)presentedItemDidChange {
[self.timer invalidate];
dispatch_async(dispatch_get_main_queue(), ^{
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5f
target:self
selector:@selector(keysDidChange:)
userInfo:nil
repeats:NO];
});
}
- (void)keysDidChange:(id)obj {
[self setupHotKeysForAppName];
[self dispatchKeysDidChangeNotification];
}
- (void)dispatchKeysDidChangeNotification {
NSNotification *notification = [NSNotification notificationWithName:AppServiceDidChangeHotKeys
object:nil
userInfo:nil];
[[NSNotificationCenter defaultCenter] postNotification:notification];
}
- (BOOL)isAppRegistered:(NSString *)appName {
return self.hotKeysForAppName[appName] != nil;
}
- (NSArray *)hotKeysForAppWithName:(NSString *)appName {
return self.hotKeysForAppName[appName];
}
- (void)openKeyMappings {
[[NSWorkspace sharedWorkspace] openFile:[self keysFilePath]];
}
- (void)openAboutURL {
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:AboutURL]];
}
@end