1/* GSKrabManager.m - this file is part of GSKrab 2 * 3 * Copyright (C) 2006 Wolfgang Sourdeau 4 * 5 * Author: Wolfgang Sourdeau <Wolfgang@Contre.COM> 6 * 7 * This file is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2, or (at your option) 10 * any later version. 11 * 12 * This file is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; see the file COPYING. If not, write to 19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 20 * Boston, MA 02111-1307, USA. 21 */ 22 23#import <AppKit/NSWorkspace.h> 24#import <Foundation/NSConnection.h> 25#import <Foundation/NSDistantObject.h> 26#import <Foundation/NSHost.h> 27#import <Foundation/NSMapTable.h> 28#import <Foundation/NSNotification.h> 29#import <Foundation/NSPort.h> 30#import <Foundation/NSPortNameServer.h> 31#import <Foundation/NSString.h> 32#import <Foundation/NSTask.h> 33#import <Foundation/NSThread.h> 34#import <Foundation/NSValue.h> 35 36#import "GSKrabDesktopInterface.h" 37#import "GSKrabServer.h" 38 39#ifdef __WIN32__ 40#import "GSKrabWin32Interface.h" 41#define DesktopInterface GSKrabWin32Interface 42#else 43#import "GSKrabX11Interface.h" 44#define DesktopInterface GSKrabX11Interface 45#endif 46 47#import "GSKrabManager.h" 48 49static NSNotificationCenter *nc = nil; 50 51@implementation GSKrabManager 52 53+ (void) initialize 54{ 55 if (!nc) 56 nc = [NSNotificationCenter defaultCenter]; 57} 58 59// - (NSDictionary **) _knownKeys 60// { 61// NSMutableDictionary **dicts; 62// NSArray *sampleKeys; 63 64// dicts = malloc (sizeof (NSDictionary *) * 2); 65// sampleKeys 66// = [NSArray arrayWithObjects: [NSNumber numberWithInt: GSKrabPlay], 67// [NSNumber numberWithInt: GSKrabStop], 68// [NSNumber numberWithInt: GSKrabEject], 69// [NSNumber numberWithInt: GSKrabTrackPrevious], 70// [NSNumber numberWithInt: GSKrabTrackNext], 71// nil]; 72// dicts[0] = [NSMutableDictionary new]; 73// [dicts[0] setObject: @"Cynthiune.app" forKey: @"Application"]; 74// [dicts[0] setObject: @"CynthiuneClient" forKey: @"ClientName"]; 75// [dicts[0] setObject: sampleKeys forKey: @"Keys"]; 76// [dicts[0] setObject: @"Application" forKey: @"BindingType"]; 77// dicts[1] = [NSMutableDictionary new]; 78// [dicts[1] setObject: @"firefox" forKey: @"Command"]; 79// [dicts[1] setObject: 80// [NSArray arrayWithObject: [NSNumber numberWithInt: GSKrabWWW]] 81// forKey: @"Keys"]; 82// [dicts[1] setObject: @"ShellCommand" forKey: @"BindingType"]; 83// dicts[2] = nil; 84 85// return dicts; 86// } 87 88// - (void) _registerKnownKeys 89// { 90// NSDictionary **applicationsDicts; 91// NSDictionary **current; 92// NSArray *keys; 93// unsigned int count, max; 94 95// applicationsDicts = [self _knownKeys]; 96// current = applicationsDicts; 97// while (*current) 98// { 99// keys = [*current objectForKey: @"Keys"]; 100// max = [keys count]; 101// for (count = 0; count < max; count++) 102// [self registerKey: [[keys objectAtIndex: count] intValue] 103// forObject: *current]; 104// current++; 105// } 106// } 107 108- (NSConnection *) _setupConnection 109{ 110 NSConnection *connection; 111 NSPort *port; 112 113 port = [NSPort new]; 114 connection = [NSConnection connectionWithReceivePort: port 115 sendPort: nil]; 116 if ([[NSPortNameServer systemDefaultPortNameServer] registerPort: port 117 forName: @"GSKrabServer"]) 118 { 119 [connection setRootObject: server]; 120 [connection setReplyTimeout: 0.5]; 121 [connection retain]; 122 } 123 else 124 connection = nil; 125 126 [port release]; 127 128 return connection; 129} 130 131- (id) init 132{ 133 if ((self = [super init])) 134 { 135 interface = [DesktopInterface sharedInterface]; 136 [interface setManager: self]; 137 keyTable = NSCreateMapTable (NSIntMapKeyCallBacks, 138 NSObjectMapValueCallBacks, 139 GSKrabMaxNumberOfKeys); 140// [self _registerKnownKeys]; 141 server = [GSKrabServer new]; 142 [server setManager: self]; 143 serverConnection = [self _setupConnection]; 144 applications = [NSMutableArray new]; 145 if (serverConnection) 146 { 147 [interface start]; 148// [nc addObserver: self 149// selector: @selector (connectionDied:) 150// name: NSConnectionDidDieNotification 151// object: serverConnection]; 152 } 153 else 154 { 155 [self release]; 156 self = nil; 157 } 158 } 159 160 return self; 161} 162 163- (void) dealloc 164{ 165 [serverConnection release]; 166 [interface release]; 167 [server release]; 168 [applications release]; 169 [super dealloc]; 170} 171 172- (void) registerKey: (GSKrabKeyCode) krabKeyCode 173 forObject: (NSObject *) object 174{ 175 NSMapInsert (keyTable, (void *) krabKeyCode, object); 176 [interface registerKeyCode: krabKeyCode]; 177} 178 179- (BOOL) _launchApplication: (NSString *) application 180{ 181 NSWorkspace *ws; 182 183// NSLog (@"launching: %@", application); 184 ws = [NSWorkspace sharedWorkspace]; 185 return [ws launchApplication: application]; 186} 187 188- (BOOL) _launchCommand: (NSString *) command 189{ 190 NSTask *task; 191 192 task = nil; 193 NS_DURING 194 { 195#ifdef __WIN32__ 196 task = [NSTask launchedTaskWithLaunchPath: @"cmd.exe" 197 arguments: [NSArray arrayWithObjects: @"start test.exe", 198 nil]]; 199#else 200 task = [NSTask launchedTaskWithLaunchPath: command 201 arguments: nil]; 202#endif 203 } 204 NS_HANDLER 205 { 206 if (![[localException name] isEqualToString: NSInvalidArgumentException]) 207 [localException raise]; 208 } 209 NS_ENDHANDLER 210 211 return (task != nil 212 && ([task isRunning] || [task terminationStatus] == 0)); 213} 214 215- (BOOL) _handlePendingKeyPress: (GSKrabKeyCode) krabKeyCode 216 forApplication: (NSDictionary *) application 217{ 218#warning FIXME: should implement method 219// NSLog (@"application '%@' not launched?", application); 220 221 return NO; 222} 223 224- (BOOL) _sendKeyPress: (GSKrabKeyCode) krabKeyCode 225 toService: (NSDistantObject <GSKrabClient> *) service 226{ 227 NSConnection *connection; 228 BOOL result; 229 230 result = NO; 231 NS_DURING 232 { 233 connection = [service connectionForProxy]; 234 [connection setReplyTimeout: 0.5]; 235 [connection setRequestTimeout: 0.5]; 236 [service performActionForKey: krabKeyCode]; 237 result = YES; 238 } 239 NS_HANDLER 240 { 241 if (![[localException name] isEqualToString: NSPortTimeoutException]) 242 [localException raise]; 243 } 244 NS_ENDHANDLER 245 246 return result; 247} 248 249- (BOOL) _sendKeyPress: (GSKrabKeyCode) krabKeyCode 250 toApplication: (NSDictionary *) application 251{ 252 NSDistantObject <GSKrabClient> *applService; 253 NSString *serviceName; 254 BOOL result; 255 256 result = NO; 257 serviceName = [application objectForKey: @"ServiceName"]; 258 if (serviceName) 259 { 260 applService = [NSConnection rootProxyForConnectionWithRegisteredName: serviceName 261 host: nil]; 262 if (applService) 263 { 264 [applService setProtocolForProxy: @protocol (GSKrabClient)]; 265 result = [self _sendKeyPress: krabKeyCode toService: applService]; 266 } 267 else 268 { 269// NSLog (@"service '%@' not reached", serviceName); 270 result = [self _handlePendingKeyPress: krabKeyCode 271 forApplication: application]; 272 } 273 } 274 else 275 { 276// NSLog (@"no service name"); 277 result = [self _handlePendingKeyPress: krabKeyCode 278 forApplication: application]; 279 } 280 281 return result; 282} 283 284- (BOOL) handleKeyPress: (GSKrabKeyCode) krabKeyCode 285{ 286 NSDictionary *keyHandler; 287 BOOL result; 288 289 result = NO; 290 291 keyHandler = NSMapGet (keyTable, (void *) krabKeyCode); 292 if (keyHandler) 293 { 294 if ([[keyHandler objectForKey: @"BindingType"] 295 isEqualToString: @"Application"]) 296 result = [self _sendKeyPress: krabKeyCode toApplication: keyHandler]; 297 else if ([[keyHandler objectForKey: @"BindingType"] 298 isEqualToString: @"ShellCommand"]) 299 result = [self _launchCommand: 300 [keyHandler objectForKey: @"Command"]]; 301 } 302// else 303// NSLog (@"no handler for key '%d'", krabKeyCode); 304 305// NSLog (@"result: %d", result); 306 307 return result; 308} 309 310- (NSDictionary *) _findApplication: (NSString *) application 311{ 312 NSEnumerator *enumerator; 313 NSDictionary *currentDict, *applDict; 314 315 applDict = nil; 316 enumerator = [applications objectEnumerator]; 317 currentDict = [enumerator nextObject]; 318 while (currentDict && !applDict) 319 if ([[currentDict objectForKey: @"Application"] 320 isEqualToString: application]) 321 applDict = currentDict; 322 else 323 currentDict = [enumerator nextObject]; 324 325 return applDict; 326} 327 328- (NSDictionary *) _findApplicationWithName: (NSString *) serviceName 329{ 330 NSEnumerator *enumerator; 331 NSDictionary *currentDict, *applDict; 332 333 applDict = nil; 334 enumerator = [applications objectEnumerator]; 335 currentDict = [enumerator nextObject]; 336 while (currentDict && !applDict) 337 if ([[currentDict objectForKey: @"ServiceName"] 338 isEqualToString: serviceName]) 339 applDict = currentDict; 340 else 341 currentDict = [enumerator nextObject]; 342 343 return applDict; 344} 345 346- (void) registerApplication: (NSString *) application 347 withServiceName: (NSString *) serviceName 348{ 349 NSDictionary *oldApplDict; 350 NSMutableDictionary *newApplDict; 351 352 oldApplDict = [self _findApplication: application]; 353 if (oldApplDict) 354 [applications removeObject: oldApplDict]; 355 356 newApplDict = [NSMutableDictionary new]; 357 [newApplDict setObject: application forKey: @"Application"]; 358 [newApplDict setObject: @"Application" forKey: @"BindingType"]; 359 [newApplDict setObject: serviceName forKey: @"ServiceName"]; 360 [newApplDict setObject: [NSMutableArray new] forKey: @"Keys"]; 361 [applications addObject: newApplDict]; 362 363// NSLog (@"application '%@' registered with service name '%@'", serviceName); 364} 365 366- (void) applicationWithServiceName: (NSString *) serviceName 367 subscribesToKeyCode: (GSKrabKeyCode) krabKeyCode 368{ 369 NSDictionary *applDict; 370 NSMutableArray *keys; 371 NSNumber *keyCode; 372 373 applDict = [self _findApplicationWithName: serviceName]; 374 if (applDict) 375 { 376 keys = [applDict objectForKey: @"Keys"]; 377 keyCode = [NSNumber numberWithInt: krabKeyCode]; 378 if ([keys indexOfObject: keyCode] == NSNotFound) 379 { 380 [keys addObject: keyCode]; 381 [self registerKey: krabKeyCode forObject: applDict]; 382 } 383 } 384// else 385// NSLog (@"no application found with service name '%@'", serviceName); 386} 387 388- (void) stop 389{ 390 [interface stop]; 391 [self release]; 392 exit (0); 393} 394 395@end 396