// // hotkeys.m // Pcsxr // // Created by Nicolas Pepin-Perreault on 12-12-12. // // #import #import #import "hotkeys.h" #import "EmuThread.h" #include "plugins.h" #include "ExtendedKeys.h" #import "PcsxrController.h" #import "ARCBridge.h" #define HK_MAX_STATE 10 static id monitor; static id gpuMonitor; static int currentState = 0; static NSMutableDictionary *hotkeys = nil; enum { HK_FAST_FORWARD, HK_SAVE_STATE, HK_LOAD_STATE, HK_NEXT_STATE, HK_PREV_STATE, HK_FRAME_LIMIT }; void nextState() { currentState++; if(currentState == HK_MAX_STATE) { currentState = 0; } } void prevState() { currentState--; if(currentState < 0) { currentState = HK_MAX_STATE-1; } } BOOL handleHotkey(NSString* keyCode) { if([EmuThread active]) { // Don't catch hotkeys if there is no emulation NSNumber *ident = [hotkeys objectForKey:keyCode]; if(ident != nil) { switch([ident intValue]) { case HK_FAST_FORWARD: // We ignore FastForward requests if the emulation is paused if(![EmuThread isPaused]) { GPU_keypressed(GPU_FAST_FORWARD); } break; case HK_FRAME_LIMIT: // Ignore FrameLimit requests if paused if(![EmuThread isPaused]) { GPU_keypressed(GPU_FRAME_LIMIT); } break; case HK_SAVE_STATE: [PcsxrController saveState:currentState]; break; case HK_LOAD_STATE: [PcsxrController loadState:currentState]; break; case HK_NEXT_STATE: nextState(); GPU_displayText((char*)[[NSString stringWithFormat:@"State Slot: %d", currentState] UTF8String]); break; case HK_PREV_STATE: prevState(); GPU_displayText((char*)[[NSString stringWithFormat:@"State Slot: %d", currentState] UTF8String]); break; default: NSLog(@"Invalid hotkey identifier %i.", [ident intValue]); } return YES; } } return NO; } void setupHotkey(int hk, NSString *label, NSDictionary *binding) { if(binding != nil) [hotkeys setObject:@(hk) forKey:[binding objectForKey:@"keyCode"]]; } void setupHotkeys() { NSDictionary *bindings = [[NSUserDefaults standardUserDefaults] objectForKey:@"HotkeyBindings"]; hotkeys = [[NSMutableDictionary alloc] initWithCapacity:[bindings count]]; setupHotkey(HK_FAST_FORWARD, @"FastForward", [bindings objectForKey:@"FastForward"]); setupHotkey(HK_SAVE_STATE, @"SaveState", [bindings objectForKey:@"SaveState"]); setupHotkey(HK_LOAD_STATE, @"LoadState", [bindings objectForKey:@"LoadState"]); setupHotkey(HK_NEXT_STATE, @"NextState", [bindings objectForKey:@"NextState"]); setupHotkey(HK_PREV_STATE, @"PrevState", [bindings objectForKey:@"PrevState"]); setupHotkey(HK_FRAME_LIMIT, @"FrameLimit", [bindings objectForKey:@"FrameLimit"]); currentState = 0; } void attachHotkeys() { // Configurable hotkeys NSEvent* (^handler)(NSEvent*) = ^(NSEvent *event) { if(handleHotkey([NSString stringWithFormat:@"%d", [event keyCode]])) { return (NSEvent*)nil; // handled } // Not handled return event; }; setupHotkeys(); monitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSKeyUpMask handler:handler]; // GPU key presses NSEvent* (^gpuKeypress)(NSEvent*) = ^(NSEvent *event) { GPU_keypressed([event keyCode]); return (NSEvent*)nil; }; gpuMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:(NSKeyUpMask | NSControlKeyMask) handler:gpuKeypress]; } void detachHotkeys() { RELEASEOBJ(hotkeys); hotkeys = nil; [NSEvent removeMonitor:monitor]; [NSEvent removeMonitor:gpuMonitor]; monitor = nil; gpuMonitor = nil; }