From bf4f513d7e6590566c17a0c6e27da30826390249 Mon Sep 17 00:00:00 2001 From: sithlord48 Date: Tue, 17 Dec 2024 20:42:03 -0500 Subject: [PATCH] chore: format *.m and *.mm files --- scripts/lint_clang.py | 2 + src/gui/src/AppDelegate.mm | 31 +- src/lib/gui/OSXHelpers.mm | 125 +- src/lib/platform/OSXDragSimulator.m | 132 +- src/lib/platform/OSXDragView.m | 131 +- src/lib/platform/OSXMediaKeySupport.m | 253 +- src/lib/platform/OSXPasteboardPeeker.m | 31 +- src/lib/platform/OSXScreen.mm | 3507 +++++++++++------------- src/lib/platform/OSXScreenSaverUtil.m | 53 +- 9 files changed, 2042 insertions(+), 2223 deletions(-) diff --git a/scripts/lint_clang.py b/scripts/lint_clang.py index b374b5cd9..a2f31d5c5 100755 --- a/scripts/lint_clang.py +++ b/scripts/lint_clang.py @@ -28,6 +28,8 @@ include_files = [ "*.c", "*.hpp", "*.cpp", + "*.m", + "*.mm", ] dirs = ["src"] diff --git a/src/gui/src/AppDelegate.mm b/src/gui/src/AppDelegate.mm index 04cdcf3a1..4ff0ca008 100644 --- a/src/gui/src/AppDelegate.mm +++ b/src/gui/src/AppDelegate.mm @@ -2,35 +2,36 @@ @interface AppDelegate () -@property (strong) IBOutlet NSWindow *window; +@property(strong) IBOutlet NSWindow *window; @end -@implementation AppDelegate -{ +@implementation AppDelegate { } --(void)applicationDidFinishLaunching:(NSNotification *)aNotification +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { - [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self]; + [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self]; #if OSX_DEPLOYMENT_TARGET >= 1014 - [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self]; + [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self]; #endif } --(BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification{ - return YES; +- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center + shouldPresentNotification:(NSUserNotification *)notification +{ + return YES; } #if OSX_DEPLOYMENT_TARGET >= 1014 --(void)userNotificationCenter:(UNUserNotificationCenter *)center +- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification - withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{ - UNNotificationPresentationOptions presentationOptions = - UNNotificationPresentationOptionSound - | UNNotificationPresentationOptionAlert - | UNNotificationPresentationOptionBadge; + withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler +{ + UNNotificationPresentationOptions presentationOptions = UNNotificationPresentationOptionSound | + UNNotificationPresentationOptionAlert | + UNNotificationPresentationOptionBadge; - completionHandler(presentationOptions); + completionHandler(presentationOptions); } #endif diff --git a/src/lib/gui/OSXHelpers.mm b/src/lib/gui/OSXHelpers.mm index 96dcb4d84..06cb2fe57 100644 --- a/src/lib/gui/OSXHelpers.mm +++ b/src/lib/gui/OSXHelpers.mm @@ -17,13 +17,13 @@ #import "OSXHelpers.h" -#import -#import #import +#import +#import #import -#import #import #import +#import #import @@ -33,86 +33,85 @@ void requestOSXNotificationPermission() { #if OSX_DEPLOYMENT_TARGET >= 1014 - if (isOSXDevelopmentBuild()) - { - qWarning("Not requesting notification permission in dev build"); - return; - } + if (isOSXDevelopmentBuild()) { + qWarning("Not requesting notification permission in dev build"); + return; + } - UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter]; - [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound) - completionHandler:^(BOOL granted, NSError * _Nullable error) { - if(error != nil) - { - qWarning("Notification permission request error: %s", [[NSString stringWithFormat:@"%@", error] UTF8String]); - } - }]; + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound) + completionHandler:^(BOOL granted, NSError *_Nullable error) { + if (error != nil) { + qWarning( + "Notification permission request error: %s", + [[NSString stringWithFormat:@"%@", error] UTF8String] + ); + } + }]; #endif } -bool -isOSXDevelopmentBuild() +bool isOSXDevelopmentBuild() { - std::string bundleURL = [[[NSBundle mainBundle] bundleURL].absoluteString UTF8String]; - return (bundleURL.find("Applications/Deskflow.app") == std::string::npos); + std::string bundleURL = [[[NSBundle mainBundle] bundleURL].absoluteString UTF8String]; + return (bundleURL.find("Applications/Deskflow.app") == std::string::npos); } -bool -showOSXNotification(const QString& title, const QString& body) +bool showOSXNotification(const QString &title, const QString &body) { #if OSX_DEPLOYMENT_TARGET >= 1014 - // accessing notification center on unsigned build causes an immidiate - // application shutodown (in this case, server) and cannot be caught - // to avoid issues with it need to first check if this is a dev build - if (isOSXDevelopmentBuild()) - { - qWarning("Not showing notification in dev build"); - return false; - } + // accessing notification center on unsigned build causes an immidiate + // application shutodown (in this case, server) and cannot be caught + // to avoid issues with it need to first check if this is a dev build + if (isOSXDevelopmentBuild()) { + qWarning("Not showing notification in dev build"); + return false; + } - requestOSXNotificationPermission(); + requestOSXNotificationPermission(); - UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter]; + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; - UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init]; - content.title = title.toNSString(); - content.body = body.toNSString(); + UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init]; + content.title = title.toNSString(); + content.body = body.toNSString(); - // Create the request object. - UNNotificationRequest* request = [UNNotificationRequest - requestWithIdentifier:@"SecureInput" content:content trigger:nil]; + // Create the request object. + UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"SecureInput" + content:content + trigger:nil]; - [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) { - if (error != nil) { - qWarning("Notification display request error: %s", [[NSString stringWithFormat:@"%@", error] UTF8String]); - } - }]; + [center + addNotificationRequest:request + withCompletionHandler:^(NSError *_Nullable error) { + if (error != nil) { + qWarning("Notification display request error: %s", [[NSString stringWithFormat:@"%@", error] UTF8String]); + } + }]; #else - NSUserNotification* notification = [[NSUserNotification alloc] init]; - notification.title = title.toNSString(); - notification.informativeText = body.toNSString(); - notification.soundName = NSUserNotificationDefaultSoundName; //Will play a default sound - [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification: notification]; - [notification autorelease]; + NSUserNotification *notification = [[NSUserNotification alloc] init]; + notification.title = title.toNSString(); + notification.informativeText = body.toNSString(); + notification.soundName = NSUserNotificationDefaultSoundName; // Will play a default sound + [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification]; + [notification autorelease]; #endif - return true; + return true; } -bool -isOSXInterfaceStyleDark() +bool isOSXInterfaceStyleDark() { - // Implementation from http://stackoverflow.com/a/26472651 - NSDictionary* dict = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain]; - id style = [dict objectForKey:@"AppleInterfaceStyle"]; - return (style && [style isKindOfClass:[NSString class]] && NSOrderedSame == [style caseInsensitiveCompare:@"dark"]); + // Implementation from http://stackoverflow.com/a/26472651 + NSDictionary *dict = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain]; + id style = [dict objectForKey:@"AppleInterfaceStyle"]; + return (style && [style isKindOfClass:[NSString class]] && NSOrderedSame == [style caseInsensitiveCompare:@"dark"]); } -IconsTheme -getOSXIconsTheme() +IconsTheme getOSXIconsTheme() { - if (@available(macOS 11, *)) - return IconsTheme::ICONS_TEMPLATE; - else if(isOSXInterfaceStyleDark()) - return IconsTheme::ICONS_DARK; - return IconsTheme::ICONS_LIGHT; + if (@available(macOS 11, *)) + return IconsTheme::ICONS_TEMPLATE; + else if (isOSXInterfaceStyleDark()) + return IconsTheme::ICONS_DARK; + return IconsTheme::ICONS_LIGHT; } diff --git a/src/lib/platform/OSXDragSimulator.m b/src/lib/platform/OSXDragSimulator.m index 5ed352d92..7bf4be0d2 100644 --- a/src/lib/platform/OSXDragSimulator.m +++ b/src/lib/platform/OSXDragSimulator.m @@ -16,89 +16,85 @@ #import "platform/OSXDragView.h" -#import -#import #import +#import +#import #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" -NSWindow* g_dragWindow = NULL; -OSXDragView* g_dragView = NULL; -NSString* g_ext = NULL; +NSWindow *g_dragWindow = NULL; +OSXDragView *g_dragView = NULL; +NSString *g_ext = NULL; -void -runCocoaApp() +void runCocoaApp() { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - - [NSApplication sharedApplication]; - - NSWindow* window = [[NSWindow alloc] - initWithContentRect: NSMakeRect(0, 0, 3, 3) - styleMask: NSBorderlessWindowMask - backing: NSBackingStoreBuffered - defer: NO]; - [window setTitle: @""]; - [window setAlphaValue:0.1]; - [window makeKeyAndOrderFront:nil]; - - OSXDragView* dragView = [[OSXDragView alloc] initWithFrame:NSMakeRect(0, 0, 3, 3)]; - - g_dragWindow = window; - g_dragView = dragView; - [window setContentView: dragView]; - - NSLog(@"starting cocoa loop"); - [NSApp run]; - - NSLog(@"cocoa: release"); - [pool release]; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + [NSApplication sharedApplication]; + + NSWindow *window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 3, 3) + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + [window setTitle:@""]; + [window setAlphaValue:0.1]; + [window makeKeyAndOrderFront:nil]; + + OSXDragView *dragView = [[OSXDragView alloc] initWithFrame:NSMakeRect(0, 0, 3, 3)]; + + g_dragWindow = window; + g_dragView = dragView; + [window setContentView:dragView]; + + NSLog(@"starting cocoa loop"); + [NSApp run]; + + NSLog(@"cocoa: release"); + [pool release]; } -void -stopCocoaLoop() +void stopCocoaLoop() { - [NSApp stop: g_dragWindow]; + [NSApp stop:g_dragWindow]; } -void -fakeDragging(const char* str, int cursorX, int cursorY) +void fakeDragging(const char *str, int cursorX, int cursorY) { - g_ext = [NSString stringWithUTF8String:str]; - - dispatch_async(dispatch_get_main_queue(), ^{ - NSRect screen = [[NSScreen mainScreen] frame]; - NSLog ( @"screen size: witdh = %f height = %f", screen.size.width, screen.size.height); - NSLog ( @"mouseLocation: %d %d", cursorX, cursorY); - - int newPosX = 0; - int newPosY = 0; - newPosX = cursorX - 1; - newPosY = screen.size.height - cursorY - 1; - - NSRect rect = NSMakeRect(newPosX, newPosY, 3, 3); - NSLog ( @"newPosX: %d", newPosX); - NSLog ( @"newPosY: %d", newPosY); - - [g_dragWindow setFrame:rect display:NO]; - [g_dragWindow makeKeyAndOrderFront:nil]; - [NSApp activateIgnoringOtherApps:YES]; - - [g_dragView setFileExt:g_ext]; + g_ext = [NSString stringWithUTF8String:str]; - CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - CGEventRef down = CGEventCreateMouseEvent(source, kCGEventLeftMouseDown, CGPointMake(cursorX, cursorY), kCGMouseButtonLeft); - CGEventPost(kCGHIDEventTap, down); - CFRelease(down); - CFRelease(source); - }); + dispatch_async(dispatch_get_main_queue(), ^{ + NSRect screen = [[NSScreen mainScreen] frame]; + NSLog(@"screen size: witdh = %f height = %f", screen.size.width, screen.size.height); + NSLog(@"mouseLocation: %d %d", cursorX, cursorY); + + int newPosX = 0; + int newPosY = 0; + newPosX = cursorX - 1; + newPosY = screen.size.height - cursorY - 1; + + NSRect rect = NSMakeRect(newPosX, newPosY, 3, 3); + NSLog(@"newPosX: %d", newPosX); + NSLog(@"newPosY: %d", newPosY); + + [g_dragWindow setFrame:rect display:NO]; + [g_dragWindow makeKeyAndOrderFront:nil]; + [NSApp activateIgnoringOtherApps:YES]; + + [g_dragView setFileExt:g_ext]; + + CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); + CGEventRef down = + CGEventCreateMouseEvent(source, kCGEventLeftMouseDown, CGPointMake(cursorX, cursorY), kCGMouseButtonLeft); + CGEventPost(kCGHIDEventTap, down); + CFRelease(down); + CFRelease(source); + }); } -CFStringRef -getCocoaDropTarget() +CFStringRef getCocoaDropTarget() { - // HACK: sleep, wait for cocoa drop target updated first - usleep(1000000); - return [g_dragView getDropTarget]; + // HACK: sleep, wait for cocoa drop target updated first + usleep(1000000); + return [g_dragView getDropTarget]; } diff --git a/src/lib/platform/OSXDragView.m b/src/lib/platform/OSXDragView.m index 44da99ceb..c1ffd851b 100644 --- a/src/lib/platform/OSXDragView.m +++ b/src/lib/platform/OSXDragView.m @@ -28,139 +28,132 @@ @dynamic animatesToDestination; @dynamic numberOfValidItemsForDrop; -- (id) -initWithFrame:(NSRect)frame +- (id)initWithFrame:(NSRect)frame { - self = [super initWithFrame:frame]; - m_dropTarget = [[NSMutableString alloc] initWithCapacity:0]; - m_dragFileExt = [[NSMutableString alloc] initWithCapacity:0]; - return self; + self = [super initWithFrame:frame]; + m_dropTarget = [[NSMutableString alloc] initWithCapacity:0]; + m_dragFileExt = [[NSMutableString alloc] initWithCapacity:0]; + return self; } -- (void) -drawRect:(NSRect)dirtyRect +- (void)drawRect:(NSRect)dirtyRect { } -- (BOOL) -acceptsFirstMouse:(NSEvent *)theEvent +- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent { - return YES; + return YES; } -- (void) -mouseDown:(NSEvent *)theEvent +- (void)mouseDown:(NSEvent *)theEvent { - NSLog ( @"cocoa mouse down"); - NSPoint dragPosition; - NSRect imageLocation; - dragPosition = [self convertPoint:[theEvent locationInWindow] - fromView:nil]; - - dragPosition.x -= 16; - dragPosition.y -= 16; - imageLocation.origin = dragPosition; - imageLocation.size = NSMakeSize(32,32); - [self dragPromisedFilesOfTypes:[NSArray arrayWithObject:m_dragFileExt] - fromRect:imageLocation - source:self - slideBack:NO - event:theEvent]; + NSLog(@"cocoa mouse down"); + NSPoint dragPosition; + NSRect imageLocation; + dragPosition = [self convertPoint:[theEvent locationInWindow] fromView:nil]; + + dragPosition.x -= 16; + dragPosition.y -= 16; + imageLocation.origin = dragPosition; + imageLocation.size = NSMakeSize(32, 32); + [self dragPromisedFilesOfTypes:[NSArray arrayWithObject:m_dragFileExt] + fromRect:imageLocation + source:self + slideBack:NO + event:theEvent]; } -- (NSArray*) -namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination +- (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination { - [m_dropTarget setString:@""]; - [m_dropTarget appendString:dropDestination.path]; - NSLog ( @"cocoa drop target: %@", m_dropTarget); - return nil; + [m_dropTarget setString:@""]; + [m_dropTarget appendString:dropDestination.path]; + NSLog(@"cocoa drop target: %@", m_dropTarget); + return nil; } -- (NSDragOperation) -draggingSourceOperationMaskForLocal:(BOOL)flag +- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag { - return NSDragOperationCopy; + return NSDragOperationCopy; } -- (CFStringRef) -getDropTarget +- (CFStringRef)getDropTarget { - NSMutableString* string; - string = [[NSMutableString alloc] initWithCapacity:0]; - [string appendString:m_dropTarget]; - return (CFStringRef)string; + NSMutableString *string; + string = [[NSMutableString alloc] initWithCapacity:0]; + [string appendString:m_dropTarget]; + return (CFStringRef)string; } -- (void) -clearDropTarget +- (void)clearDropTarget { - [m_dropTarget setString:@""]; + [m_dropTarget setString:@""]; } -- (void) -setFileExt:(NSString*) ext +- (void)setFileExt:(NSString *)ext { - [ext retain]; - [m_dragFileExt release]; - m_dragFileExt = ext; - NSLog(@"drag file ext: %@", m_dragFileExt); + [ext retain]; + [m_dragFileExt release]; + m_dragFileExt = ext; + NSLog(@"drag file ext: %@", m_dragFileExt); } -- (NSWindow *) -draggingDestinationWindow +- (NSWindow *)draggingDestinationWindow { - return nil; + return nil; } -- (NSDragOperation) -draggingSourceOperationMask +- (NSDragOperation)draggingSourceOperationMask { - return NSDragOperationCopy; + return NSDragOperationCopy; } - (NSPoint)draggingLocation { - NSPoint point; - return point; + NSPoint point; + return point; } - (NSPoint)draggedImageLocation { - NSPoint point; - return point; + NSPoint point; + return point; } - (NSImage *)draggedImage { - return nil; + return nil; } - (NSPasteboard *)draggingPasteboard { - return nil; + return nil; } - (id)draggingSource { - return nil; + return nil; } - (NSInteger)draggingSequenceNumber { - return 0; + return 0; } - (void)slideDraggedImageTo:(NSPoint)screenPoint { } -- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context +- (NSDragOperation)draggingSession:(NSDraggingSession *)session + sourceOperationMaskForDraggingContext:(NSDraggingContext)context { - return NSDragOperationCopy; + return NSDragOperationCopy; } -- (void)enumerateDraggingItemsWithOptions:(NSDraggingItemEnumerationOptions)enumOpts forView:(NSView *)view classes:(NSArray *)classArray searchOptions:(NSDictionary *)searchOptions usingBlock:(void (^)(NSDraggingItem *draggingItem, NSInteger idx, BOOL *stop))block +- (void)enumerateDraggingItemsWithOptions:(NSDraggingItemEnumerationOptions)enumOpts + forView:(NSView *)view + classes:(NSArray *)classArray + searchOptions:(NSDictionary *)searchOptions + usingBlock:(void (^)(NSDraggingItem *draggingItem, NSInteger idx, BOOL *stop))block { } diff --git a/src/lib/platform/OSXMediaKeySupport.m b/src/lib/platform/OSXMediaKeySupport.m index 55920fa62..d13ea0fbf 100644 --- a/src/lib/platform/OSXMediaKeySupport.m +++ b/src/lib/platform/OSXMediaKeySupport.m @@ -22,137 +22,142 @@ int convertKeyIDToNXKeyType(KeyID id) { - int type = -1; + int type = -1; - switch (id) { - case kKeyAudioUp: - type = NX_KEYTYPE_SOUND_UP; - break; - case kKeyAudioDown: - type = NX_KEYTYPE_SOUND_DOWN; - break; - case kKeyBrightnessUp: - type = NX_KEYTYPE_BRIGHTNESS_UP; - break; - case kKeyBrightnessDown: - type = NX_KEYTYPE_BRIGHTNESS_DOWN; - break; - case kKeyAudioMute: - type = NX_KEYTYPE_MUTE; - break; - case kKeyEject: - type = NX_KEYTYPE_EJECT; - break; - case kKeyAudioPlay: - type = NX_KEYTYPE_PLAY; - break; - case kKeyAudioNext: - type = NX_KEYTYPE_NEXT; - break; - case kKeyAudioPrev: - type = NX_KEYTYPE_PREVIOUS; - break; - default: - break; - } - - return type; + switch (id) { + case kKeyAudioUp: + type = NX_KEYTYPE_SOUND_UP; + break; + case kKeyAudioDown: + type = NX_KEYTYPE_SOUND_DOWN; + break; + case kKeyBrightnessUp: + type = NX_KEYTYPE_BRIGHTNESS_UP; + break; + case kKeyBrightnessDown: + type = NX_KEYTYPE_BRIGHTNESS_DOWN; + break; + case kKeyAudioMute: + type = NX_KEYTYPE_MUTE; + break; + case kKeyEject: + type = NX_KEYTYPE_EJECT; + break; + case kKeyAudioPlay: + type = NX_KEYTYPE_PLAY; + break; + case kKeyAudioNext: + type = NX_KEYTYPE_NEXT; + break; + case kKeyAudioPrev: + type = NX_KEYTYPE_PREVIOUS; + break; + default: + break; + } + + return type; } -static KeyID -convertNXKeyTypeToKeyID(uint32_t const type) +static KeyID convertNXKeyTypeToKeyID(uint32_t const type) { - KeyID id = 0; + KeyID id = 0; - switch (type) { - case NX_KEYTYPE_SOUND_UP: - id = kKeyAudioUp; - break; - case NX_KEYTYPE_SOUND_DOWN: - id = kKeyAudioDown; - break; - case NX_KEYTYPE_MUTE: - id = kKeyAudioMute; - break; - case NX_KEYTYPE_EJECT: - id = kKeyEject; - break; - case NX_KEYTYPE_PLAY: - id = kKeyAudioPlay; - break; - case NX_KEYTYPE_FAST: - case NX_KEYTYPE_NEXT: - id = kKeyAudioNext; - break; - case NX_KEYTYPE_REWIND: - case NX_KEYTYPE_PREVIOUS: - id = kKeyAudioPrev; - break; - default: - break; - } + switch (type) { + case NX_KEYTYPE_SOUND_UP: + id = kKeyAudioUp; + break; + case NX_KEYTYPE_SOUND_DOWN: + id = kKeyAudioDown; + break; + case NX_KEYTYPE_MUTE: + id = kKeyAudioMute; + break; + case NX_KEYTYPE_EJECT: + id = kKeyEject; + break; + case NX_KEYTYPE_PLAY: + id = kKeyAudioPlay; + break; + case NX_KEYTYPE_FAST: + case NX_KEYTYPE_NEXT: + id = kKeyAudioNext; + break; + case NX_KEYTYPE_REWIND: + case NX_KEYTYPE_PREVIOUS: + id = kKeyAudioPrev; + break; + default: + break; + } - return id; + return id; } -bool -isMediaKeyEvent(CGEventRef event) { - NSEvent* nsEvent = nil; - @try { - nsEvent = [NSEvent eventWithCGEvent: event]; - if ([nsEvent subtype] != 8) { - return false; - } - uint32_t const nxKeyId = ([nsEvent data1] & 0xFFFF0000) >> 16; - if (convertNXKeyTypeToKeyID (nxKeyId)) { - return true; - } - } @catch (NSException* e) { - } - return false; -} - -bool -getMediaKeyEventInfo(CGEventRef event, KeyID* const keyId, - bool* const down, bool* const isRepeat) { - NSEvent* nsEvent = nil; - @try { - nsEvent = [NSEvent eventWithCGEvent: event]; - } @catch (NSException* e) { - return false; - } - if (keyId) { - *keyId = convertNXKeyTypeToKeyID (([nsEvent data1] & 0xFFFF0000) >> 16); - } - if (down) { - *down = !([nsEvent data1] & 0x100); - } - if (isRepeat) { - *isRepeat = [nsEvent data1] & 0x1; - } - return true; -} - -bool -fakeNativeMediaKey(KeyID id) +bool isMediaKeyEvent(CGEventRef event) { - - NSEvent* downRef = [NSEvent otherEventWithType:NSSystemDefined - location: NSMakePoint(0, 0) modifierFlags:0xa00 - timestamp:0 windowNumber:0 context:0 subtype:8 - data1:(convertKeyIDToNXKeyType(id) << 16) | ((0xa) << 8) - data2:-1]; - CGEventRef downEvent = [downRef CGEvent]; - - NSEvent* upRef = [NSEvent otherEventWithType:NSSystemDefined - location: NSMakePoint(0, 0) modifierFlags:0xa00 - timestamp:0 windowNumber:0 context:0 subtype:8 - data1:(convertKeyIDToNXKeyType(id) << 16) | ((0xb) << 8) - data2:-1]; - CGEventRef upEvent = [upRef CGEvent]; - - CGEventPost(0, downEvent); - CGEventPost(0, upEvent); - - return true; + NSEvent *nsEvent = nil; + @try { + nsEvent = [NSEvent eventWithCGEvent:event]; + if ([nsEvent subtype] != 8) { + return false; + } + uint32_t const nxKeyId = ([nsEvent data1] & 0xFFFF0000) >> 16; + if (convertNXKeyTypeToKeyID(nxKeyId)) { + return true; + } + } @catch (NSException *e) { + } + return false; +} + +bool getMediaKeyEventInfo(CGEventRef event, KeyID *const keyId, bool *const down, bool *const isRepeat) +{ + NSEvent *nsEvent = nil; + @try { + nsEvent = [NSEvent eventWithCGEvent:event]; + } @catch (NSException *e) { + return false; + } + if (keyId) { + *keyId = convertNXKeyTypeToKeyID(([nsEvent data1] & 0xFFFF0000) >> 16); + } + if (down) { + *down = !([nsEvent data1] & 0x100); + } + if (isRepeat) { + *isRepeat = [nsEvent data1] & 0x1; + } + return true; +} + +bool fakeNativeMediaKey(KeyID id) +{ + + NSEvent *downRef = [NSEvent otherEventWithType:NSSystemDefined + location:NSMakePoint(0, 0) + modifierFlags:0xa00 + timestamp:0 + windowNumber:0 + context:0 + subtype:8 + data1:(convertKeyIDToNXKeyType(id) << 16) | ((0xa) << 8) + data2:-1]; + CGEventRef downEvent = [downRef CGEvent]; + + NSEvent *upRef = [NSEvent otherEventWithType:NSSystemDefined + location:NSMakePoint(0, 0) + modifierFlags:0xa00 + timestamp:0 + windowNumber:0 + context:0 + subtype:8 + data1:(convertKeyIDToNXKeyType(id) << 16) | ((0xb) << 8) + data2:-1]; + CGEventRef upEvent = [upRef CGEvent]; + + CGEventPost(0, downEvent); + CGEventPost(0, upEvent); + + return true; } diff --git a/src/lib/platform/OSXPasteboardPeeker.m b/src/lib/platform/OSXPasteboardPeeker.m index 203612dcd..76e179077 100644 --- a/src/lib/platform/OSXPasteboardPeeker.m +++ b/src/lib/platform/OSXPasteboardPeeker.m @@ -14,27 +14,26 @@ #import "platform/OSXPasteboardPeeker.h" -#import -#import #import +#import +#import #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" -CFStringRef -getDraggedFileURL() +CFStringRef getDraggedFileURL() { - NSString* pbName = NSDragPboard; - NSPasteboard* pboard = [NSPasteboard pasteboardWithName:pbName]; - - NSMutableString* string; - string = [[NSMutableString alloc] initWithCapacity:0]; + NSString *pbName = NSDragPboard; + NSPasteboard *pboard = [NSPasteboard pasteboardWithName:pbName]; - NSArray* files = [pboard propertyListForType:NSFilenamesPboardType]; - for (id file in files) { - [string appendString: (NSString*)file]; - [string appendString: @"\0"]; - } - - return (CFStringRef)string; + NSMutableString *string; + string = [[NSMutableString alloc] initWithCapacity:0]; + + NSArray *files = [pboard propertyListForType:NSFilenamesPboardType]; + for (id file in files) { + [string appendString:(NSString *)file]; + [string appendString:@"\0"]; + } + + return (CFStringRef)string; } diff --git a/src/lib/platform/OSXScreen.mm b/src/lib/platform/OSXScreen.mm index c8c0a425e..a2bf45842 100644 --- a/src/lib/platform/OSXScreen.mm +++ b/src/lib/platform/OSXScreen.mm @@ -2,11 +2,11 @@ * Deskflow -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman - * + * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE that should have accompanied this file. - * + * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -18,35 +18,35 @@ #include "platform/OSXScreen.h" +#include "arch/XArch.h" #include "base/EventQueue.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "base/TMethodEventJob.h" +#include "base/TMethodJob.h" #include "client/Client.h" -#include "platform/OSXClipboard.h" -#include "platform/OSXEventQueueBuffer.h" -#include "platform/OSXKeyState.h" -#include "platform/OSXScreenSaver.h" -#include "platform/OSXDragSimulator.h" -#include "platform/OSXMediaKeySupport.h" -#include "platform/OSXPasteboardPeeker.h" -#include "deskflow/Clipboard.h" -#include "deskflow/KeyMap.h" #include "deskflow/ClientApp.h" +#include "deskflow/Clipboard.h" +#include "deskflow/DisplayInvalidException.h" +#include "deskflow/KeyMap.h" #include "mt/CondVar.h" #include "mt/Lock.h" #include "mt/Mutex.h" #include "mt/Thread.h" -#include "arch/XArch.h" -#include "base/Log.h" -#include "base/IEventQueue.h" -#include "base/TMethodEventJob.h" -#include "base/TMethodJob.h" -#include "deskflow/DisplayInvalidException.h" +#include "platform/OSXClipboard.h" +#include "platform/OSXDragSimulator.h" +#include "platform/OSXEventQueueBuffer.h" +#include "platform/OSXKeyState.h" +#include "platform/OSXMediaKeySupport.h" +#include "platform/OSXPasteboardPeeker.h" +#include "platform/OSXScreenSaver.h" -#include -#include +#include #include #include -#include #include +#include +#include #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" @@ -54,20 +54,21 @@ // The following creates a section that tells Mac OS X // that it is OK to let us inject input in the login screen. // Just the name of the section is important, not its contents. -__attribute__((used)) -__attribute__((section ("__CGPreLoginApp,__cgpreloginapp"))) -static const char magic_section[] = ""; +__attribute__((used)) __attribute__((section("__CGPreLoginApp,__cgpreloginapp"))) static const char magic_section[] = + ""; //////////////////////////////////////////////////////////// // This isn't in any Apple SDK that I know of as of yet. -enum { - kDeskflowEventMouseScroll = 11, - kDeskflowMouseScrollAxisX = 'saxx', - kDeskflowMouseScrollAxisY = 'saxy' +enum +{ + kDeskflowEventMouseScroll = 11, + kDeskflowMouseScrollAxisX = 'saxx', + kDeskflowMouseScrollAxisY = 'saxy' }; -enum { - kCarbonLoopWaitTimeout = 10 +enum +{ + kCarbonLoopWaitTimeout = 10 }; int getSecureInputEventPID(); @@ -83,1704 +84,1560 @@ void avoidHesitatingCursor(); // OSXScreen // -bool OSXScreen::s_testedForGHOM = false; -bool OSXScreen::s_hasGHOM = false; +bool OSXScreen::s_testedForGHOM = false; +bool OSXScreen::s_hasGHOM = false; -OSXScreen::OSXScreen(IEventQueue* events, - bool isPrimary, - bool enableLangSync, - deskflow::ClientScrollDirection scrollDirection) : - PlatformScreen(events, scrollDirection), - m_isPrimary(isPrimary), - m_isOnScreen(m_isPrimary), - m_cursorPosValid(false), - MouseButtonEventMap(NumButtonIDs), - m_cursorHidden(false), - m_dragNumButtonsDown(0), - m_dragTimer(NULL), - m_keyState(NULL), - m_sequenceNumber(0), - m_screensaver(NULL), - m_screensaverNotify(false), - m_ownClipboard(false), - m_clipboardTimer(NULL), - m_hiddenWindow(NULL), - m_userInputWindow(NULL), - m_switchEventHandlerRef(0), - m_pmMutex(new Mutex), - m_pmWatchThread(NULL), - m_pmThreadReady(new CondVar(m_pmMutex, false)), - m_pmRootPort(0), - m_activeModifierHotKey(0), - m_activeModifierHotKeyMask(0), - m_eventTapPort(nullptr), - m_eventTapRLSR(nullptr), - m_lastClickTime(0), - m_clickState(1), - m_lastSingleClickXCursor(0), - m_lastSingleClickYCursor(0), - m_events(events), - m_getDropTargetThread(nullptr), - m_impl(NULL) +OSXScreen::OSXScreen( + IEventQueue *events, bool isPrimary, bool enableLangSync, deskflow::ClientScrollDirection scrollDirection +) + : PlatformScreen(events, scrollDirection), + m_isPrimary(isPrimary), + m_isOnScreen(m_isPrimary), + m_cursorPosValid(false), + MouseButtonEventMap(NumButtonIDs), + m_cursorHidden(false), + m_dragNumButtonsDown(0), + m_dragTimer(NULL), + m_keyState(NULL), + m_sequenceNumber(0), + m_screensaver(NULL), + m_screensaverNotify(false), + m_ownClipboard(false), + m_clipboardTimer(NULL), + m_hiddenWindow(NULL), + m_userInputWindow(NULL), + m_switchEventHandlerRef(0), + m_pmMutex(new Mutex), + m_pmWatchThread(NULL), + m_pmThreadReady(new CondVar(m_pmMutex, false)), + m_pmRootPort(0), + m_activeModifierHotKey(0), + m_activeModifierHotKeyMask(0), + m_eventTapPort(nullptr), + m_eventTapRLSR(nullptr), + m_lastClickTime(0), + m_clickState(1), + m_lastSingleClickXCursor(0), + m_lastSingleClickYCursor(0), + m_events(events), + m_getDropTargetThread(nullptr), + m_impl(NULL) { - m_displayID = CGMainDisplayID(); - if (!updateScreenShape(m_displayID, 0)) { - throw DisplayInvalidException ("failed to initialize screen shape"); + m_displayID = CGMainDisplayID(); + if (!updateScreenShape(m_displayID, 0)) { + throw DisplayInvalidException("failed to initialize screen shape"); + } + + try { + m_screensaver = new OSXScreenSaver(m_events, getEventTarget()); + m_keyState = new OSXKeyState(m_events, AppUtil::instance().getKeyboardLayoutList(), enableLangSync); + + if (App::instance().argsBase().m_preventSleep) { + m_powerManager.disableSleep(); } - try { - m_screensaver = new OSXScreenSaver(m_events, getEventTarget()); - m_keyState = new OSXKeyState(m_events, - AppUtil::instance().getKeyboardLayoutList(), - enableLangSync); + // only needed when running as a server. + if (m_isPrimary) { - if (App::instance().argsBase().m_preventSleep) { - m_powerManager.disableSleep(); - } - - // only needed when running as a server. - if (m_isPrimary) { - #if defined(MAC_OS_X_VERSION_10_9) - // we can't pass options to show the dialog, this must be done by the gui. - if (!AXIsProcessTrusted()) { - throw XArch("assistive devices does not trust this process, allow it in system settings."); - } + // we can't pass options to show the dialog, this must be done by the gui. + if (!AXIsProcessTrusted()) { + throw XArch("assistive devices does not trust this process, allow it in system settings."); + } #else - // now deprecated in mavericks. - if (!AXAPIEnabled()) { - throw XArch("assistive devices is not enabled, enable it in system settings."); - } + // now deprecated in mavericks. + if (!AXAPIEnabled()) { + throw XArch("assistive devices is not enabled, enable it in system settings."); + } #endif - } - - // install display manager notification handler - CGDisplayRegisterReconfigurationCallback(displayReconfigurationCallback, this); + } - // install fast user switching event handler - EventTypeSpec switchEventTypes[2]; - switchEventTypes[0].eventClass = kEventClassSystem; - switchEventTypes[0].eventKind = kEventSystemUserSessionDeactivated; - switchEventTypes[1].eventClass = kEventClassSystem; - switchEventTypes[1].eventKind = kEventSystemUserSessionActivated; - EventHandlerUPP switchEventHandler = - NewEventHandlerUPP(userSwitchCallback); - InstallApplicationEventHandler(switchEventHandler, 2, switchEventTypes, - this, &m_switchEventHandlerRef); - DisposeEventHandlerUPP(switchEventHandler); + // install display manager notification handler + CGDisplayRegisterReconfigurationCallback(displayReconfigurationCallback, this); - constructMouseButtonEventMap(); + // install fast user switching event handler + EventTypeSpec switchEventTypes[2]; + switchEventTypes[0].eventClass = kEventClassSystem; + switchEventTypes[0].eventKind = kEventSystemUserSessionDeactivated; + switchEventTypes[1].eventClass = kEventClassSystem; + switchEventTypes[1].eventKind = kEventSystemUserSessionActivated; + EventHandlerUPP switchEventHandler = NewEventHandlerUPP(userSwitchCallback); + InstallApplicationEventHandler(switchEventHandler, 2, switchEventTypes, this, &m_switchEventHandlerRef); + DisposeEventHandlerUPP(switchEventHandler); - // watch for requests to sleep - m_events->adoptHandler(m_events->forOSXScreen().confirmSleep(), - getEventTarget(), - new TMethodEventJob(this, - &OSXScreen::handleConfirmSleep)); + constructMouseButtonEventMap(); - // create thread for monitoring system power state. - *m_pmThreadReady = false; + // watch for requests to sleep + m_events->adoptHandler( + m_events->forOSXScreen().confirmSleep(), getEventTarget(), + new TMethodEventJob(this, &OSXScreen::handleConfirmSleep) + ); + + // create thread for monitoring system power state. + *m_pmThreadReady = false; #if defined(MAC_OS_X_VERSION_10_7) - m_carbonLoopMutex = new Mutex(); - m_carbonLoopReady = new CondVar(m_carbonLoopMutex, false); + m_carbonLoopMutex = new Mutex(); + m_carbonLoopReady = new CondVar(m_carbonLoopMutex, false); #endif - LOG((CLOG_DEBUG "starting watchSystemPowerThread")); - m_pmWatchThread = new Thread(new TMethodJob - (this, &OSXScreen::watchSystemPowerThread)); - } - catch (...) { - m_events->removeHandler(m_events->forOSXScreen().confirmSleep(), - getEventTarget()); - if (m_switchEventHandlerRef != 0) { - RemoveEventHandler(m_switchEventHandlerRef); - } + LOG((CLOG_DEBUG "starting watchSystemPowerThread")); + m_pmWatchThread = new Thread(new TMethodJob(this, &OSXScreen::watchSystemPowerThread)); + } catch (...) { + m_events->removeHandler(m_events->forOSXScreen().confirmSleep(), getEventTarget()); + if (m_switchEventHandlerRef != 0) { + RemoveEventHandler(m_switchEventHandlerRef); + } - CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this); + CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this); - delete m_keyState; - delete m_screensaver; - throw; - } + delete m_keyState; + delete m_screensaver; + throw; + } - // install event handlers - m_events->adoptHandler(Event::kSystem, m_events->getSystemTarget(), - new TMethodEventJob(this, - &OSXScreen::handleSystemEvent)); + // install event handlers + m_events->adoptHandler( + Event::kSystem, m_events->getSystemTarget(), new TMethodEventJob(this, &OSXScreen::handleSystemEvent) + ); - // install the platform event queue - m_events->adoptBuffer(new OSXEventQueueBuffer(m_events)); + // install the platform event queue + m_events->adoptBuffer(new OSXEventQueueBuffer(m_events)); } OSXScreen::~OSXScreen() { - disable(); + disable(); - m_events->adoptBuffer(NULL); - m_events->removeHandler(Event::kSystem, m_events->getSystemTarget()); + m_events->adoptBuffer(NULL); + m_events->removeHandler(Event::kSystem, m_events->getSystemTarget()); - if (m_pmWatchThread) { - // make sure the thread has setup the runloop. - { - Lock lock(m_pmMutex); - while (!(bool)*m_pmThreadReady) { - m_pmThreadReady->wait(); - } - } + if (m_pmWatchThread) { + // make sure the thread has setup the runloop. + { + Lock lock(m_pmMutex); + while (!(bool)*m_pmThreadReady) { + m_pmThreadReady->wait(); + } + } - // now exit the thread's runloop and wait for it to exit - LOG((CLOG_DEBUG "stopping watchSystemPowerThread")); - CFRunLoopStop(m_pmRunloop); - m_pmWatchThread->wait(); - delete m_pmWatchThread; - m_pmWatchThread = NULL; - } - delete m_pmThreadReady; - delete m_pmMutex; + // now exit the thread's runloop and wait for it to exit + LOG((CLOG_DEBUG "stopping watchSystemPowerThread")); + CFRunLoopStop(m_pmRunloop); + m_pmWatchThread->wait(); + delete m_pmWatchThread; + m_pmWatchThread = NULL; + } + delete m_pmThreadReady; + delete m_pmMutex; - m_events->removeHandler(m_events->forOSXScreen().confirmSleep(), - getEventTarget()); + m_events->removeHandler(m_events->forOSXScreen().confirmSleep(), getEventTarget()); - RemoveEventHandler(m_switchEventHandlerRef); + RemoveEventHandler(m_switchEventHandlerRef); - CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this); + CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this); + + delete m_keyState; + delete m_screensaver; - delete m_keyState; - delete m_screensaver; - #if defined(MAC_OS_X_VERSION_10_7) - delete m_carbonLoopMutex; - delete m_carbonLoopReady; + delete m_carbonLoopMutex; + delete m_carbonLoopReady; #endif } -void* -OSXScreen::getEventTarget() const +void *OSXScreen::getEventTarget() const { - return const_cast(this); + return const_cast(this); } -bool -OSXScreen::getClipboard(ClipboardID, IClipboard* dst) const +bool OSXScreen::getClipboard(ClipboardID, IClipboard *dst) const { - Clipboard::copy(dst, &m_pasteboard); - return true; + Clipboard::copy(dst, &m_pasteboard); + return true; } -void -OSXScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const +void OSXScreen::getShape(SInt32 &x, SInt32 &y, SInt32 &w, SInt32 &h) const { - x = m_x; - y = m_y; - w = m_w; - h = m_h; + x = m_x; + y = m_y; + w = m_w; + h = m_h; } -void -OSXScreen::getCursorPos(SInt32& x, SInt32& y) const +void OSXScreen::getCursorPos(SInt32 &x, SInt32 &y) const { - CGEventRef event = CGEventCreate(NULL); - CGPoint mouse = CGEventGetLocation(event); - x = mouse.x; - y = mouse.y; - m_cursorPosValid = true; - m_xCursor = x; - m_yCursor = y; - CFRelease(event); + CGEventRef event = CGEventCreate(NULL); + CGPoint mouse = CGEventGetLocation(event); + x = mouse.x; + y = mouse.y; + m_cursorPosValid = true; + m_xCursor = x; + m_yCursor = y; + CFRelease(event); } -void -OSXScreen::reconfigure(UInt32) +void OSXScreen::reconfigure(UInt32) { - // do nothing + // do nothing } -void -OSXScreen::warpCursor(SInt32 x, SInt32 y) +void OSXScreen::warpCursor(SInt32 x, SInt32 y) { - // move cursor without generating events - CGPoint pos; - pos.x = x; - pos.y = y; - CGWarpMouseCursorPosition(pos); - - // save new cursor position - m_xCursor = x; - m_yCursor = y; - m_cursorPosValid = true; + // move cursor without generating events + CGPoint pos; + pos.x = x; + pos.y = y; + CGWarpMouseCursorPosition(pos); + + // save new cursor position + m_xCursor = x; + m_yCursor = y; + m_cursorPosValid = true; } -void -OSXScreen::fakeInputBegin() +void OSXScreen::fakeInputBegin() { - // FIXME -- not implemented + // FIXME -- not implemented } -void -OSXScreen::fakeInputEnd() +void OSXScreen::fakeInputEnd() { - // FIXME -- not implemented + // FIXME -- not implemented } -SInt32 -OSXScreen::getJumpZoneSize() const +SInt32 OSXScreen::getJumpZoneSize() const { - return 1; + return 1; } -bool -OSXScreen::isAnyMouseButtonDown(UInt32& buttonID) const +bool OSXScreen::isAnyMouseButtonDown(UInt32 &buttonID) const { - if (m_buttonState.test(0)) { - buttonID = kButtonLeft; - return true; - } + if (m_buttonState.test(0)) { + buttonID = kButtonLeft; + return true; + } - return (GetCurrentButtonState() != 0); + return (GetCurrentButtonState() != 0); } -void -OSXScreen::getCursorCenter(SInt32& x, SInt32& y) const +void OSXScreen::getCursorCenter(SInt32 &x, SInt32 &y) const { - x = m_xCenter; - y = m_yCenter; + x = m_xCenter; + y = m_yCenter; } -UInt32 -OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask) +UInt32 OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask) { - // get mac virtual key and modifier mask matching deskflow key and mask - UInt32 macKey, macMask; - if (!m_keyState->mapDeskflowHotKeyToMac(key, mask, macKey, macMask)) { - LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); - return 0; - } - - // choose hotkey id - UInt32 id; - if (!m_oldHotKeyIDs.empty()) { - id = m_oldHotKeyIDs.back(); - m_oldHotKeyIDs.pop_back(); - } - else { - id = m_hotKeys.size() + 1; - } + // get mac virtual key and modifier mask matching deskflow key and mask + UInt32 macKey, macMask; + if (!m_keyState->mapDeskflowHotKeyToMac(key, mask, macKey, macMask)) { + LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); + return 0; + } - // if this hot key has modifiers only then we'll handle it specially - EventHotKeyRef ref = NULL; - bool okay; - if (key == kKeyNone) { - if (m_modifierHotKeys.count(mask) > 0) { - // already registered - okay = false; - } - else { - m_modifierHotKeys[mask] = id; - okay = true; - } - } - else { - EventHotKeyID hkid = { 'SNRG', (UInt32)id }; - OSStatus status = RegisterEventHotKey(macKey, macMask, hkid, - GetApplicationEventTarget(), 0, - &ref); - okay = (status == noErr); - m_hotKeyToIDMap[HotKeyItem(macKey, macMask)] = id; - } + // choose hotkey id + UInt32 id; + if (!m_oldHotKeyIDs.empty()) { + id = m_oldHotKeyIDs.back(); + m_oldHotKeyIDs.pop_back(); + } else { + id = m_hotKeys.size() + 1; + } - if (!okay) { - m_oldHotKeyIDs.push_back(id); - m_hotKeyToIDMap.erase(HotKeyItem(macKey, macMask)); - LOG((CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", deskflow::KeyMap::formatKey(key, mask).c_str(), key, mask)); - return 0; - } - - m_hotKeys.insert(std::make_pair(id, HotKeyItem(ref, macKey, macMask))); - - LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", deskflow::KeyMap::formatKey(key, mask).c_str(), key, mask, id)); - return id; -} - -void -OSXScreen::unregisterHotKey(UInt32 id) -{ - // look up hotkey - HotKeyMap::iterator i = m_hotKeys.find(id); - if (i == m_hotKeys.end()) { - return; - } - - // unregister with OS - bool okay; - if (i->second.getRef() != NULL) { - okay = (UnregisterEventHotKey(i->second.getRef()) == noErr); - } - else { - okay = false; - // XXX -- this is inefficient - for (ModifierHotKeyMap::iterator j = m_modifierHotKeys.begin(); - j != m_modifierHotKeys.end(); ++j) { - if (j->second == id) { - m_modifierHotKeys.erase(j); - okay = true; - break; - } - } - } - if (!okay) { - LOG((CLOG_WARN "failed to unregister hotkey id=%d", id)); - } - else { - LOG((CLOG_DEBUG "unregistered hotkey id=%d", id)); - } - - // discard hot key from map and record old id for reuse - m_hotKeyToIDMap.erase(i->second); - m_hotKeys.erase(i); - m_oldHotKeyIDs.push_back(id); - if (m_activeModifierHotKey == id) { - m_activeModifierHotKey = 0; - m_activeModifierHotKeyMask = 0; - } -} - -void -OSXScreen::constructMouseButtonEventMap() -{ - const CGEventType source[NumButtonIDs][3] = { - {kCGEventLeftMouseUp, kCGEventLeftMouseDragged, kCGEventLeftMouseDown}, - {kCGEventRightMouseUp, kCGEventRightMouseDragged, kCGEventRightMouseDown}, - {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown}, - {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown}, - {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown} - }; - - for (UInt16 button = 0; button < NumButtonIDs; button++) { - MouseButtonEventMapType new_map; - for (UInt16 state = (UInt32) kMouseButtonUp; state < kMouseButtonStateMax; state++) { - CGEventType curEvent = source[button][state]; - new_map[state] = curEvent; - } - MouseButtonEventMap[button] = new_map; - } -} - -void -OSXScreen::postMouseEvent(CGPoint& pos) const -{ - // check if cursor position is valid on the client display configuration - // stkamp@users.sourceforge.net - CGDisplayCount displayCount = 0; - CGGetDisplaysWithPoint(pos, 0, NULL, &displayCount); - if (displayCount == 0) { - // cursor position invalid - clamp to bounds of last valid display. - // find the last valid display using the last cursor position. - displayCount = 0; - CGDirectDisplayID displayID; - CGGetDisplaysWithPoint(CGPointMake(m_xCursor, m_yCursor), 1, - &displayID, &displayCount); - if (displayCount != 0) { - CGRect displayRect = CGDisplayBounds(displayID); - if (pos.x < displayRect.origin.x) { - pos.x = displayRect.origin.x; - } - else if (pos.x > displayRect.origin.x + - displayRect.size.width - 1) { - pos.x = displayRect.origin.x + displayRect.size.width - 1; - } - if (pos.y < displayRect.origin.y) { - pos.y = displayRect.origin.y; - } - else if (pos.y > displayRect.origin.y + - displayRect.size.height - 1) { - pos.y = displayRect.origin.y + displayRect.size.height - 1; - } - } - } - - CGEventType type = kCGEventMouseMoved; - - SInt8 button = m_buttonState.getFirstButtonDown(); - if (button != -1) { - MouseButtonEventMapType thisButtonType = MouseButtonEventMap[button]; - type = thisButtonType[kMouseButtonDragged]; - } - - CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, static_cast(button)); - - // Dragging events also need the click state - CGEventSetIntegerValueField(event, kCGMouseEventClickState, m_clickState); - - // Fix for sticky keys - CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags(); - CGEventSetFlags(event, modifiers); - - // Set movement deltas to fix issues with certain 3D programs - SInt64 deltaX = pos.x; - deltaX -= m_xCursor; - - SInt64 deltaY = pos.y; - deltaY -= m_yCursor; - - CGEventSetIntegerValueField(event, kCGMouseEventDeltaX, deltaX); - CGEventSetIntegerValueField(event, kCGMouseEventDeltaY, deltaY); - - double deltaFX = deltaX; - double deltaFY = deltaY; - - CGEventSetDoubleValueField(event, kCGMouseEventDeltaX, deltaFX); - CGEventSetDoubleValueField(event, kCGMouseEventDeltaY, deltaFY); - - CGEventPost(kCGHIDEventTap, event); - - CFRelease(event); -} - -void -OSXScreen::fakeMouseButton(ButtonID id, bool press) -{ - // Buttons are indexed from one, but the button down array is indexed from zero - UInt32 index = mapDeskflowButtonToMac(id) - kButtonLeft; - if (index >= NumButtonIDs) { - return; - } - - CGPoint pos; - if (!m_cursorPosValid) { - SInt32 x, y; - getCursorPos(x, y); - } - pos.x = m_xCursor; - pos.y = m_yCursor; - - // variable used to detect mouse coordinate differences between - // old & new mouse clicks. Used in double click detection. - SInt32 xDiff = m_xCursor - m_lastSingleClickXCursor; - SInt32 yDiff = m_yCursor - m_lastSingleClickYCursor; - double diff = sqrt(xDiff * xDiff + yDiff * yDiff); - // max sqrt(x^2 + y^2) difference allowed to double click - // since we don't have double click distance in NX APIs - // we define our own defaults. - const double maxDiff = sqrt(2) + 0.0001; - - double clickTime = [NSEvent doubleClickInterval]; - - // As long as the click is within the time window and distance window - // increase clickState (double click, triple click, etc) - // This will allow for higher than triple click but the quartz documenation - // does not specify that this should be limited to triple click - if (press) { - if ((ARCH->time() - m_lastClickTime) <= clickTime && diff <= maxDiff){ - m_clickState++; - } - else { - m_clickState = 1; - } - - m_lastClickTime = ARCH->time(); + // if this hot key has modifiers only then we'll handle it specially + EventHotKeyRef ref = NULL; + bool okay; + if (key == kKeyNone) { + if (m_modifierHotKeys.count(mask) > 0) { + // already registered + okay = false; + } else { + m_modifierHotKeys[mask] = id; + okay = true; } - - if (m_clickState == 1){ - m_lastSingleClickXCursor = m_xCursor; - m_lastSingleClickYCursor = m_yCursor; - } - - EMouseButtonState state = press ? kMouseButtonDown : kMouseButtonUp; - - LOG((CLOG_DEBUG1 "faking mouse button id: %d press: %s", index, press ? "pressed" : "released")); - - MouseButtonEventMapType thisButtonMap = MouseButtonEventMap[index]; - CGEventType type = thisButtonMap[state]; + } else { + EventHotKeyID hkid = {'SNRG', (UInt32)id}; + OSStatus status = RegisterEventHotKey(macKey, macMask, hkid, GetApplicationEventTarget(), 0, &ref); + okay = (status == noErr); + m_hotKeyToIDMap[HotKeyItem(macKey, macMask)] = id; + } - CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, static_cast(index)); - - CGEventSetIntegerValueField(event, kCGMouseEventClickState, m_clickState); - - // Fix for sticky keys - CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags(); - CGEventSetFlags(event, modifiers); - - m_buttonState.set(index, state); - CGEventPost(kCGHIDEventTap, event); - - CFRelease(event); - - if (!press && (id == kButtonLeft)) { - if (m_fakeDraggingStarted) { - auto method = new TMethodJob(this, &OSXScreen::getDropTargetThread); - m_getDropTargetThread.reset(new Thread(method)); - } - - m_draggingStarted = false; - } + if (!okay) { + m_oldHotKeyIDs.push_back(id); + m_hotKeyToIDMap.erase(HotKeyItem(macKey, macMask)); + LOG( + (CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", deskflow::KeyMap::formatKey(key, mask).c_str(), + key, mask) + ); + return 0; + } + + m_hotKeys.insert(std::make_pair(id, HotKeyItem(ref, macKey, macMask))); + + LOG( + (CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", deskflow::KeyMap::formatKey(key, mask).c_str(), + key, mask, id) + ); + return id; } -void -OSXScreen::getDropTargetThread(void*) +void OSXScreen::unregisterHotKey(UInt32 id) +{ + // look up hotkey + HotKeyMap::iterator i = m_hotKeys.find(id); + if (i == m_hotKeys.end()) { + return; + } + + // unregister with OS + bool okay; + if (i->second.getRef() != NULL) { + okay = (UnregisterEventHotKey(i->second.getRef()) == noErr); + } else { + okay = false; + // XXX -- this is inefficient + for (ModifierHotKeyMap::iterator j = m_modifierHotKeys.begin(); j != m_modifierHotKeys.end(); ++j) { + if (j->second == id) { + m_modifierHotKeys.erase(j); + okay = true; + break; + } + } + } + if (!okay) { + LOG((CLOG_WARN "failed to unregister hotkey id=%d", id)); + } else { + LOG((CLOG_DEBUG "unregistered hotkey id=%d", id)); + } + + // discard hot key from map and record old id for reuse + m_hotKeyToIDMap.erase(i->second); + m_hotKeys.erase(i); + m_oldHotKeyIDs.push_back(id); + if (m_activeModifierHotKey == id) { + m_activeModifierHotKey = 0; + m_activeModifierHotKeyMask = 0; + } +} + +void OSXScreen::constructMouseButtonEventMap() +{ + const CGEventType source[NumButtonIDs][3] = { + {kCGEventLeftMouseUp, kCGEventLeftMouseDragged, kCGEventLeftMouseDown}, + {kCGEventRightMouseUp, kCGEventRightMouseDragged, kCGEventRightMouseDown}, + {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown}, + {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown}, + {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown} + }; + + for (UInt16 button = 0; button < NumButtonIDs; button++) { + MouseButtonEventMapType new_map; + for (UInt16 state = (UInt32)kMouseButtonUp; state < kMouseButtonStateMax; state++) { + CGEventType curEvent = source[button][state]; + new_map[state] = curEvent; + } + MouseButtonEventMap[button] = new_map; + } +} + +void OSXScreen::postMouseEvent(CGPoint &pos) const +{ + // check if cursor position is valid on the client display configuration + // stkamp@users.sourceforge.net + CGDisplayCount displayCount = 0; + CGGetDisplaysWithPoint(pos, 0, NULL, &displayCount); + if (displayCount == 0) { + // cursor position invalid - clamp to bounds of last valid display. + // find the last valid display using the last cursor position. + displayCount = 0; + CGDirectDisplayID displayID; + CGGetDisplaysWithPoint(CGPointMake(m_xCursor, m_yCursor), 1, &displayID, &displayCount); + if (displayCount != 0) { + CGRect displayRect = CGDisplayBounds(displayID); + if (pos.x < displayRect.origin.x) { + pos.x = displayRect.origin.x; + } else if (pos.x > displayRect.origin.x + displayRect.size.width - 1) { + pos.x = displayRect.origin.x + displayRect.size.width - 1; + } + if (pos.y < displayRect.origin.y) { + pos.y = displayRect.origin.y; + } else if (pos.y > displayRect.origin.y + displayRect.size.height - 1) { + pos.y = displayRect.origin.y + displayRect.size.height - 1; + } + } + } + + CGEventType type = kCGEventMouseMoved; + + SInt8 button = m_buttonState.getFirstButtonDown(); + if (button != -1) { + MouseButtonEventMapType thisButtonType = MouseButtonEventMap[button]; + type = thisButtonType[kMouseButtonDragged]; + } + + CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, static_cast(button)); + + // Dragging events also need the click state + CGEventSetIntegerValueField(event, kCGMouseEventClickState, m_clickState); + + // Fix for sticky keys + CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags(); + CGEventSetFlags(event, modifiers); + + // Set movement deltas to fix issues with certain 3D programs + SInt64 deltaX = pos.x; + deltaX -= m_xCursor; + + SInt64 deltaY = pos.y; + deltaY -= m_yCursor; + + CGEventSetIntegerValueField(event, kCGMouseEventDeltaX, deltaX); + CGEventSetIntegerValueField(event, kCGMouseEventDeltaY, deltaY); + + double deltaFX = deltaX; + double deltaFY = deltaY; + + CGEventSetDoubleValueField(event, kCGMouseEventDeltaX, deltaFX); + CGEventSetDoubleValueField(event, kCGMouseEventDeltaY, deltaFY); + + CGEventPost(kCGHIDEventTap, event); + + CFRelease(event); +} + +void OSXScreen::fakeMouseButton(ButtonID id, bool press) +{ + // Buttons are indexed from one, but the button down array is indexed from zero + UInt32 index = mapDeskflowButtonToMac(id) - kButtonLeft; + if (index >= NumButtonIDs) { + return; + } + + CGPoint pos; + if (!m_cursorPosValid) { + SInt32 x, y; + getCursorPos(x, y); + } + pos.x = m_xCursor; + pos.y = m_yCursor; + + // variable used to detect mouse coordinate differences between + // old & new mouse clicks. Used in double click detection. + SInt32 xDiff = m_xCursor - m_lastSingleClickXCursor; + SInt32 yDiff = m_yCursor - m_lastSingleClickYCursor; + double diff = sqrt(xDiff * xDiff + yDiff * yDiff); + // max sqrt(x^2 + y^2) difference allowed to double click + // since we don't have double click distance in NX APIs + // we define our own defaults. + const double maxDiff = sqrt(2) + 0.0001; + + double clickTime = [NSEvent doubleClickInterval]; + + // As long as the click is within the time window and distance window + // increase clickState (double click, triple click, etc) + // This will allow for higher than triple click but the quartz documenation + // does not specify that this should be limited to triple click + if (press) { + if ((ARCH->time() - m_lastClickTime) <= clickTime && diff <= maxDiff) { + m_clickState++; + } else { + m_clickState = 1; + } + + m_lastClickTime = ARCH->time(); + } + + if (m_clickState == 1) { + m_lastSingleClickXCursor = m_xCursor; + m_lastSingleClickYCursor = m_yCursor; + } + + EMouseButtonState state = press ? kMouseButtonDown : kMouseButtonUp; + + LOG((CLOG_DEBUG1 "faking mouse button id: %d press: %s", index, press ? "pressed" : "released")); + + MouseButtonEventMapType thisButtonMap = MouseButtonEventMap[index]; + CGEventType type = thisButtonMap[state]; + + CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, static_cast(index)); + + CGEventSetIntegerValueField(event, kCGMouseEventClickState, m_clickState); + + // Fix for sticky keys + CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags(); + CGEventSetFlags(event, modifiers); + + m_buttonState.set(index, state); + CGEventPost(kCGHIDEventTap, event); + + CFRelease(event); + + if (!press && (id == kButtonLeft)) { + if (m_fakeDraggingStarted) { + auto method = new TMethodJob(this, &OSXScreen::getDropTargetThread); + m_getDropTargetThread.reset(new Thread(method)); + } + + m_draggingStarted = false; + } +} + +void OSXScreen::getDropTargetThread(void *) { #if defined(MAC_OS_X_VERSION_10_7) - // wait for 5 secs for the drop destinaiton string to be filled. - UInt32 timeout = ARCH->time() + 5; - m_dropTarget.clear(); + // wait for 5 secs for the drop destinaiton string to be filled. + UInt32 timeout = ARCH->time() + 5; + m_dropTarget.clear(); - while (ARCH->time() < timeout) { - CFStringRef cfstr = getCocoaDropTarget(); - char* cstr = CFStringRefToUTF8String(cfstr); - CFRelease(cfstr); - - if (cstr != NULL) { - LOG((CLOG_DEBUG "drop target: %s", cstr)); - m_dropTarget = cstr; - free(cstr); - break; - } - ARCH->sleep(.1f); - } - - if (m_dropTarget.empty()) { - LOG((CLOG_ERR "failed to get drop target")); - } + while (ARCH->time() < timeout) { + CFStringRef cfstr = getCocoaDropTarget(); + char *cstr = CFStringRefToUTF8String(cfstr); + CFRelease(cfstr); + + if (cstr != NULL) { + LOG((CLOG_DEBUG "drop target: %s", cstr)); + m_dropTarget = cstr; + free(cstr); + break; + } + ARCH->sleep(.1f); + } + + if (m_dropTarget.empty()) { + LOG((CLOG_ERR "failed to get drop target")); + } #else - LOG((CLOG_WARN "drag drop not supported")); + LOG((CLOG_WARN "drag drop not supported")); #endif - m_fakeDraggingStarted = false; + m_fakeDraggingStarted = false; } -void -OSXScreen::fakeMouseMove(SInt32 x, SInt32 y) +void OSXScreen::fakeMouseMove(SInt32 x, SInt32 y) { - if (m_fakeDraggingStarted) { - m_buttonState.set(0, kMouseButtonDown); - } - - // index 0 means left mouse button - if (m_buttonState.test(0)) { - m_draggingStarted = true; - } - - // synthesize event - CGPoint pos; - pos.x = x; - pos.y = y; - postMouseEvent(pos); + if (m_fakeDraggingStarted) { + m_buttonState.set(0, kMouseButtonDown); + } - // save new cursor position - m_xCursor = static_cast(pos.x); - m_yCursor = static_cast(pos.y); - m_cursorPosValid = true; + // index 0 means left mouse button + if (m_buttonState.test(0)) { + m_draggingStarted = true; + } + + // synthesize event + CGPoint pos; + pos.x = x; + pos.y = y; + postMouseEvent(pos); + + // save new cursor position + m_xCursor = static_cast(pos.x); + m_yCursor = static_cast(pos.y); + m_cursorPosValid = true; } -void -OSXScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const +void OSXScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const { - // OS X does not appear to have a fake relative mouse move function. - // simulate it by getting the current mouse position and adding to - // that. this can yield the wrong answer but there's not much else - // we can do. + // OS X does not appear to have a fake relative mouse move function. + // simulate it by getting the current mouse position and adding to + // that. this can yield the wrong answer but there's not much else + // we can do. - // get current position - CGEventRef event = CGEventCreate(NULL); - CGPoint oldPos = CGEventGetLocation(event); - CFRelease(event); + // get current position + CGEventRef event = CGEventCreate(NULL); + CGPoint oldPos = CGEventGetLocation(event); + CFRelease(event); - // synthesize event - CGPoint pos; - m_xCursor = static_cast(oldPos.x); - m_yCursor = static_cast(oldPos.y); - pos.x = oldPos.x + dx; - pos.y = oldPos.y + dy; - postMouseEvent(pos); + // synthesize event + CGPoint pos; + m_xCursor = static_cast(oldPos.x); + m_yCursor = static_cast(oldPos.y); + pos.x = oldPos.x + dx; + pos.y = oldPos.y + dy; + postMouseEvent(pos); - // we now assume we don't know the current cursor position - m_cursorPosValid = false; + // we now assume we don't know the current cursor position + m_cursorPosValid = false; } -void -OSXScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const +void OSXScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const { - if (xDelta != 0 || yDelta != 0) { - // create a scroll event, post it and release it. not sure if kCGScrollEventUnitLine - // is the right choice here over kCGScrollEventUnitPixel - CGEventRef scrollEvent = CGEventCreateScrollWheelEvent( - NULL, kCGScrollEventUnitLine, 2, - mapScrollWheelFromDeskflow(yDelta), - mapScrollWheelFromDeskflow(xDelta)); + if (xDelta != 0 || yDelta != 0) { + // create a scroll event, post it and release it. not sure if kCGScrollEventUnitLine + // is the right choice here over kCGScrollEventUnitPixel + CGEventRef scrollEvent = CGEventCreateScrollWheelEvent( + NULL, kCGScrollEventUnitLine, 2, mapScrollWheelFromDeskflow(yDelta), mapScrollWheelFromDeskflow(xDelta) + ); - // Fix for sticky keys - CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags(); - CGEventSetFlags(scrollEvent, modifiers); - - CGEventPost(kCGHIDEventTap, scrollEvent); - CFRelease(scrollEvent); - } + // Fix for sticky keys + CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags(); + CGEventSetFlags(scrollEvent, modifiers); + + CGEventPost(kCGHIDEventTap, scrollEvent); + CFRelease(scrollEvent); + } } -void -OSXScreen::showCursor() +void OSXScreen::showCursor() { - LOG((CLOG_DEBUG "showing cursor")); + LOG((CLOG_DEBUG "showing cursor")); - CFStringRef propertyString = CFStringCreateWithCString( - NULL, "SetsCursorInBackground", kCFStringEncodingMacRoman); + CFStringRef propertyString = CFStringCreateWithCString(NULL, "SetsCursorInBackground", kCFStringEncodingMacRoman); - CGSSetConnectionProperty( - _CGSDefaultConnection(), _CGSDefaultConnection(), - propertyString, kCFBooleanTrue); + CGSSetConnectionProperty(_CGSDefaultConnection(), _CGSDefaultConnection(), propertyString, kCFBooleanTrue); - CFRelease(propertyString); + CFRelease(propertyString); - CGError error = CGDisplayShowCursor(m_displayID); - if (error != kCGErrorSuccess) { - LOG((CLOG_ERR "failed to show cursor, error=%d", error)); - } + CGError error = CGDisplayShowCursor(m_displayID); + if (error != kCGErrorSuccess) { + LOG((CLOG_ERR "failed to show cursor, error=%d", error)); + } - // appears to fix "mouse randomly not showing" bug - CGAssociateMouseAndMouseCursorPosition(true); + // appears to fix "mouse randomly not showing" bug + CGAssociateMouseAndMouseCursorPosition(true); - logCursorVisibility(); + logCursorVisibility(); - m_cursorHidden = false; + m_cursorHidden = false; } -void -OSXScreen::hideCursor() +void OSXScreen::hideCursor() { - LOG((CLOG_DEBUG "hiding cursor")); + LOG((CLOG_DEBUG "hiding cursor")); - CFStringRef propertyString = CFStringCreateWithCString( - NULL, "SetsCursorInBackground", kCFStringEncodingMacRoman); + CFStringRef propertyString = CFStringCreateWithCString(NULL, "SetsCursorInBackground", kCFStringEncodingMacRoman); - CGSSetConnectionProperty( - _CGSDefaultConnection(), _CGSDefaultConnection(), - propertyString, kCFBooleanTrue); + CGSSetConnectionProperty(_CGSDefaultConnection(), _CGSDefaultConnection(), propertyString, kCFBooleanTrue); - CFRelease(propertyString); + CFRelease(propertyString); - CGError error = CGDisplayHideCursor(m_displayID); - if (error != kCGErrorSuccess) { - LOG((CLOG_ERR "failed to hide cursor, error=%d", error)); - } + CGError error = CGDisplayHideCursor(m_displayID); + if (error != kCGErrorSuccess) { + LOG((CLOG_ERR "failed to hide cursor, error=%d", error)); + } - // appears to fix "mouse randomly not hiding" bug - CGAssociateMouseAndMouseCursorPosition(true); + // appears to fix "mouse randomly not hiding" bug + CGAssociateMouseAndMouseCursorPosition(true); - logCursorVisibility(); + logCursorVisibility(); - m_cursorHidden = true; + m_cursorHidden = true; } -void -OSXScreen::enable() +void OSXScreen::enable() { - // watch the clipboard - m_clipboardTimer = m_events->newTimer(1.0, NULL); - m_events->adoptHandler(Event::kTimer, m_clipboardTimer, - new TMethodEventJob(this, - &OSXScreen::handleClipboardCheck)); + // watch the clipboard + m_clipboardTimer = m_events->newTimer(1.0, NULL); + m_events->adoptHandler( + Event::kTimer, m_clipboardTimer, new TMethodEventJob(this, &OSXScreen::handleClipboardCheck) + ); - if (m_isPrimary) { - // FIXME -- start watching jump zones - - // kCGEventTapOptionDefault = 0x00000000 (Missing in 10.4, so specified literally) - m_eventTapPort = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, - kCGEventMaskForAllEvents, - handleCGInputEvent, - this); - } - else { - // FIXME -- prevent system from entering power save mode + if (m_isPrimary) { + // FIXME -- start watching jump zones - hideCursor(); + // kCGEventTapOptionDefault = 0x00000000 (Missing in 10.4, so specified literally) + m_eventTapPort = CGEventTapCreate( + kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, kCGEventMaskForAllEvents, handleCGInputEvent, + this + ); + } else { + // FIXME -- prevent system from entering power save mode - // warp the mouse to the cursor center - fakeMouseMove(m_xCenter, m_yCenter); - - // there may be a better way to do this, but we register an event handler even if we're - // not on the primary display (acting as a client). This way, if a local event comes in - // (either keyboard or mouse), we can make sure to show the cursor if we've hidden it. - m_eventTapPort = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, - kCGEventMaskForAllEvents, - handleCGInputEventSecondary, - this); - } - - if (m_eventTapPort) { - m_eventTapRLSR = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, m_eventTapPort, 0); - if (m_eventTapRLSR) { - CFRunLoopAddSource(CFRunLoopGetCurrent(), m_eventTapRLSR, kCFRunLoopDefaultMode); - } - else{ - LOG((CLOG_ERR "failed to create a CFRunLoopSourceRef for the quartz event tap")); - } - } - else{ - LOG((CLOG_ERR "failed to create quartz event tap")); - } -} - -void -OSXScreen::disable() -{ - showCursor(); - - // FIXME -- stop watching jump zones, stop capturing input - - if (m_eventTapRLSR) { - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_eventTapRLSR, kCFRunLoopDefaultMode); - CFRelease(m_eventTapRLSR); - m_eventTapRLSR = nullptr; - } - - if (m_eventTapPort) { - CGEventTapEnable(m_eventTapPort, false); - CFRelease(m_eventTapPort); - m_eventTapPort = nullptr; - } - // FIXME -- allow system to enter power saving mode - - // disable drag handling - m_dragNumButtonsDown = 0; - enableDragTimer(false); - - // uninstall clipboard timer - if (m_clipboardTimer != NULL) { - m_events->removeHandler(Event::kTimer, m_clipboardTimer); - m_events->deleteTimer(m_clipboardTimer); - m_clipboardTimer = NULL; - } - - m_isOnScreen = m_isPrimary; -} - -void -OSXScreen::enter() -{ - showCursor(); - - if (m_isPrimary) { - setZeroSuppressionInterval(); - } - else { - // reset buttons - m_buttonState.reset(); - - // wakes the client screen - io_registry_entry_t entry = IORegistryEntryFromPath( - kIOMasterPortDefault, - "IOService:/IOResources/IODisplayWrangler"); - - if (entry != MACH_PORT_NULL) { - IORegistryEntrySetCFProperty(entry, CFSTR("IORequestIdle"), kCFBooleanFalse); - IOObjectRelease(entry); - } - - avoidSupression(); - } - - // now on screen - m_isOnScreen = true; -} - -bool -OSXScreen::canLeave() -{ - return true; -} - -void -OSXScreen::leave() -{ hideCursor(); - if (isDraggingStarted()) { - String& fileList = getDraggingFilename(); - - if (!m_isPrimary) { - if (fileList.empty() == false) { - ClientApp& app = ClientApp::instance(); - Client* client = app.getClientPtr(); - - DragInformation di; - di.setFilename(fileList); - DragFileList dragFileList; - dragFileList.push_back(di); - String info; - UInt32 fileCount = DragInformation::setupDragInfo( - dragFileList, info); - client->sendDragInfo(fileCount, info, info.size()); - LOG((CLOG_DEBUG "send dragging file to server")); - - // TODO: what to do with multiple file or even - // a folder - client->sendFileToServer(fileList.c_str()); - } - } - m_draggingStarted = false; - } - - if (m_isPrimary) { - avoidHesitatingCursor(); + // warp the mouse to the cursor center + fakeMouseMove(m_xCenter, m_yCenter); - } + // there may be a better way to do this, but we register an event handler even if we're + // not on the primary display (acting as a client). This way, if a local event comes in + // (either keyboard or mouse), we can make sure to show the cursor if we've hidden it. + m_eventTapPort = CGEventTapCreate( + kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, kCGEventMaskForAllEvents, + handleCGInputEventSecondary, this + ); + } - // now off screen - m_isOnScreen = false; + if (m_eventTapPort) { + m_eventTapRLSR = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, m_eventTapPort, 0); + if (m_eventTapRLSR) { + CFRunLoopAddSource(CFRunLoopGetCurrent(), m_eventTapRLSR, kCFRunLoopDefaultMode); + } else { + LOG((CLOG_ERR "failed to create a CFRunLoopSourceRef for the quartz event tap")); + } + } else { + LOG((CLOG_ERR "failed to create quartz event tap")); + } } -bool -OSXScreen::setClipboard(ClipboardID, const IClipboard* src) +void OSXScreen::disable() { - if (src != NULL) { - LOG((CLOG_DEBUG "setting clipboard")); - Clipboard::copy(&m_pasteboard, src); - } - return true; + showCursor(); + + // FIXME -- stop watching jump zones, stop capturing input + + if (m_eventTapRLSR) { + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_eventTapRLSR, kCFRunLoopDefaultMode); + CFRelease(m_eventTapRLSR); + m_eventTapRLSR = nullptr; + } + + if (m_eventTapPort) { + CGEventTapEnable(m_eventTapPort, false); + CFRelease(m_eventTapPort); + m_eventTapPort = nullptr; + } + // FIXME -- allow system to enter power saving mode + + // disable drag handling + m_dragNumButtonsDown = 0; + enableDragTimer(false); + + // uninstall clipboard timer + if (m_clipboardTimer != NULL) { + m_events->removeHandler(Event::kTimer, m_clipboardTimer); + m_events->deleteTimer(m_clipboardTimer); + m_clipboardTimer = NULL; + } + + m_isOnScreen = m_isPrimary; } -void -OSXScreen::checkClipboards() +void OSXScreen::enter() { - LOG((CLOG_DEBUG2 "checking clipboard")); - if (m_pasteboard.synchronize()) { - LOG((CLOG_DEBUG "clipboard changed")); - sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), kClipboardClipboard); - sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), kClipboardSelection); - } -} + showCursor(); -void -OSXScreen::openScreensaver(bool notify) -{ - m_screensaverNotify = notify; - if (!m_screensaverNotify) { - m_screensaver->disable(); - } -} + if (m_isPrimary) { + setZeroSuppressionInterval(); + } else { + // reset buttons + m_buttonState.reset(); -void -OSXScreen::closeScreensaver() -{ - if (!m_screensaverNotify) { - m_screensaver->enable(); - } -} + // wakes the client screen + io_registry_entry_t entry = + IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/IOResources/IODisplayWrangler"); -void -OSXScreen::screensaver(bool activate) -{ - if (activate) { - m_screensaver->activate(); - } - else { - m_screensaver->deactivate(); - } -} - -void -OSXScreen::resetOptions() -{ - // no options -} - -void -OSXScreen::setOptions(const OptionsList&) -{ - // no options -} - -void -OSXScreen::setSequenceNumber(UInt32 seqNum) -{ - m_sequenceNumber = seqNum; -} - -bool -OSXScreen::isPrimary() const -{ - return m_isPrimary; -} - -void -OSXScreen::sendEvent(Event::Type type, void* data) const -{ - m_events->addEvent(Event(type, getEventTarget(), data)); -} - -void -OSXScreen::sendClipboardEvent(Event::Type type, ClipboardID id) const -{ - ClipboardInfo* info = (ClipboardInfo*)malloc(sizeof(ClipboardInfo)); - info->m_id = id; - info->m_sequenceNumber = m_sequenceNumber; - sendEvent(type, info); -} - -void -OSXScreen::handleSystemEvent(const Event& event, void*) -{ - EventRef* carbonEvent = static_cast(event.getData()); - assert(carbonEvent != NULL); - - UInt32 eventClass = GetEventClass(*carbonEvent); - - switch (eventClass) { - case kEventClassMouse: - switch (GetEventKind(*carbonEvent)) { - case kDeskflowEventMouseScroll: - { - OSStatus r; - long xScroll; - long yScroll; - - // get scroll amount - r = GetEventParameter(*carbonEvent, - kDeskflowMouseScrollAxisX, - typeSInt32, - NULL, - sizeof(xScroll), - NULL, - &xScroll); - if (r != noErr) { - xScroll = 0; - } - r = GetEventParameter(*carbonEvent, - kDeskflowMouseScrollAxisY, - typeSInt32, - NULL, - sizeof(yScroll), - NULL, - &yScroll); - if (r != noErr) { - yScroll = 0; - } - - if (xScroll != 0 || yScroll != 0) { - onMouseWheel(-mapScrollWheelToDeskflow(xScroll), - mapScrollWheelToDeskflow(yScroll)); - } - } - } - break; - - case kEventClassKeyboard: - switch (GetEventKind(*carbonEvent)) { - case kEventHotKeyPressed: - case kEventHotKeyReleased: - onHotKey(*carbonEvent); - break; - } - - break; - - case kEventClassWindow: - // 2nd param was formerly GetWindowEventTarget(m_userInputWindow) which is 32-bit only, - // however as m_userInputWindow is never initialized to anything we can take advantage of - // the fact that GetWindowEventTarget(NULL) == NULL - SendEventToEventTarget(*carbonEvent, NULL); - switch (GetEventKind(*carbonEvent)) { - case kEventWindowActivated: - LOG((CLOG_DEBUG1 "window activated")); - break; - - case kEventWindowDeactivated: - LOG((CLOG_DEBUG1 "window deactivated")); - break; - - case kEventWindowFocusAcquired: - LOG((CLOG_DEBUG1 "focus acquired")); - break; - - case kEventWindowFocusRelinquish: - LOG((CLOG_DEBUG1 "focus released")); - break; - } - break; - - default: - SendEventToEventTarget(*carbonEvent, GetEventDispatcherTarget()); - break; - } -} - -bool -OSXScreen::onMouseMove(CGFloat mx, CGFloat my) -{ - LOG((CLOG_DEBUG2 "mouse move %+f,%+f", mx, my)); - - CGFloat x = mx - m_xCursor; - CGFloat y = my - m_yCursor; - - if ((x == 0 && y == 0) || (mx == m_xCenter && mx == m_yCenter)) { - return true; - } - - // save position to compute delta of next motion - m_xCursor = (SInt32)mx; - m_yCursor = (SInt32)my; - - if (m_isOnScreen) { - // motion on primary screen - sendEvent(m_events->forIPrimaryScreen().motionOnPrimary(), - MotionInfo::alloc(m_xCursor, m_yCursor)); - if (m_buttonState.test(0)) { - m_draggingStarted = true; - } - } - else { - // motion on secondary screen. warp mouse back to - // center. - warpCursor(m_xCenter, m_yCenter); - - // examine the motion. if it's about the distance - // from the center of the screen to an edge then - // it's probably a bogus motion that we want to - // ignore (see warpCursorNoFlush() for a further - // description). - static SInt32 bogusZoneSize = 10; - if (-x + bogusZoneSize > m_xCenter - m_x || - x + bogusZoneSize > m_x + m_w - m_xCenter || - -y + bogusZoneSize > m_yCenter - m_y || - y + bogusZoneSize > m_y + m_h - m_yCenter) { - LOG((CLOG_DEBUG "dropped bogus motion %+d,%+d", x, y)); - } - else { - // send motion - // Accumulate together the move into the running total - static CGFloat m_xFractionalMove = 0; - static CGFloat m_yFractionalMove = 0; - - m_xFractionalMove += x; - m_yFractionalMove += y; - - // Return the integer part - SInt32 intX = (SInt32)m_xFractionalMove; - SInt32 intY = (SInt32)m_yFractionalMove; - - // And keep only the fractional part - m_xFractionalMove -= intX; - m_yFractionalMove -= intY; - sendEvent(m_events->forIPrimaryScreen().motionOnSecondary(), MotionInfo::alloc(intX, intY)); - } - } - - return true; -} - -bool -OSXScreen::onMouseButton(bool pressed, UInt16 macButton) -{ - // Buttons 2 and 3 are inverted on the mac - ButtonID button = mapMacButtonToDeskflow(macButton); - - if (pressed) { - LOG((CLOG_DEBUG1 "event: button press button=%d", button)); - if (button != kButtonNone) { - KeyModifierMask mask = m_keyState->getActiveModifiers(); - sendEvent(m_events->forIPrimaryScreen().buttonDown(), ButtonInfo::alloc(button, mask)); - } - } - else { - LOG((CLOG_DEBUG1 "event: button release button=%d", button)); - if (button != kButtonNone) { - KeyModifierMask mask = m_keyState->getActiveModifiers(); - sendEvent(m_events->forIPrimaryScreen().buttonUp(), ButtonInfo::alloc(button, mask)); - } - } - - // handle drags with any button other than button 1 or 2 - if (macButton > 2) { - if (pressed) { - // one more button - if (m_dragNumButtonsDown++ == 0) { - enableDragTimer(true); - } - } - else { - // one less button - if (--m_dragNumButtonsDown == 0) { - enableDragTimer(false); - } - } - } - - if (macButton == kButtonLeft) { - EMouseButtonState state = pressed ? kMouseButtonDown : kMouseButtonUp; - m_buttonState.set(kButtonLeft - 1, state); - if (pressed) { - m_draggingFilename.clear(); - LOG((CLOG_DEBUG2 "dragging file directory is cleared")); - } - else { - if (m_fakeDraggingStarted) { - auto method = new TMethodJob(this, &OSXScreen::getDropTargetThread); - m_getDropTargetThread.reset(new Thread(method)); - } - - m_draggingStarted = false; - } - } - - return true; -} - -bool -OSXScreen::onMouseWheel(SInt32 xDelta, SInt32 yDelta) const -{ - LOG((CLOG_DEBUG1 "event: button wheel delta=%+d,%+d", xDelta, yDelta)); - sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(xDelta, yDelta)); - return true; -} - -void -OSXScreen::handleClipboardCheck(const Event&, void*) -{ - checkClipboards(); -} - -void -OSXScreen::displayReconfigurationCallback(CGDirectDisplayID displayID, CGDisplayChangeSummaryFlags flags, void* inUserData) -{ - OSXScreen* screen = (OSXScreen*)inUserData; - - // Closing or opening the lid when an external monitor is - // connected causes an kCGDisplayBeginConfigurationFlag event - CGDisplayChangeSummaryFlags mask = kCGDisplayBeginConfigurationFlag | kCGDisplayMovedFlag | - kCGDisplaySetModeFlag | kCGDisplayAddFlag | kCGDisplayRemoveFlag | - kCGDisplayEnabledFlag | kCGDisplayDisabledFlag | - kCGDisplayMirrorFlag | kCGDisplayUnMirrorFlag | - kCGDisplayDesktopShapeChangedFlag; - - LOG((CLOG_DEBUG1 "event: display was reconfigured: %x %x %x", flags, mask, flags & mask)); - - if (flags & mask) { /* Something actually did change */ - LOG((CLOG_DEBUG1 "event: screen changed shape; refreshing dimensions")); - if (!screen->updateScreenShape(displayID, flags)) { - LOG((CLOG_ERR "failed to update screen shape during display reconfiguration")); - } - } -} - -bool -OSXScreen::onKey(CGEventRef event) -{ - CGEventType eventKind = CGEventGetType(event); - - // get the key and active modifiers - UInt32 virtualKey = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode); - CGEventFlags macMask = CGEventGetFlags(event); - LOG((CLOG_DEBUG1 "event: Key event kind: %d, keycode=%d", eventKind, virtualKey)); - - // Special handling to track state of modifiers - if (eventKind == kCGEventFlagsChanged) { - // get old and new modifier state - KeyModifierMask oldMask = getActiveModifiers(); - KeyModifierMask newMask = m_keyState->mapModifiersFromOSX(macMask); - m_keyState->handleModifierKeys(getEventTarget(), oldMask, newMask); - - // if the current set of modifiers exactly matches a modifiers-only - // hot key then generate a hot key down event. - if (m_activeModifierHotKey == 0) { - if (m_modifierHotKeys.count(newMask) > 0) { - m_activeModifierHotKey = m_modifierHotKeys[newMask]; - m_activeModifierHotKeyMask = newMask; - m_events->addEvent(Event(m_events->forIPrimaryScreen().hotKeyDown(), - getEventTarget(), - HotKeyInfo::alloc(m_activeModifierHotKey))); - } - } - - // if a modifiers-only hot key is active and should no longer be - // then generate a hot key up event. - else if (m_activeModifierHotKey != 0) { - KeyModifierMask mask = (newMask & m_activeModifierHotKeyMask); - if (mask != m_activeModifierHotKeyMask) { - m_events->addEvent(Event(m_events->forIPrimaryScreen().hotKeyUp(), - getEventTarget(), - HotKeyInfo::alloc(m_activeModifierHotKey))); - m_activeModifierHotKey = 0; - m_activeModifierHotKeyMask = 0; - } - } - - return true; - } - - // check for hot key - HotKeyToIDMap::const_iterator i = - m_hotKeyToIDMap.find(HotKeyItem(virtualKey, - m_keyState->mapModifiersToCarbon(macMask) - & 0xff00u)); - if (i != m_hotKeyToIDMap.end()) { - UInt32 id = i->second; - - // determine event type - Event::Type type; - //UInt32 eventKind = GetEventKind(event); - if (eventKind == kCGEventKeyDown) { - type = m_events->forIPrimaryScreen().hotKeyDown(); - } - else if (eventKind == kCGEventKeyUp) { - type = m_events->forIPrimaryScreen().hotKeyUp(); - } - else { - return false; - } - - m_events->addEvent(Event(type, getEventTarget(), - HotKeyInfo::alloc(id))); - - return true; - } - - // decode event type - bool down = (eventKind == kCGEventKeyDown); - bool up = (eventKind == kCGEventKeyUp); - bool isRepeat = (CGEventGetIntegerValueField(event, kCGKeyboardEventAutorepeat) == 1); - - // map event to keys - KeyModifierMask mask; - OSXKeyState::KeyIDs keys; - KeyButton button = m_keyState->mapKeyFromEvent(keys, &mask, event); - if (button == 0) { - return false; - } - - // check for AltGr in mask. if set we send neither the AltGr nor - // the super modifiers to clients then remove AltGr before passing - // the modifiers to onKey. - KeyModifierMask sendMask = (mask & ~KeyModifierAltGr); - if ((mask & KeyModifierAltGr) != 0) { - sendMask &= ~KeyModifierSuper; - } - mask &= ~KeyModifierAltGr; - - // update button state - if (down) { - m_keyState->onKey(button, true, mask); - } - else if (up) { - if (!m_keyState->isKeyDown(button)) { - // up event for a dead key. throw it away. - return false; - } - m_keyState->onKey(button, false, mask); - } - - // send key events - for (OSXKeyState::KeyIDs::const_iterator i = keys.begin(); - i != keys.end(); ++i) { - m_keyState->sendKeyEvent(getEventTarget(), down, isRepeat, - *i, sendMask, 1, button); - } - - return true; -} - -void -OSXScreen::onMediaKey(CGEventRef event) -{ - KeyID keyID; - bool down; - bool isRepeat; - - if (!getMediaKeyEventInfo (event, &keyID, &down, &isRepeat)) { - LOG ((CLOG_ERR "Failed to decode media key event")); - return; - } - - LOG ((CLOG_DEBUG2 "Media key event: keyID=0x%02x, %s, repeat=%s", - keyID, (down ? "down": "up"), - (isRepeat ? "yes" : "no"))); - - KeyButton button = 0; - KeyModifierMask mask = m_keyState->getActiveModifiers(); - m_keyState->sendKeyEvent(getEventTarget(), down, isRepeat, keyID, mask, 1, button); -} - -bool -OSXScreen::onHotKey(EventRef event) const -{ - // get the hotkey id - EventHotKeyID hkid; - GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, - NULL, sizeof(EventHotKeyID), NULL, &hkid); - UInt32 id = hkid.id; - - // determine event type - Event::Type type; - UInt32 eventKind = GetEventKind(event); - if (eventKind == kEventHotKeyPressed) { - type = m_events->forIPrimaryScreen().hotKeyDown(); - } - else if (eventKind == kEventHotKeyReleased) { - type = m_events->forIPrimaryScreen().hotKeyUp(); - } - else { - return false; - } - - m_events->addEvent(Event(type, getEventTarget(), - HotKeyInfo::alloc(id))); - - return true; -} - -ButtonID -OSXScreen::mapDeskflowButtonToMac(UInt16 button) const -{ - switch (button) { - case 1: - return kButtonLeft; - case 2: - return kMacButtonMiddle; - case 3: - return kMacButtonRight; + if (entry != MACH_PORT_NULL) { + IORegistryEntrySetCFProperty(entry, CFSTR("IORequestIdle"), kCFBooleanFalse); + IOObjectRelease(entry); } - return static_cast(button); + avoidSupression(); + } + + // now on screen + m_isOnScreen = true; } -ButtonID -OSXScreen::mapMacButtonToDeskflow(UInt16 macButton) const +bool OSXScreen::canLeave() { - switch (macButton) { - case 1: - return kButtonLeft; - - case 2: - return kButtonRight; - - case 3: - return kButtonMiddle; - } - - return static_cast(macButton); + return true; } -SInt32 -OSXScreen::mapScrollWheelToDeskflow(SInt32 x) const +void OSXScreen::leave() { - // return accelerated scrolling - double d = (1.0 + getScrollSpeed()) * x; - return static_cast(120.0 * d); + hideCursor(); + + if (isDraggingStarted()) { + String &fileList = getDraggingFilename(); + + if (!m_isPrimary) { + if (fileList.empty() == false) { + ClientApp &app = ClientApp::instance(); + Client *client = app.getClientPtr(); + + DragInformation di; + di.setFilename(fileList); + DragFileList dragFileList; + dragFileList.push_back(di); + String info; + UInt32 fileCount = DragInformation::setupDragInfo(dragFileList, info); + client->sendDragInfo(fileCount, info, info.size()); + LOG((CLOG_DEBUG "send dragging file to server")); + + // TODO: what to do with multiple file or even + // a folder + client->sendFileToServer(fileList.c_str()); + } + } + m_draggingStarted = false; + } + + if (m_isPrimary) { + avoidHesitatingCursor(); + } + + // now off screen + m_isOnScreen = false; } -SInt32 -OSXScreen::mapScrollWheelFromDeskflow(SInt32 x) const +bool OSXScreen::setClipboard(ClipboardID, const IClipboard *src) { - // use server's acceleration with a little boost since other platforms - // take one wheel step as a larger step than the mac does. - auto result = static_cast(3.0 * x / 120.0); - return mapClientScrollDirection(result); + if (src != NULL) { + LOG((CLOG_DEBUG "setting clipboard")); + Clipboard::copy(&m_pasteboard, src); + } + return true; } -double -OSXScreen::getScrollSpeed() const +void OSXScreen::checkClipboards() { - double scaling = 0.0; - - CFPropertyListRef pref = ::CFPreferencesCopyValue( - CFSTR("com.apple.scrollwheel.scaling") , - kCFPreferencesAnyApplication, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - if (pref != NULL) { - CFTypeID id = CFGetTypeID(pref); - if (id == CFNumberGetTypeID()) { - CFNumberRef value = static_cast(pref); - if (CFNumberGetValue(value, kCFNumberDoubleType, &scaling)) { - if (scaling < 0.0) { - scaling = 0.0; - } - } - } - CFRelease(pref); - } - - return scaling; + LOG((CLOG_DEBUG2 "checking clipboard")); + if (m_pasteboard.synchronize()) { + LOG((CLOG_DEBUG "clipboard changed")); + sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), kClipboardClipboard); + sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), kClipboardSelection); + } } -void -OSXScreen::enableDragTimer(bool enable) +void OSXScreen::openScreensaver(bool notify) { - if (enable && m_dragTimer == NULL) { - m_dragTimer = m_events->newTimer(0.01, NULL); - m_events->adoptHandler(Event::kTimer, m_dragTimer, - new TMethodEventJob(this, - &OSXScreen::handleDrag)); - CGEventRef event = CGEventCreate(NULL); - CGPoint mouse = CGEventGetLocation(event); - m_dragLastPoint.h = (short)mouse.x; - m_dragLastPoint.v = (short)mouse.y; - CFRelease(event); - } - else if (!enable && m_dragTimer != NULL) { - m_events->removeHandler(Event::kTimer, m_dragTimer); - m_events->deleteTimer(m_dragTimer); - m_dragTimer = NULL; - } + m_screensaverNotify = notify; + if (!m_screensaverNotify) { + m_screensaver->disable(); + } } -void -OSXScreen::handleDrag(const Event&, void*) +void OSXScreen::closeScreensaver() { - CGEventRef event = CGEventCreate(NULL); - CGPoint p = CGEventGetLocation(event); - CFRelease(event); - - if ((short)p.x != m_dragLastPoint.h || (short)p.y != m_dragLastPoint.v) { - m_dragLastPoint.h = (short)p.x; - m_dragLastPoint.v = (short)p.y; - onMouseMove((SInt32)p.x, (SInt32)p.y); - } + if (!m_screensaverNotify) { + m_screensaver->enable(); + } } -void -OSXScreen::updateButtons() +void OSXScreen::screensaver(bool activate) { - UInt32 buttons = GetCurrentButtonState(); - - m_buttonState.overwrite(buttons); + if (activate) { + m_screensaver->activate(); + } else { + m_screensaver->deactivate(); + } } -IKeyState* -OSXScreen::getKeyState() const +void OSXScreen::resetOptions() { - return m_keyState; + // no options +} + +void OSXScreen::setOptions(const OptionsList &) +{ + // no options +} + +void OSXScreen::setSequenceNumber(UInt32 seqNum) +{ + m_sequenceNumber = seqNum; +} + +bool OSXScreen::isPrimary() const +{ + return m_isPrimary; +} + +void OSXScreen::sendEvent(Event::Type type, void *data) const +{ + m_events->addEvent(Event(type, getEventTarget(), data)); +} + +void OSXScreen::sendClipboardEvent(Event::Type type, ClipboardID id) const +{ + ClipboardInfo *info = (ClipboardInfo *)malloc(sizeof(ClipboardInfo)); + info->m_id = id; + info->m_sequenceNumber = m_sequenceNumber; + sendEvent(type, info); +} + +void OSXScreen::handleSystemEvent(const Event &event, void *) +{ + EventRef *carbonEvent = static_cast(event.getData()); + assert(carbonEvent != NULL); + + UInt32 eventClass = GetEventClass(*carbonEvent); + + switch (eventClass) { + case kEventClassMouse: + switch (GetEventKind(*carbonEvent)) { + case kDeskflowEventMouseScroll: { + OSStatus r; + long xScroll; + long yScroll; + + // get scroll amount + r = GetEventParameter(*carbonEvent, kDeskflowMouseScrollAxisX, typeSInt32, NULL, sizeof(xScroll), NULL, &xScroll); + if (r != noErr) { + xScroll = 0; + } + r = GetEventParameter(*carbonEvent, kDeskflowMouseScrollAxisY, typeSInt32, NULL, sizeof(yScroll), NULL, &yScroll); + if (r != noErr) { + yScroll = 0; + } + + if (xScroll != 0 || yScroll != 0) { + onMouseWheel(-mapScrollWheelToDeskflow(xScroll), mapScrollWheelToDeskflow(yScroll)); + } + } + } + break; + + case kEventClassKeyboard: + switch (GetEventKind(*carbonEvent)) { + case kEventHotKeyPressed: + case kEventHotKeyReleased: + onHotKey(*carbonEvent); + break; + } + + break; + + case kEventClassWindow: + // 2nd param was formerly GetWindowEventTarget(m_userInputWindow) which is 32-bit only, + // however as m_userInputWindow is never initialized to anything we can take advantage of + // the fact that GetWindowEventTarget(NULL) == NULL + SendEventToEventTarget(*carbonEvent, NULL); + switch (GetEventKind(*carbonEvent)) { + case kEventWindowActivated: + LOG((CLOG_DEBUG1 "window activated")); + break; + + case kEventWindowDeactivated: + LOG((CLOG_DEBUG1 "window deactivated")); + break; + + case kEventWindowFocusAcquired: + LOG((CLOG_DEBUG1 "focus acquired")); + break; + + case kEventWindowFocusRelinquish: + LOG((CLOG_DEBUG1 "focus released")); + break; + } + break; + + default: + SendEventToEventTarget(*carbonEvent, GetEventDispatcherTarget()); + break; + } +} + +bool OSXScreen::onMouseMove(CGFloat mx, CGFloat my) +{ + LOG((CLOG_DEBUG2 "mouse move %+f,%+f", mx, my)); + + CGFloat x = mx - m_xCursor; + CGFloat y = my - m_yCursor; + + if ((x == 0 && y == 0) || (mx == m_xCenter && mx == m_yCenter)) { + return true; + } + + // save position to compute delta of next motion + m_xCursor = (SInt32)mx; + m_yCursor = (SInt32)my; + + if (m_isOnScreen) { + // motion on primary screen + sendEvent(m_events->forIPrimaryScreen().motionOnPrimary(), MotionInfo::alloc(m_xCursor, m_yCursor)); + if (m_buttonState.test(0)) { + m_draggingStarted = true; + } + } else { + // motion on secondary screen. warp mouse back to + // center. + warpCursor(m_xCenter, m_yCenter); + + // examine the motion. if it's about the distance + // from the center of the screen to an edge then + // it's probably a bogus motion that we want to + // ignore (see warpCursorNoFlush() for a further + // description). + static SInt32 bogusZoneSize = 10; + if (-x + bogusZoneSize > m_xCenter - m_x || x + bogusZoneSize > m_x + m_w - m_xCenter || + -y + bogusZoneSize > m_yCenter - m_y || y + bogusZoneSize > m_y + m_h - m_yCenter) { + LOG((CLOG_DEBUG "dropped bogus motion %+d,%+d", x, y)); + } else { + // send motion + // Accumulate together the move into the running total + static CGFloat m_xFractionalMove = 0; + static CGFloat m_yFractionalMove = 0; + + m_xFractionalMove += x; + m_yFractionalMove += y; + + // Return the integer part + SInt32 intX = (SInt32)m_xFractionalMove; + SInt32 intY = (SInt32)m_yFractionalMove; + + // And keep only the fractional part + m_xFractionalMove -= intX; + m_yFractionalMove -= intY; + sendEvent(m_events->forIPrimaryScreen().motionOnSecondary(), MotionInfo::alloc(intX, intY)); + } + } + + return true; +} + +bool OSXScreen::onMouseButton(bool pressed, UInt16 macButton) +{ + // Buttons 2 and 3 are inverted on the mac + ButtonID button = mapMacButtonToDeskflow(macButton); + + if (pressed) { + LOG((CLOG_DEBUG1 "event: button press button=%d", button)); + if (button != kButtonNone) { + KeyModifierMask mask = m_keyState->getActiveModifiers(); + sendEvent(m_events->forIPrimaryScreen().buttonDown(), ButtonInfo::alloc(button, mask)); + } + } else { + LOG((CLOG_DEBUG1 "event: button release button=%d", button)); + if (button != kButtonNone) { + KeyModifierMask mask = m_keyState->getActiveModifiers(); + sendEvent(m_events->forIPrimaryScreen().buttonUp(), ButtonInfo::alloc(button, mask)); + } + } + + // handle drags with any button other than button 1 or 2 + if (macButton > 2) { + if (pressed) { + // one more button + if (m_dragNumButtonsDown++ == 0) { + enableDragTimer(true); + } + } else { + // one less button + if (--m_dragNumButtonsDown == 0) { + enableDragTimer(false); + } + } + } + + if (macButton == kButtonLeft) { + EMouseButtonState state = pressed ? kMouseButtonDown : kMouseButtonUp; + m_buttonState.set(kButtonLeft - 1, state); + if (pressed) { + m_draggingFilename.clear(); + LOG((CLOG_DEBUG2 "dragging file directory is cleared")); + } else { + if (m_fakeDraggingStarted) { + auto method = new TMethodJob(this, &OSXScreen::getDropTargetThread); + m_getDropTargetThread.reset(new Thread(method)); + } + + m_draggingStarted = false; + } + } + + return true; +} + +bool OSXScreen::onMouseWheel(SInt32 xDelta, SInt32 yDelta) const +{ + LOG((CLOG_DEBUG1 "event: button wheel delta=%+d,%+d", xDelta, yDelta)); + sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(xDelta, yDelta)); + return true; +} + +void OSXScreen::handleClipboardCheck(const Event &, void *) +{ + checkClipboards(); +} + +void OSXScreen::displayReconfigurationCallback( + CGDirectDisplayID displayID, CGDisplayChangeSummaryFlags flags, void *inUserData +) +{ + OSXScreen *screen = (OSXScreen *)inUserData; + + // Closing or opening the lid when an external monitor is + // connected causes an kCGDisplayBeginConfigurationFlag event + CGDisplayChangeSummaryFlags mask = kCGDisplayBeginConfigurationFlag | kCGDisplayMovedFlag | kCGDisplaySetModeFlag | + kCGDisplayAddFlag | kCGDisplayRemoveFlag | kCGDisplayEnabledFlag | + kCGDisplayDisabledFlag | kCGDisplayMirrorFlag | kCGDisplayUnMirrorFlag | + kCGDisplayDesktopShapeChangedFlag; + + LOG((CLOG_DEBUG1 "event: display was reconfigured: %x %x %x", flags, mask, flags & mask)); + + if (flags & mask) { /* Something actually did change */ + LOG((CLOG_DEBUG1 "event: screen changed shape; refreshing dimensions")); + if (!screen->updateScreenShape(displayID, flags)) { + LOG((CLOG_ERR "failed to update screen shape during display reconfiguration")); + } + } +} + +bool OSXScreen::onKey(CGEventRef event) +{ + CGEventType eventKind = CGEventGetType(event); + + // get the key and active modifiers + UInt32 virtualKey = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode); + CGEventFlags macMask = CGEventGetFlags(event); + LOG((CLOG_DEBUG1 "event: Key event kind: %d, keycode=%d", eventKind, virtualKey)); + + // Special handling to track state of modifiers + if (eventKind == kCGEventFlagsChanged) { + // get old and new modifier state + KeyModifierMask oldMask = getActiveModifiers(); + KeyModifierMask newMask = m_keyState->mapModifiersFromOSX(macMask); + m_keyState->handleModifierKeys(getEventTarget(), oldMask, newMask); + + // if the current set of modifiers exactly matches a modifiers-only + // hot key then generate a hot key down event. + if (m_activeModifierHotKey == 0) { + if (m_modifierHotKeys.count(newMask) > 0) { + m_activeModifierHotKey = m_modifierHotKeys[newMask]; + m_activeModifierHotKeyMask = newMask; + m_events->addEvent(Event( + m_events->forIPrimaryScreen().hotKeyDown(), getEventTarget(), HotKeyInfo::alloc(m_activeModifierHotKey) + )); + } + } + + // if a modifiers-only hot key is active and should no longer be + // then generate a hot key up event. + else if (m_activeModifierHotKey != 0) { + KeyModifierMask mask = (newMask & m_activeModifierHotKeyMask); + if (mask != m_activeModifierHotKeyMask) { + m_events->addEvent( + Event(m_events->forIPrimaryScreen().hotKeyUp(), getEventTarget(), HotKeyInfo::alloc(m_activeModifierHotKey)) + ); + m_activeModifierHotKey = 0; + m_activeModifierHotKeyMask = 0; + } + } + + return true; + } + + // check for hot key + HotKeyToIDMap::const_iterator i = + m_hotKeyToIDMap.find(HotKeyItem(virtualKey, m_keyState->mapModifiersToCarbon(macMask) & 0xff00u)); + if (i != m_hotKeyToIDMap.end()) { + UInt32 id = i->second; + + // determine event type + Event::Type type; + // UInt32 eventKind = GetEventKind(event); + if (eventKind == kCGEventKeyDown) { + type = m_events->forIPrimaryScreen().hotKeyDown(); + } else if (eventKind == kCGEventKeyUp) { + type = m_events->forIPrimaryScreen().hotKeyUp(); + } else { + return false; + } + + m_events->addEvent(Event(type, getEventTarget(), HotKeyInfo::alloc(id))); + + return true; + } + + // decode event type + bool down = (eventKind == kCGEventKeyDown); + bool up = (eventKind == kCGEventKeyUp); + bool isRepeat = (CGEventGetIntegerValueField(event, kCGKeyboardEventAutorepeat) == 1); + + // map event to keys + KeyModifierMask mask; + OSXKeyState::KeyIDs keys; + KeyButton button = m_keyState->mapKeyFromEvent(keys, &mask, event); + if (button == 0) { + return false; + } + + // check for AltGr in mask. if set we send neither the AltGr nor + // the super modifiers to clients then remove AltGr before passing + // the modifiers to onKey. + KeyModifierMask sendMask = (mask & ~KeyModifierAltGr); + if ((mask & KeyModifierAltGr) != 0) { + sendMask &= ~KeyModifierSuper; + } + mask &= ~KeyModifierAltGr; + + // update button state + if (down) { + m_keyState->onKey(button, true, mask); + } else if (up) { + if (!m_keyState->isKeyDown(button)) { + // up event for a dead key. throw it away. + return false; + } + m_keyState->onKey(button, false, mask); + } + + // send key events + for (OSXKeyState::KeyIDs::const_iterator i = keys.begin(); i != keys.end(); ++i) { + m_keyState->sendKeyEvent(getEventTarget(), down, isRepeat, *i, sendMask, 1, button); + } + + return true; +} + +void OSXScreen::onMediaKey(CGEventRef event) +{ + KeyID keyID; + bool down; + bool isRepeat; + + if (!getMediaKeyEventInfo(event, &keyID, &down, &isRepeat)) { + LOG((CLOG_ERR "Failed to decode media key event")); + return; + } + + LOG( + (CLOG_DEBUG2 "Media key event: keyID=0x%02x, %s, repeat=%s", keyID, (down ? "down" : "up"), + (isRepeat ? "yes" : "no")) + ); + + KeyButton button = 0; + KeyModifierMask mask = m_keyState->getActiveModifiers(); + m_keyState->sendKeyEvent(getEventTarget(), down, isRepeat, keyID, mask, 1, button); +} + +bool OSXScreen::onHotKey(EventRef event) const +{ + // get the hotkey id + EventHotKeyID hkid; + GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(EventHotKeyID), NULL, &hkid); + UInt32 id = hkid.id; + + // determine event type + Event::Type type; + UInt32 eventKind = GetEventKind(event); + if (eventKind == kEventHotKeyPressed) { + type = m_events->forIPrimaryScreen().hotKeyDown(); + } else if (eventKind == kEventHotKeyReleased) { + type = m_events->forIPrimaryScreen().hotKeyUp(); + } else { + return false; + } + + m_events->addEvent(Event(type, getEventTarget(), HotKeyInfo::alloc(id))); + + return true; +} + +ButtonID OSXScreen::mapDeskflowButtonToMac(UInt16 button) const +{ + switch (button) { + case 1: + return kButtonLeft; + case 2: + return kMacButtonMiddle; + case 3: + return kMacButtonRight; + } + + return static_cast(button); +} + +ButtonID OSXScreen::mapMacButtonToDeskflow(UInt16 macButton) const +{ + switch (macButton) { + case 1: + return kButtonLeft; + + case 2: + return kButtonRight; + + case 3: + return kButtonMiddle; + } + + return static_cast(macButton); +} + +SInt32 OSXScreen::mapScrollWheelToDeskflow(SInt32 x) const +{ + // return accelerated scrolling + double d = (1.0 + getScrollSpeed()) * x; + return static_cast(120.0 * d); +} + +SInt32 OSXScreen::mapScrollWheelFromDeskflow(SInt32 x) const +{ + // use server's acceleration with a little boost since other platforms + // take one wheel step as a larger step than the mac does. + auto result = static_cast(3.0 * x / 120.0); + return mapClientScrollDirection(result); +} + +double OSXScreen::getScrollSpeed() const +{ + double scaling = 0.0; + + CFPropertyListRef pref = ::CFPreferencesCopyValue( + CFSTR("com.apple.scrollwheel.scaling"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, + kCFPreferencesAnyHost + ); + if (pref != NULL) { + CFTypeID id = CFGetTypeID(pref); + if (id == CFNumberGetTypeID()) { + CFNumberRef value = static_cast(pref); + if (CFNumberGetValue(value, kCFNumberDoubleType, &scaling)) { + if (scaling < 0.0) { + scaling = 0.0; + } + } + } + CFRelease(pref); + } + + return scaling; +} + +void OSXScreen::enableDragTimer(bool enable) +{ + if (enable && m_dragTimer == NULL) { + m_dragTimer = m_events->newTimer(0.01, NULL); + m_events->adoptHandler(Event::kTimer, m_dragTimer, new TMethodEventJob(this, &OSXScreen::handleDrag)); + CGEventRef event = CGEventCreate(NULL); + CGPoint mouse = CGEventGetLocation(event); + m_dragLastPoint.h = (short)mouse.x; + m_dragLastPoint.v = (short)mouse.y; + CFRelease(event); + } else if (!enable && m_dragTimer != NULL) { + m_events->removeHandler(Event::kTimer, m_dragTimer); + m_events->deleteTimer(m_dragTimer); + m_dragTimer = NULL; + } +} + +void OSXScreen::handleDrag(const Event &, void *) +{ + CGEventRef event = CGEventCreate(NULL); + CGPoint p = CGEventGetLocation(event); + CFRelease(event); + + if ((short)p.x != m_dragLastPoint.h || (short)p.y != m_dragLastPoint.v) { + m_dragLastPoint.h = (short)p.x; + m_dragLastPoint.v = (short)p.y; + onMouseMove((SInt32)p.x, (SInt32)p.y); + } +} + +void OSXScreen::updateButtons() +{ + UInt32 buttons = GetCurrentButtonState(); + + m_buttonState.overwrite(buttons); +} + +IKeyState *OSXScreen::getKeyState() const +{ + return m_keyState; } bool OSXScreen::updateScreenShape(const CGDirectDisplayID, const CGDisplayChangeSummaryFlags flags) { - return updateScreenShape(); + return updateScreenShape(); } -bool -OSXScreen::updateScreenShape() +bool OSXScreen::updateScreenShape() { - // get info for each display - CGDisplayCount displayCount = 0; + // get info for each display + CGDisplayCount displayCount = 0; - if (CGGetActiveDisplayList(0, NULL, &displayCount) != CGDisplayNoErr) { - return false; - } - - if (displayCount == 0) { - return false; - } + if (CGGetActiveDisplayList(0, NULL, &displayCount) != CGDisplayNoErr) { + return false; + } - CGDirectDisplayID* displays = new CGDirectDisplayID[displayCount]; - if (displays == NULL) { - return false; - } + if (displayCount == 0) { + return false; + } - if (CGGetActiveDisplayList(displayCount, - displays, &displayCount) != CGDisplayNoErr) { - delete[] displays; - return false; - } + CGDirectDisplayID *displays = new CGDirectDisplayID[displayCount]; + if (displays == NULL) { + return false; + } - // get smallest rect enclosing all display rects - CGRect totalBounds = CGRectZero; - for (CGDisplayCount i = 0; i < displayCount; ++i) { - CGRect bounds = CGDisplayBounds(displays[i]); - totalBounds = CGRectUnion(totalBounds, bounds); - } + if (CGGetActiveDisplayList(displayCount, displays, &displayCount) != CGDisplayNoErr) { + delete[] displays; + return false; + } - // get shape of default screen - m_x = (SInt32)totalBounds.origin.x; - m_y = (SInt32)totalBounds.origin.y; - m_w = (SInt32)totalBounds.size.width; - m_h = (SInt32)totalBounds.size.height; + // get smallest rect enclosing all display rects + CGRect totalBounds = CGRectZero; + for (CGDisplayCount i = 0; i < displayCount; ++i) { + CGRect bounds = CGDisplayBounds(displays[i]); + totalBounds = CGRectUnion(totalBounds, bounds); + } - // get center of default screen + // get shape of default screen + m_x = (SInt32)totalBounds.origin.x; + m_y = (SInt32)totalBounds.origin.y; + m_w = (SInt32)totalBounds.size.width; + m_h = (SInt32)totalBounds.size.height; + + // get center of default screen CGDirectDisplayID main = CGMainDisplayID(); const CGRect rect = CGDisplayBounds(main); m_xCenter = (rect.origin.x + rect.size.width) / 2; m_yCenter = (rect.origin.y + rect.size.height) / 2; - delete[] displays; - // We want to notify the peer screen whether we are primary screen or not - sendEvent(m_events->forIScreen().shapeChanged()); + delete[] displays; + // We want to notify the peer screen whether we are primary screen or not + sendEvent(m_events->forIScreen().shapeChanged()); - LOG((CLOG_DEBUG "screen shape: center=%d,%d size=%dx%d on %u %s", - m_x, m_y, m_w, m_h, displayCount, - (displayCount == 1) ? "display" : "displays")); + LOG( + (CLOG_DEBUG "screen shape: center=%d,%d size=%dx%d on %u %s", m_x, m_y, m_w, m_h, displayCount, + (displayCount == 1) ? "display" : "displays") + ); - return true; + return true; } -#pragma mark - +#pragma mark - // // FAST USER SWITCH NOTIFICATION SUPPORT // // OSXScreen::userSwitchCallback(void*) -// +// // gets called if a fast user switch occurs // -pascal OSStatus -OSXScreen::userSwitchCallback(EventHandlerCallRef nextHandler, - EventRef theEvent, - void* inUserData) +pascal OSStatus OSXScreen::userSwitchCallback(EventHandlerCallRef nextHandler, EventRef theEvent, void *inUserData) { - OSXScreen* screen = (OSXScreen*)inUserData; - UInt32 kind = GetEventKind(theEvent); - IEventQueue* events = screen->getEvents(); + OSXScreen *screen = (OSXScreen *)inUserData; + UInt32 kind = GetEventKind(theEvent); + IEventQueue *events = screen->getEvents(); - if (kind == kEventSystemUserSessionDeactivated) { - LOG((CLOG_DEBUG "user session deactivated")); - events->addEvent(Event(events->forIScreen().suspend(), - screen->getEventTarget())); - } - else if (kind == kEventSystemUserSessionActivated) { - LOG((CLOG_DEBUG "user session activated")); - events->addEvent(Event(events->forIScreen().resume(), - screen->getEventTarget())); - } - return (CallNextEventHandler(nextHandler, theEvent)); + if (kind == kEventSystemUserSessionDeactivated) { + LOG((CLOG_DEBUG "user session deactivated")); + events->addEvent(Event(events->forIScreen().suspend(), screen->getEventTarget())); + } else if (kind == kEventSystemUserSessionActivated) { + LOG((CLOG_DEBUG "user session activated")); + events->addEvent(Event(events->forIScreen().resume(), screen->getEventTarget())); + } + return (CallNextEventHandler(nextHandler, theEvent)); } -#pragma mark - +#pragma mark - // // SLEEP/WAKEUP NOTIFICATION SUPPORT // // OSXScreen::watchSystemPowerThread(void*) -// +// // main of thread monitoring system power (sleep/wakup) using a CFRunLoop // -void -OSXScreen::watchSystemPowerThread(void*) +void OSXScreen::watchSystemPowerThread(void *) { - io_object_t notifier; - IONotificationPortRef notificationPortRef; - CFRunLoopSourceRef runloopSourceRef = 0; + io_object_t notifier; + IONotificationPortRef notificationPortRef; + CFRunLoopSourceRef runloopSourceRef = 0; - m_pmRunloop = CFRunLoopGetCurrent(); - // install system power change callback - m_pmRootPort = IORegisterForSystemPower(this, ¬ificationPortRef, - powerChangeCallback, ¬ifier); - if (m_pmRootPort == 0) { - LOG((CLOG_WARN "IORegisterForSystemPower failed")); - } - else { - runloopSourceRef = - IONotificationPortGetRunLoopSource(notificationPortRef); - CFRunLoopAddSource(m_pmRunloop, runloopSourceRef, - kCFRunLoopCommonModes); - } - - // thread is ready - { - Lock lock(m_pmMutex); - *m_pmThreadReady = true; - m_pmThreadReady->signal(); - } + m_pmRunloop = CFRunLoopGetCurrent(); + // install system power change callback + m_pmRootPort = IORegisterForSystemPower(this, ¬ificationPortRef, powerChangeCallback, ¬ifier); + if (m_pmRootPort == 0) { + LOG((CLOG_WARN "IORegisterForSystemPower failed")); + } else { + runloopSourceRef = IONotificationPortGetRunLoopSource(notificationPortRef); + CFRunLoopAddSource(m_pmRunloop, runloopSourceRef, kCFRunLoopCommonModes); + } - // if we were unable to initialize then exit. we must do this after - // setting m_pmThreadReady to true otherwise the parent thread will - // block waiting for it. - if (m_pmRootPort == 0) { - LOG((CLOG_WARN "failed to init watchSystemPowerThread")); - return; - } + // thread is ready + { + Lock lock(m_pmMutex); + *m_pmThreadReady = true; + m_pmThreadReady->signal(); + } + + // if we were unable to initialize then exit. we must do this after + // setting m_pmThreadReady to true otherwise the parent thread will + // block waiting for it. + if (m_pmRootPort == 0) { + LOG((CLOG_WARN "failed to init watchSystemPowerThread")); + return; + } + + LOG((CLOG_DEBUG "started watchSystemPowerThread")); + + LOG((CLOG_DEBUG "waiting for event loop")); + m_events->waitForReady(); - LOG((CLOG_DEBUG "started watchSystemPowerThread")); - - LOG((CLOG_DEBUG "waiting for event loop")); - m_events->waitForReady(); - #if defined(MAC_OS_X_VERSION_10_7) - { - Lock lockCarbon(m_carbonLoopMutex); - if (*m_carbonLoopReady == false) { - - // we signalling carbon loop ready before starting - // unless we know how to do it within the loop - LOG((CLOG_DEBUG "signalling carbon loop ready")); + { + Lock lockCarbon(m_carbonLoopMutex); + if (*m_carbonLoopReady == false) { - *m_carbonLoopReady = true; - m_carbonLoopReady->signal(); - } - } + // we signalling carbon loop ready before starting + // unless we know how to do it within the loop + LOG((CLOG_DEBUG "signalling carbon loop ready")); + + *m_carbonLoopReady = true; + m_carbonLoopReady->signal(); + } + } #endif - - // start the run loop - LOG((CLOG_DEBUG "starting carbon loop")); - CFRunLoopRun(); - LOG((CLOG_DEBUG "carbon loop has stopped")); - - // cleanup - if (notificationPortRef) { - CFRunLoopRemoveSource(m_pmRunloop, - runloopSourceRef, kCFRunLoopDefaultMode); - CFRunLoopSourceInvalidate(runloopSourceRef); - CFRelease(runloopSourceRef); - } - Lock lock(m_pmMutex); - IODeregisterForSystemPower(¬ifier); - m_pmRootPort = 0; - LOG((CLOG_DEBUG "stopped watchSystemPowerThread")); + // start the run loop + LOG((CLOG_DEBUG "starting carbon loop")); + CFRunLoopRun(); + LOG((CLOG_DEBUG "carbon loop has stopped")); + + // cleanup + if (notificationPortRef) { + CFRunLoopRemoveSource(m_pmRunloop, runloopSourceRef, kCFRunLoopDefaultMode); + CFRunLoopSourceInvalidate(runloopSourceRef); + CFRelease(runloopSourceRef); + } + + Lock lock(m_pmMutex); + IODeregisterForSystemPower(¬ifier); + m_pmRootPort = 0; + LOG((CLOG_DEBUG "stopped watchSystemPowerThread")); } -void -OSXScreen::powerChangeCallback(void* refcon, io_service_t service, - natural_t messageType, void* messageArg) +void OSXScreen::powerChangeCallback(void *refcon, io_service_t service, natural_t messageType, void *messageArg) { - ((OSXScreen*)refcon)->handlePowerChangeRequest(messageType, messageArg); + ((OSXScreen *)refcon)->handlePowerChangeRequest(messageType, messageArg); } -void -OSXScreen::handlePowerChangeRequest(natural_t messageType, void* messageArg) +void OSXScreen::handlePowerChangeRequest(natural_t messageType, void *messageArg) { - // we've received a power change notification - switch (messageType) { - case kIOMessageSystemWillSleep: - // OSXScreen has to handle this in the main thread so we have to - // queue a confirm sleep event here. we actually don't allow the - // system to sleep until the event is handled. - m_events->addEvent(Event(m_events->forOSXScreen().confirmSleep(), - getEventTarget(), messageArg, - Event::kDontFreeData)); - return; - - case kIOMessageSystemHasPoweredOn: - LOG((CLOG_DEBUG "system wakeup")); - m_events->addEvent(Event(m_events->forIScreen().resume(), - getEventTarget())); - break; + // we've received a power change notification + switch (messageType) { + case kIOMessageSystemWillSleep: + // OSXScreen has to handle this in the main thread so we have to + // queue a confirm sleep event here. we actually don't allow the + // system to sleep until the event is handled. + m_events->addEvent( + Event(m_events->forOSXScreen().confirmSleep(), getEventTarget(), messageArg, Event::kDontFreeData) + ); + return; - default: - break; - } + case kIOMessageSystemHasPoweredOn: + LOG((CLOG_DEBUG "system wakeup")); + m_events->addEvent(Event(m_events->forIScreen().resume(), getEventTarget())); + break; - Lock lock(m_pmMutex); - if (m_pmRootPort != 0) { - IOAllowPowerChange(m_pmRootPort, (long)messageArg); - } + default: + break; + } + + Lock lock(m_pmMutex); + if (m_pmRootPort != 0) { + IOAllowPowerChange(m_pmRootPort, (long)messageArg); + } } -void -OSXScreen::handleConfirmSleep(const Event& event, void*) +void OSXScreen::handleConfirmSleep(const Event &event, void *) { - long messageArg = (long)event.getData(); - if (messageArg != 0) { - Lock lock(m_pmMutex); - if (m_pmRootPort != 0) { - // deliver suspend event immediately. - m_events->addEvent(Event(m_events->forIScreen().suspend(), - getEventTarget(), NULL, - Event::kDeliverImmediately)); - - LOG((CLOG_DEBUG "system will sleep")); - IOAllowPowerChange(m_pmRootPort, messageArg); - } - } + long messageArg = (long)event.getData(); + if (messageArg != 0) { + Lock lock(m_pmMutex); + if (m_pmRootPort != 0) { + // deliver suspend event immediately. + m_events->addEvent(Event(m_events->forIScreen().suspend(), getEventTarget(), NULL, Event::kDeliverImmediately)); + + LOG((CLOG_DEBUG "system will sleep")); + IOAllowPowerChange(m_pmRootPort, messageArg); + } + } } -#pragma mark - +#pragma mark - // // GLOBAL HOTKEY OPERATING MODE SUPPORT (10.3) @@ -1798,7 +1655,7 @@ OSXScreen::handleConfirmSleep(const Event& event, void*) // #if 0 -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif @@ -1820,17 +1677,15 @@ static _CGSDefaultConnection_t s__CGSDefaultConnection; static CGSGetGlobalHotKeyOperatingMode_t s_CGSGetGlobalHotKeyOperatingMode; static CGSSetGlobalHotKeyOperatingMode_t s_CGSSetGlobalHotKeyOperatingMode; -#ifdef __cplusplus +#ifdef __cplusplus } #endif -#define LOOKUP(name_) \ - s_ ## name_ = NULL; \ - if (NSIsSymbolNameDefinedWithHint("_" #name_, "CoreGraphics")) { \ - s_ ## name_ = (name_ ## _t)NSAddressOfSymbol( \ - NSLookupAndBindSymbolWithHint( \ - "_" #name_, "CoreGraphics")); \ - } +#define LOOKUP(name_) \ + s_##name_ = NULL; \ + if (NSIsSymbolNameDefinedWithHint("_" #name_, "CoreGraphics")) { \ + s_##name_ = (name_##_t)NSAddressOfSymbol(NSLookupAndBindSymbolWithHint("_" #name_, "CoreGraphics")); \ + } bool OSXScreen::isGlobalHotKeyOperatingModeAvailable() @@ -1885,375 +1740,353 @@ OSXScreen::getGlobalHotKeysEnabled() // OSXScreen::HotKeyItem // -OSXScreen::HotKeyItem::HotKeyItem(UInt32 keycode, UInt32 mask) : - m_ref(NULL), - m_keycode(keycode), - m_mask(mask) +OSXScreen::HotKeyItem::HotKeyItem(UInt32 keycode, UInt32 mask) : m_ref(NULL), m_keycode(keycode), m_mask(mask) { - // do nothing + // do nothing } -OSXScreen::HotKeyItem::HotKeyItem(EventHotKeyRef ref, - UInt32 keycode, UInt32 mask) : - m_ref(ref), - m_keycode(keycode), - m_mask(mask) +OSXScreen::HotKeyItem::HotKeyItem(EventHotKeyRef ref, UInt32 keycode, UInt32 mask) + : m_ref(ref), + m_keycode(keycode), + m_mask(mask) { - // do nothing + // do nothing } -EventHotKeyRef -OSXScreen::HotKeyItem::getRef() const +EventHotKeyRef OSXScreen::HotKeyItem::getRef() const { - return m_ref; + return m_ref; } -bool -OSXScreen::HotKeyItem::operator<(const HotKeyItem& x) const +bool OSXScreen::HotKeyItem::operator<(const HotKeyItem &x) const { - return (m_keycode < x.m_keycode || - (m_keycode == x.m_keycode && m_mask < x.m_mask)); + return (m_keycode < x.m_keycode || (m_keycode == x.m_keycode && m_mask < x.m_mask)); } // Quartz event tap support for the secondary display. This makes sure that we // will show the cursor if a local event comes in while deskflow has the cursor // off the screen. CGEventRef -OSXScreen::handleCGInputEventSecondary( - CGEventTapProxy proxy, - CGEventType type, - CGEventRef event, - void* refcon) +OSXScreen::handleCGInputEventSecondary(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { - // this fix is really screwing with the correct show/hide behavior. it - // should be tested better before reintroducing. - return event; + // this fix is really screwing with the correct show/hide behavior. it + // should be tested better before reintroducing. + return event; - OSXScreen* screen = (OSXScreen*)refcon; - if (screen->m_cursorHidden && type == kCGEventMouseMoved) { + OSXScreen *screen = (OSXScreen *)refcon; + if (screen->m_cursorHidden && type == kCGEventMouseMoved) { - CGPoint pos = CGEventGetLocation(event); - if (pos.x != screen->m_xCenter || pos.y != screen->m_yCenter) { + CGPoint pos = CGEventGetLocation(event); + if (pos.x != screen->m_xCenter || pos.y != screen->m_yCenter) { - LOG((CLOG_DEBUG "show cursor on secondary, type=%d pos=%d,%d", - type, pos.x, pos.y)); - screen->showCursor(); - } - } - return event; + LOG((CLOG_DEBUG "show cursor on secondary, type=%d pos=%d,%d", type, pos.x, pos.y)); + screen->showCursor(); + } + } + return event; } // Quartz event tap support -CGEventRef -OSXScreen::handleCGInputEvent(CGEventTapProxy proxy, - CGEventType type, - CGEventRef event, - void* refcon) +CGEventRef OSXScreen::handleCGInputEvent(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { - OSXScreen* screen = (OSXScreen*)refcon; - CGPoint pos; + OSXScreen *screen = (OSXScreen *)refcon; + CGPoint pos; - switch(type) { - case kCGEventLeftMouseDown: - case kCGEventRightMouseDown: - case kCGEventOtherMouseDown: - screen->onMouseButton(true, CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber) + 1); - break; - case kCGEventLeftMouseUp: - case kCGEventRightMouseUp: - case kCGEventOtherMouseUp: - screen->onMouseButton(false, CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber) + 1); - break; - case kCGEventLeftMouseDragged: - case kCGEventRightMouseDragged: - case kCGEventOtherMouseDragged: - case kCGEventMouseMoved: - pos = CGEventGetLocation(event); - screen->onMouseMove(pos.x, pos.y); - - // The system ignores our cursor-centering calls if - // we don't return the event. This should be harmless, - // but might register as slight movement to other apps - // on the system. It hasn't been a problem before, though. - return event; - break; - case kCGEventScrollWheel: - screen->onMouseWheel(screen->mapScrollWheelToDeskflow( - CGEventGetIntegerValueField(event, kCGScrollWheelEventDeltaAxis2)), - screen->mapScrollWheelToDeskflow( - CGEventGetIntegerValueField(event, kCGScrollWheelEventDeltaAxis1))); - break; - case kCGEventKeyDown: - case kCGEventKeyUp: - case kCGEventFlagsChanged: - screen->onKey(event); - break; - case kCGEventTapDisabledByTimeout: - // Re-enable our event-tap - CGEventTapEnable(screen->m_eventTapPort, true); - LOG((CLOG_INFO "quartz event tap was disabled by timeout, re-enabling")); - break; - case kCGEventTapDisabledByUserInput: - LOG((CLOG_ERR "quartz event tap was disabled by user input")); - break; - case NX_NULLEVENT: - break; - default: - if (type == NX_SYSDEFINED) { - if (isMediaKeyEvent (event)) { - LOG((CLOG_DEBUG2 "detected media key event")); - screen->onMediaKey (event); - } else { - LOG((CLOG_DEBUG2 "ignoring unknown system defined event")); - return event; - } - break; - } - - LOG((CLOG_DEBUG3 "unknown quartz event type: 0x%02x", type)); - } - - if (screen->m_isOnScreen) { - return event; - } else { - return NULL; - } -} + switch (type) { + case kCGEventLeftMouseDown: + case kCGEventRightMouseDown: + case kCGEventOtherMouseDown: + screen->onMouseButton(true, CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber) + 1); + break; + case kCGEventLeftMouseUp: + case kCGEventRightMouseUp: + case kCGEventOtherMouseUp: + screen->onMouseButton(false, CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber) + 1); + break; + case kCGEventLeftMouseDragged: + case kCGEventRightMouseDragged: + case kCGEventOtherMouseDragged: + case kCGEventMouseMoved: + pos = CGEventGetLocation(event); + screen->onMouseMove(pos.x, pos.y); -void -OSXScreen::MouseButtonState::set(UInt32 button, EMouseButtonState state) -{ - bool newState = (state == kMouseButtonDown); - m_buttons.set(button, newState); -} - -bool -OSXScreen::MouseButtonState::any() -{ - return m_buttons.any(); -} - -void -OSXScreen::MouseButtonState::reset() -{ - m_buttons.reset(); -} - -void -OSXScreen::MouseButtonState::overwrite(UInt32 buttons) -{ - m_buttons = std::bitset(buttons); -} - -bool -OSXScreen::MouseButtonState::test(UInt32 button) const -{ - return m_buttons.test(button); -} - -SInt8 -OSXScreen::MouseButtonState::getFirstButtonDown() const -{ - if (m_buttons.any()) { - for (unsigned short button = 0; button < m_buttons.size(); button++) { - if (m_buttons.test(button)) { - return button; - } - } - } - return -1; -} - -char* -OSXScreen::CFStringRefToUTF8String(CFStringRef aString) -{ - if (aString == NULL) { - return NULL; - } - - CFIndex length = CFStringGetLength(aString); - CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); - char* buffer = (char*)malloc(maxSize); - - if (!CFStringGetCString(aString, buffer, maxSize, kCFStringEncodingUTF8)) { - free(buffer); - buffer = NULL; - } - - return buffer; -} - -void -OSXScreen::fakeDraggingFiles(DragFileList fileList) -{ - m_fakeDraggingStarted = true; - String fileExt; - if (fileList.size() == 1) { - fileExt = DragInformation::getDragFileExtension( - fileList.at(0).getFilename()); - } - -#if defined(MAC_OS_X_VERSION_10_7) - fakeDragging(fileExt.c_str(), m_xCursor, m_yCursor); -#else - LOG((CLOG_WARN "drag drop not supported")); -#endif -} - -String& -OSXScreen::getDraggingFilename() -{ - if (m_draggingStarted) { - m_draggingFilename.clear(); - - CFStringRef dragInfo = getDraggedFileURL(); - char* info = CFStringRefToUTF8String(dragInfo); - CFRelease(dragInfo); - - if (info != NULL) { - LOG((CLOG_DEBUG "drag info: %s", info)); - m_draggingFilename = info; - free(info); - } - - // fake a escape key down and up then left mouse button up - fakeKeyDown(kKeyEscape, 8192, 1, AppUtil::instance().getCurrentLanguageCode()); - fakeKeyUp(1); - fakeMouseButton(kButtonLeft, false); - } - return m_draggingFilename; -} - -void -OSXScreen::waitForCarbonLoop() const -{ -#if defined(MAC_OS_X_VERSION_10_7) - if (*m_carbonLoopReady) { - LOG((CLOG_DEBUG "carbon loop already ready")); - return; - } - - Lock lock(m_carbonLoopMutex); - - LOG((CLOG_DEBUG "waiting for carbon loop")); - - double timeout = ARCH->time() + kCarbonLoopWaitTimeout; - while (!m_carbonLoopReady->wait()) { - if (ARCH->time() > timeout) { - LOG((CLOG_DEBUG "carbon loop not ready, waiting again")); - timeout = ARCH->time() + kCarbonLoopWaitTimeout; - } - } - - LOG((CLOG_DEBUG "carbon loop ready")); -#endif - -} - -String -OSXScreen::getSecureInputApp() const -{ - if(IsSecureEventInputEnabled()) { - int secureInputProcessPID = getSecureInputEventPID(); - if(secureInputProcessPID == 0) return "unknown"; - return getProcessName(secureInputProcessPID); - } - return ""; -} - -int -getSecureInputEventPID() -{ - io_service_t service = MACH_PORT_NULL, service_root = MACH_PORT_NULL; - mach_port_t masterPort; - - kern_return_t kr = IOMasterPort( MACH_PORT_NULL, &masterPort ); - if(kr != KERN_SUCCESS) return 0; - - // IO registry refuses to tap into the root level directly - // as a workaround access the parent of the top user level - service = IORegistryEntryFromPath( masterPort, kIOServicePlane ":/" ); - IORegistryEntryGetParentEntry(service, kIOServicePlane, &service_root); - - std::unique_ptr::type, decltype(&CFRelease)> consoleUsers( - IORegistryEntrySearchCFProperty(service_root, kIOServicePlane, CFSTR("IOConsoleUsers"), NULL, kIORegistryIterateParents | kIORegistryIterateRecursively), - CFRelease + // The system ignores our cursor-centering calls if + // we don't return the event. This should be harmless, + // but might register as slight movement to other apps + // on the system. It hasn't been a problem before, though. + return event; + break; + case kCGEventScrollWheel: + screen->onMouseWheel( + screen->mapScrollWheelToDeskflow(CGEventGetIntegerValueField(event, kCGScrollWheelEventDeltaAxis2)), + screen->mapScrollWheelToDeskflow(CGEventGetIntegerValueField(event, kCGScrollWheelEventDeltaAxis1)) ); - if(!consoleUsers) return 0; + break; + case kCGEventKeyDown: + case kCGEventKeyUp: + case kCGEventFlagsChanged: + screen->onKey(event); + break; + case kCGEventTapDisabledByTimeout: + // Re-enable our event-tap + CGEventTapEnable(screen->m_eventTapPort, true); + LOG((CLOG_INFO "quartz event tap was disabled by timeout, re-enabling")); + break; + case kCGEventTapDisabledByUserInput: + LOG((CLOG_ERR "quartz event tap was disabled by user input")); + break; + case NX_NULLEVENT: + break; + default: + if (type == NX_SYSDEFINED) { + if (isMediaKeyEvent(event)) { + LOG((CLOG_DEBUG2 "detected media key event")); + screen->onMediaKey(event); + } else { + LOG((CLOG_DEBUG2 "ignoring unknown system defined event")); + return event; + } + break; + } - CFTypeID type = CFGetTypeID(consoleUsers.get()); - if(type != CFArrayGetTypeID()) return 0; + LOG((CLOG_DEBUG3 "unknown quartz event type: 0x%02x", type)); + } - CFTypeRef dict = CFArrayGetValueAtIndex((CFArrayRef)consoleUsers.get(), 0); - if(!dict) return 0; - - type = CFGetTypeID(dict); - if(type != CFDictionaryGetTypeID()) return 0; - - CFTypeRef secureInputPID = nullptr; - CFDictionaryGetValueIfPresent((CFDictionaryRef)dict, CFSTR("kCGSSessionSecureInputPID"), &secureInputPID); - - if(secureInputPID == nullptr) return 0; - - type = CFGetTypeID(secureInputPID); - if(type != CFNumberGetTypeID()) return 0; - - auto pidRef = (CFNumberRef)secureInputPID; - CFNumberType numberType = CFNumberGetType(pidRef); - if(numberType != kCFNumberSInt32Type) return 0; - - int pid; - CFNumberGetValue(pidRef, kCFNumberSInt32Type, &pid); - return pid; + if (screen->m_isOnScreen) { + return event; + } else { + return NULL; + } } -String -getProcessName(int pid) +void OSXScreen::MouseButtonState::set(UInt32 button, EMouseButtonState state) { - if(!pid) return ""; - char buf[128]; - proc_name(pid, buf, sizeof(buf)); - return buf; + bool newState = (state == kMouseButtonDown); + m_buttons.set(button, newState); +} + +bool OSXScreen::MouseButtonState::any() +{ + return m_buttons.any(); +} + +void OSXScreen::MouseButtonState::reset() +{ + m_buttons.reset(); +} + +void OSXScreen::MouseButtonState::overwrite(UInt32 buttons) +{ + m_buttons = std::bitset(buttons); +} + +bool OSXScreen::MouseButtonState::test(UInt32 button) const +{ + return m_buttons.test(button); +} + +SInt8 OSXScreen::MouseButtonState::getFirstButtonDown() const +{ + if (m_buttons.any()) { + for (unsigned short button = 0; button < m_buttons.size(); button++) { + if (m_buttons.test(button)) { + return button; + } + } + } + return -1; +} + +char *OSXScreen::CFStringRefToUTF8String(CFStringRef aString) +{ + if (aString == NULL) { + return NULL; + } + + CFIndex length = CFStringGetLength(aString); + CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); + char *buffer = (char *)malloc(maxSize); + + if (!CFStringGetCString(aString, buffer, maxSize, kCFStringEncodingUTF8)) { + free(buffer); + buffer = NULL; + } + + return buffer; +} + +void OSXScreen::fakeDraggingFiles(DragFileList fileList) +{ + m_fakeDraggingStarted = true; + String fileExt; + if (fileList.size() == 1) { + fileExt = DragInformation::getDragFileExtension(fileList.at(0).getFilename()); + } + +#if defined(MAC_OS_X_VERSION_10_7) + fakeDragging(fileExt.c_str(), m_xCursor, m_yCursor); +#else + LOG((CLOG_WARN "drag drop not supported")); +#endif +} + +String &OSXScreen::getDraggingFilename() +{ + if (m_draggingStarted) { + m_draggingFilename.clear(); + + CFStringRef dragInfo = getDraggedFileURL(); + char *info = CFStringRefToUTF8String(dragInfo); + CFRelease(dragInfo); + + if (info != NULL) { + LOG((CLOG_DEBUG "drag info: %s", info)); + m_draggingFilename = info; + free(info); + } + + // fake a escape key down and up then left mouse button up + fakeKeyDown(kKeyEscape, 8192, 1, AppUtil::instance().getCurrentLanguageCode()); + fakeKeyUp(1); + fakeMouseButton(kButtonLeft, false); + } + return m_draggingFilename; +} + +void OSXScreen::waitForCarbonLoop() const +{ +#if defined(MAC_OS_X_VERSION_10_7) + if (*m_carbonLoopReady) { + LOG((CLOG_DEBUG "carbon loop already ready")); + return; + } + + Lock lock(m_carbonLoopMutex); + + LOG((CLOG_DEBUG "waiting for carbon loop")); + + double timeout = ARCH->time() + kCarbonLoopWaitTimeout; + while (!m_carbonLoopReady->wait()) { + if (ARCH->time() > timeout) { + LOG((CLOG_DEBUG "carbon loop not ready, waiting again")); + timeout = ARCH->time() + kCarbonLoopWaitTimeout; + } + } + + LOG((CLOG_DEBUG "carbon loop ready")); +#endif +} + +String OSXScreen::getSecureInputApp() const +{ + if (IsSecureEventInputEnabled()) { + int secureInputProcessPID = getSecureInputEventPID(); + if (secureInputProcessPID == 0) + return "unknown"; + return getProcessName(secureInputProcessPID); + } + return ""; +} + +int getSecureInputEventPID() +{ + io_service_t service = MACH_PORT_NULL, service_root = MACH_PORT_NULL; + mach_port_t masterPort; + + kern_return_t kr = IOMasterPort(MACH_PORT_NULL, &masterPort); + if (kr != KERN_SUCCESS) + return 0; + + // IO registry refuses to tap into the root level directly + // as a workaround access the parent of the top user level + service = IORegistryEntryFromPath(masterPort, kIOServicePlane ":/"); + IORegistryEntryGetParentEntry(service, kIOServicePlane, &service_root); + + std::unique_ptr::type, decltype(&CFRelease)> consoleUsers( + IORegistryEntrySearchCFProperty( + service_root, kIOServicePlane, CFSTR("IOConsoleUsers"), NULL, + kIORegistryIterateParents | kIORegistryIterateRecursively + ), + CFRelease + ); + if (!consoleUsers) + return 0; + + CFTypeID type = CFGetTypeID(consoleUsers.get()); + if (type != CFArrayGetTypeID()) + return 0; + + CFTypeRef dict = CFArrayGetValueAtIndex((CFArrayRef)consoleUsers.get(), 0); + if (!dict) + return 0; + + type = CFGetTypeID(dict); + if (type != CFDictionaryGetTypeID()) + return 0; + + CFTypeRef secureInputPID = nullptr; + CFDictionaryGetValueIfPresent((CFDictionaryRef)dict, CFSTR("kCGSSessionSecureInputPID"), &secureInputPID); + + if (secureInputPID == nullptr) + return 0; + + type = CFGetTypeID(secureInputPID); + if (type != CFNumberGetTypeID()) + return 0; + + auto pidRef = (CFNumberRef)secureInputPID; + CFNumberType numberType = CFNumberGetType(pidRef); + if (numberType != kCFNumberSInt32Type) + return 0; + + int pid; + CFNumberGetValue(pidRef, kCFNumberSInt32Type, &pid); + return pid; +} + +String getProcessName(int pid) +{ + if (!pid) + return ""; + char buf[128]; + proc_name(pid, buf, sizeof(buf)); + return buf; } #pragma GCC diagnostic ignored "-Wdeprecated-declarations" -void -setZeroSuppressionInterval() +void setZeroSuppressionInterval() { - CGSetLocalEventsSuppressionInterval(0.0); + CGSetLocalEventsSuppressionInterval(0.0); } -void -avoidSupression() +void avoidSupression() { - // avoid suppression of local hardware events - // stkamp@users.sourceforge.net - CGSetLocalEventsFilterDuringSupressionState( - kCGEventFilterMaskPermitAllEvents, - kCGEventSupressionStateSupressionInterval); - CGSetLocalEventsFilterDuringSupressionState( - (kCGEventFilterMaskPermitLocalKeyboardEvents | - kCGEventFilterMaskPermitSystemDefinedEvents), - kCGEventSupressionStateRemoteMouseDrag); + // avoid suppression of local hardware events + // stkamp@users.sourceforge.net + CGSetLocalEventsFilterDuringSupressionState( + kCGEventFilterMaskPermitAllEvents, kCGEventSupressionStateSupressionInterval + ); + CGSetLocalEventsFilterDuringSupressionState( + (kCGEventFilterMaskPermitLocalKeyboardEvents | kCGEventFilterMaskPermitSystemDefinedEvents), + kCGEventSupressionStateRemoteMouseDrag + ); } -void -logCursorVisibility() +void logCursorVisibility() { - // CGCursorIsVisible is probably deprecated because its unreliable. - if (!CGCursorIsVisible()) { - LOG((CLOG_WARN "cursor may not be visible")); - } + // CGCursorIsVisible is probably deprecated because its unreliable. + if (!CGCursorIsVisible()) { + LOG((CLOG_WARN "cursor may not be visible")); + } } -void -avoidHesitatingCursor() +void avoidHesitatingCursor() { - // This used to be necessary to get smooth mouse motion on other screens, - // but now is just to avoid a hesitating cursor when transitioning to - // the primary (this) screen. - CGSetLocalEventsSuppressionInterval(0.0001); + // This used to be necessary to get smooth mouse motion on other screens, + // but now is just to avoid a hesitating cursor when transitioning to + // the primary (this) screen. + CGSetLocalEventsSuppressionInterval(0.0001); } #pragma GCC diagnostic error "-Wdeprecated-declarations" diff --git a/src/lib/platform/OSXScreenSaverUtil.m b/src/lib/platform/OSXScreenSaverUtil.m index b18652322..83dc16cac 100644 --- a/src/lib/platform/OSXScreenSaverUtil.m +++ b/src/lib/platform/OSXScreenSaverUtil.m @@ -1,11 +1,11 @@ /* * Deskflow -- mouse and keyboard sharing utility * Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea - * + * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE that should have accompanied this file. - * + * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -26,58 +26,49 @@ // teach them about it. // -void* -screenSaverUtilCreatePool() +void *screenSaverUtilCreatePool() { - return [[NSAutoreleasePool alloc] init]; + return [[NSAutoreleasePool alloc] init]; } -void -screenSaverUtilReleasePool(void* pool) +void screenSaverUtilReleasePool(void *pool) { - [(NSAutoreleasePool*)pool release]; + [(NSAutoreleasePool *)pool release]; } -void* -screenSaverUtilCreateController() +void *screenSaverUtilCreateController() { - return [[ScreenSaverController controller] retain]; + return [[ScreenSaverController controller] retain]; } -void -screenSaverUtilReleaseController(void* controller) +void screenSaverUtilReleaseController(void *controller) { - [(ScreenSaverController*)controller release]; + [(ScreenSaverController *)controller release]; } -void -screenSaverUtilEnable(void* controller) +void screenSaverUtilEnable(void *controller) { - [(ScreenSaverController*)controller setScreenSaverCanRun:YES]; + [(ScreenSaverController *)controller setScreenSaverCanRun:YES]; } -void -screenSaverUtilDisable(void* controller) +void screenSaverUtilDisable(void *controller) { - [(ScreenSaverController*)controller setScreenSaverCanRun:NO]; + [(ScreenSaverController *)controller setScreenSaverCanRun:NO]; } -void -screenSaverUtilActivate(void* controller) +void screenSaverUtilActivate(void *controller) { - [(ScreenSaverController*)controller setScreenSaverCanRun:YES]; - [(ScreenSaverController*)controller screenSaverStartNow]; + [(ScreenSaverController *)controller setScreenSaverCanRun:YES]; + [(ScreenSaverController *)controller screenSaverStartNow]; } -void -screenSaverUtilDeactivate(void* controller, int isEnabled) +void screenSaverUtilDeactivate(void *controller, int isEnabled) { - [(ScreenSaverController*)controller screenSaverStopNow]; - [(ScreenSaverController*)controller setScreenSaverCanRun:isEnabled]; + [(ScreenSaverController *)controller screenSaverStopNow]; + [(ScreenSaverController *)controller setScreenSaverCanRun:isEnabled]; } -int -screenSaverUtilIsActive(void* controller) +int screenSaverUtilIsActive(void *controller) { - return [(ScreenSaverController*)controller screenSaverIsRunning]; + return [(ScreenSaverController *)controller screenSaverIsRunning]; }