From fd0d6597729e8549ba7b838798bfa12b19f6d171 Mon Sep 17 00:00:00 2001 From: Levent Duivel Date: Fri, 8 Nov 2024 00:40:14 +0500 Subject: [PATCH] refactored into ObjC without C++ --- screendump/FrameUpdater.h | 6 +- screendump/FrameUpdater.m | 79 +++ screendump/IOHID.h | 30 + screendump/IOMobileFramebuffer.h | 37 ++ screendump/Makefile | 2 +- screendump/ScreenDumpVNC.h | 12 + screendump/ScreenDumpVNC.m | 173 ++++++ screendump/control | 2 +- .../ru.mostmodest.screendumpd.plist | 10 + .../Preferences/screendump/Preferences.plist | 4 +- screendump/main.m | 17 + screendump/main.mm | 551 ------------------ screendump/utils.h | 4 + screendump/utils.m | 15 + screendump/vnc.h | 8 + screendump/vnc.m | 195 +++++++ 16 files changed, 588 insertions(+), 557 deletions(-) create mode 100644 screendump/FrameUpdater.m create mode 100644 screendump/IOHID.h create mode 100644 screendump/IOMobileFramebuffer.h create mode 100644 screendump/ScreenDumpVNC.h create mode 100644 screendump/ScreenDumpVNC.m create mode 100644 screendump/main.m delete mode 100755 screendump/main.mm create mode 100644 screendump/utils.h create mode 100644 screendump/utils.m create mode 100644 screendump/vnc.h create mode 100644 screendump/vnc.m diff --git a/screendump/FrameUpdater.h b/screendump/FrameUpdater.h index eecd452..7993b6b 100644 --- a/screendump/FrameUpdater.h +++ b/screendump/FrameUpdater.h @@ -1,8 +1,10 @@ #import +#import +#import +#import "IOMobileFramebuffer.h" @interface FrameUpdater : NSObject -@property (nonatomic, retain) NSTimer* myTimer; -@property (nonatomic) BOOL isEnabled; +-(instancetype)initWithSurfaceInfo:(IOSurfaceRef)screenSurface rfbScreenInfo:(rfbScreenInfoPtr)rfbScreenInfo accelerator:(IOSurfaceAcceleratorRef)accelerator staticBuffer:(IOSurfaceRef)staticBuffer width:(size_t)width height:(size_t)height; - (void)startFrameLoop; - (void)stopFrameLoop; @end diff --git a/screendump/FrameUpdater.m b/screendump/FrameUpdater.m new file mode 100644 index 0000000..c925f21 --- /dev/null +++ b/screendump/FrameUpdater.m @@ -0,0 +1,79 @@ +#import "FrameUpdater.h" + +@implementation FrameUpdater { + + // Process + NSOperationQueue *_q; + BOOL _updatingFrames; + uint32_t _lastUpdatedSeed; + NSTimer* _updateFrameTimer; + + // Shared from ScreenDumpVNC + IOSurfaceRef _screenSurface; + rfbScreenInfoPtr _rfbScreenInfo; + IOSurfaceAcceleratorRef _accelerator; + IOSurfaceRef _staticBuffer; + size_t _width; + size_t _height; +} + +-(instancetype)initWithSurfaceInfo:(IOSurfaceRef)screenSurface rfbScreenInfo:(rfbScreenInfoPtr)rfbScreenInfo accelerator:(IOSurfaceAcceleratorRef)accelerator staticBuffer:(IOSurfaceRef)staticBuffer width:(size_t)width height:(size_t)height { + if ((self = [super init])) { + _q = [[NSOperationQueue alloc] init]; + _updatingFrames = NO; + _lastUpdatedSeed = 0; + _updateFrameTimer = nil; + + _screenSurface = screenSurface; + _rfbScreenInfo = rfbScreenInfo; + _accelerator = accelerator; + _staticBuffer = staticBuffer; + _width = width; + _height = height; + } + return self; +} + + +-(void)_updateFrame { + if (!_updatingFrames) { + [self stopFrameLoop]; + return; + } + + // check if screen changed + uint32_t currentFrameSeed = IOSurfaceGetSeed(_screenSurface); + + if (_lastUpdatedSeed != currentFrameSeed && rfbIsActive(_rfbScreenInfo)) { + _lastUpdatedSeed = currentFrameSeed; + [_q addOperationWithBlock: ^{ + IOSurfaceAcceleratorTransferSurface(_accelerator, _screenSurface, _staticBuffer, NULL, NULL, NULL, NULL); + rfbMarkRectAsModified(_rfbScreenInfo, 0, 0, _width, _height); + }]; + } +} + +-(void)stopFrameLoop { + if (_updateFrameTimer == nil || ![_updateFrameTimer isValid]) return; + + dispatch_async(dispatch_get_main_queue(), ^(void){ + [_updateFrameTimer invalidate]; + _updatingFrames = NO; + }); +} + +-(void)startFrameLoop { + // if (size_image == 0) VNCSetup(); + [self stopFrameLoop]; + _updatingFrames = YES; + dispatch_async(dispatch_get_main_queue(), ^(void){ + // TODO: can we make VSync happen here? + _updateFrameTimer = [NSTimer scheduledTimerWithTimeInterval:1/500 target:self selector:@selector(_updateFrame) userInfo:nil repeats:YES]; + }); +} + +-(void)dealloc { + [self stopFrameLoop]; +} + +@end diff --git a/screendump/IOHID.h b/screendump/IOHID.h new file mode 100644 index 0000000..0cf7404 --- /dev/null +++ b/screendump/IOHID.h @@ -0,0 +1,30 @@ +#import "./include/IOKit/hid/IOHIDEventTypes.h" +#import "./include/IOKit/hidsystem/IOHIDUsageTables.h" + +typedef uint32_t IOHIDDigitizerTransducerType; + +#ifdef __LP64__ +typedef double IOHIDFloat; +#else +typedef float IOHIDFloat; +#endif + +typedef UInt32 IOOptionBits; +typedef uint32_t IOHIDEventField; + +typedef uint32_t IOHIDEventOptionBits; +typedef struct __IOHIDEvent *IOHIDEventRef; +typedef struct CF_BRIDGED_TYPE(id) __IOHIDEventSystemClient * IOHIDEventSystemClientRef; +IOHIDEventRef IOHIDEventCreateKeyboardEvent( + CFAllocatorRef allocator, + uint64_t time, uint16_t page, uint16_t usage, + Boolean down, IOHIDEventOptionBits flags +); +IOHIDEventRef IOHIDEventCreateDigitizerEvent(CFAllocatorRef allocator, uint64_t timeStamp, IOHIDDigitizerTransducerType type, uint32_t index, uint32_t identity, uint32_t eventMask, uint32_t buttonMask, IOHIDFloat x, IOHIDFloat y, IOHIDFloat z, IOHIDFloat tipPressure, IOHIDFloat barrelPressure, Boolean range, Boolean touch, IOOptionBits options); +IOHIDEventRef IOHIDEventCreateDigitizerFingerEvent(CFAllocatorRef allocator, uint64_t timeStamp, uint32_t index, uint32_t identity, uint32_t eventMask, IOHIDFloat x, IOHIDFloat y, IOHIDFloat z, IOHIDFloat tipPressure, IOHIDFloat twist, Boolean range, Boolean touch, IOOptionBits options); +IOHIDEventSystemClientRef IOHIDEventSystemClientCreate(CFAllocatorRef allocator); +void IOHIDEventAppendEvent(IOHIDEventRef parent, IOHIDEventRef child); +void IOHIDEventSetIntegerValue(IOHIDEventRef event, IOHIDEventField field, int value); +void IOHIDEventSetSenderID(IOHIDEventRef event, uint64_t sender); +void IOHIDEventSystemClientDispatchEvent(IOHIDEventSystemClientRef client, IOHIDEventRef event); +// void IOHIDEventSystemConnectionDispatchEvent(IOHIDEventSystemConnectionRef connection, IOHIDEventRef event); diff --git a/screendump/IOMobileFramebuffer.h b/screendump/IOMobileFramebuffer.h new file mode 100644 index 0000000..79d56dd --- /dev/null +++ b/screendump/IOMobileFramebuffer.h @@ -0,0 +1,37 @@ +#import + +typedef void *IOMobileFramebufferRef; +typedef void *IOSurfaceAcceleratorRef; +typedef struct __IOMobileFramebuffer *IOMobileFramebufferConnection; + +extern CFStringRef kIOSurfaceMemoryRegion; +extern const CFStringRef kIOSurfaceIsGlobal; + +extern void IOMobileFramebufferGetDisplaySize(IOMobileFramebufferRef connect, CGSize *size); +extern int IOSurfaceAcceleratorCreate(CFAllocatorRef allocator, int type, IOSurfaceAcceleratorRef *accel); +extern unsigned int IOSurfaceAcceleratorTransferSurface(IOSurfaceAcceleratorRef accelerator, IOSurfaceRef dest, IOSurfaceRef src, void *, void *, void *, void *); + +extern kern_return_t IOMobileFramebufferSwapSetLayer( + IOMobileFramebufferRef fb, + int layer, + IOSurfaceRef buffer, + CGRect bounds, + CGRect frame, + int flags +); +typedef mach_port_t io_service_t; +typedef kern_return_t IOReturn; +typedef IOReturn IOMobileFramebufferReturn; +typedef io_service_t IOMobileFramebufferService; +extern void IOSurfaceFlushProcessorCaches(IOSurfaceRef buffer); +extern int IOSurfaceLock(IOSurfaceRef surface, uint32_t options, uint32_t *seed); +extern int IOSurfaceUnlock(IOSurfaceRef surface, uint32_t options, uint32_t *seed); +extern Boolean IOSurfaceIsInUse(IOSurfaceRef buffer); +extern CFMutableDictionaryRef IOServiceMatching(const char *name); +extern const mach_port_t kIOMasterPortDefault; +extern io_service_t IOServiceGetMatchingService(mach_port_t masterPort, CFDictionaryRef matching); +extern IOMobileFramebufferReturn IOMobileFramebufferGetLayerDefaultSurface(IOMobileFramebufferRef pointer, int surface, IOSurfaceRef *buffer); +extern IOMobileFramebufferReturn IOMobileFramebufferCopyLayerDisplayedSurface(IOMobileFramebufferRef pointer, int surface, IOSurfaceRef *buffer); +extern IOMobileFramebufferReturn IOMobileFramebufferOpen(IOMobileFramebufferService service, mach_port_t owningTask, unsigned int type, IOMobileFramebufferRef *pointer); +extern IOMobileFramebufferReturn IOMobileFramebufferGetMainDisplay(IOMobileFramebufferRef *pointer); +extern mach_port_t mach_task_self(); \ No newline at end of file diff --git a/screendump/Makefile b/screendump/Makefile index fbde1e1..64c4cbd 100644 --- a/screendump/Makefile +++ b/screendump/Makefile @@ -7,7 +7,7 @@ export COPYFILE_DISABLE=1 include $(THEOS)/makefiles/common.mk TOOL_NAME = screendumpd -$(TOOL_NAME)_FILES = main.mm +$(TOOL_NAME)_FILES = $(wildcard *.m) $(TOOL_NAME)_FRAMEWORKS := IOSurface IOKit $(TOOL_NAME)_PRIVATE_FRAMEWORKS := IOMobileFramebuffer IOSurface $(TOOL_NAME)_OBJCFLAGS += -I./vncbuild/include -Iinclude diff --git a/screendump/ScreenDumpVNC.h b/screendump/ScreenDumpVNC.h new file mode 100644 index 0000000..0d45de8 --- /dev/null +++ b/screendump/ScreenDumpVNC.h @@ -0,0 +1,12 @@ +#import +#import + +#define kVNCServerName "ScreenDumpVNC" + +@interface ScreenDumpVNC : NSObject ++(void)load; ++(instancetype)sharedInstance; +-(rfbBool)handleVNCAuthorization:(rfbClientPtr)client data:(const char *)data size:(int)size; +-(size_t)width; +-(size_t)height; +@end \ No newline at end of file diff --git a/screendump/ScreenDumpVNC.m b/screendump/ScreenDumpVNC.m new file mode 100644 index 0000000..bce997f --- /dev/null +++ b/screendump/ScreenDumpVNC.m @@ -0,0 +1,173 @@ +#import "ScreenDumpVNC.h" +#import "FrameUpdater.h" +#import "utils.h" +#import "vnc.h" +#import +#import +#import "IOMobileFramebuffer.h" + +@implementation ScreenDumpVNC { + int _prefsHeight; + int _prefsWidth; + bool _enabled; + NSString *_password; + rfbScreenInfoPtr _rfbScreenInfo; + bool _vncIsRunning; + + // sent to FrameUpdater + IOSurfaceRef _screenSurface; + size_t _sizeImage; + IOSurfaceAcceleratorRef _accelerator; + IOSurfaceRef _staticBuffer; + size_t _width; + size_t _height; + + FrameUpdater *_frameUpdater; +} + ++(void)load { + ScreenDumpVNC* sharedInstance = [self sharedInstance]; + if (![sharedInstance enabled]) return; + [sharedInstance setupScreenInfo]; + [sharedInstance startVNCServer]; +} + ++(instancetype)sharedInstance { + static dispatch_once_t onceToken = 0; + __strong static ScreenDumpVNC* sharedInstance = nil; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + return sharedInstance; +} + +-(instancetype)init { + if ((self = [super init])) { + // TODO: init procedures + [self loadPrefs]; + } + return self; +} + +-(void)loadPrefs { + NSDictionary* defaults = getPrefsForAppId(@"ru.mostmodest.screendump"); + NSNumber *height = [defaults objectForKey:@"height"]; + _prefsHeight = height ? [height intValue] : 0; + + NSNumber *width = [defaults objectForKey:@"width"]; + _prefsWidth = width ? [width intValue] : 0; + + NSNumber *enabled = [defaults objectForKey:@"enabled"]; + _enabled = enabled ? [enabled boolValue] : NO; + _password = [defaults objectForKey:@"password"]; +} + +-(void)setupVNCAuthentication { + if (_rfbScreenInfo == nil) return; + + _rfbScreenInfo->authPasswdData = nil; + if (_password && _password.length) { + _rfbScreenInfo->authPasswdData = (void *)_password; + } +} + +-(void)startVNCServer { + if (_rfbScreenInfo == nil || _vncIsRunning == YES) return; + + [self setupVNCAuthentication]; + rfbInitServer(_rfbScreenInfo); + rfbRunEventLoop(_rfbScreenInfo, -1, YES); + [_frameUpdater startFrameLoop]; +} + +-(void)shutdownVNCServer { + // unused + if (_rfbScreenInfo == nil || _vncIsRunning == NO) return; + + [_frameUpdater stopFrameLoop]; + rfbShutdownServer(_rfbScreenInfo, YES); +} + +-(void)setupScreenInfo { + size_t bytesPerPixel; + size_t bitsPerSample; + + if (!_screenSurface) { + IOMobileFramebufferRef framebufferConnection; + + IOSurfaceAcceleratorCreate(kCFAllocatorDefault, 0, &_accelerator); + IOMobileFramebufferGetMainDisplay(&framebufferConnection); + IOMobileFramebufferGetLayerDefaultSurface(framebufferConnection, 0, &_screenSurface); + + if (_screenSurface == NULL) IOMobileFramebufferCopyLayerDisplayedSurface(framebufferConnection, 0, &_screenSurface); + + _width = _prefsWidth == 0 ? IOSurfaceGetWidth(_screenSurface) : _prefsWidth; + _height = _prefsHeight == 0 ? IOSurfaceGetHeight(_screenSurface) : _prefsHeight; + + _sizeImage = IOSurfaceGetAllocSize(_screenSurface); + // TODO: do these change at all? this might have been done for perf reasons + // bytesPerRow = IOSurfaceGetBytesPerRow(_screenSurface); + // pixelF = IOSurfaceGetPixelFormat(_screenSurface); + + bytesPerPixel = 4; // IOSurfaceGetBytesPerElement(_screenSurface); + bitsPerSample = 8; + + _staticBuffer = IOSurfaceCreate((CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys: + @"PurpleEDRAM", kIOSurfaceMemoryRegion, + [NSNumber numberWithBool:YES], kIOSurfaceIsGlobal, + [NSNumber numberWithInt:bytesPerPixel*_width], kIOSurfaceBytesPerRow, + [NSNumber numberWithInt:bytesPerPixel], kIOSurfaceBytesPerElement, + [NSNumber numberWithInt:_width], kIOSurfaceWidth, + [NSNumber numberWithInt:_height], kIOSurfaceHeight, + [NSNumber numberWithInt:'BGRA'], kIOSurfacePixelFormat, + [NSNumber numberWithInt:(_width*_height*bytesPerPixel)], kIOSurfaceAllocSize, + nil]); + } + + int argc = 1; + char *arg0 = strdup(kVNCServerName); + char *argv[] = {arg0, NULL}; + int samplesPerPixel = 3; + + _rfbScreenInfo = rfbGetScreen(&argc, argv, _width, _height, bitsPerSample, samplesPerPixel, bytesPerPixel); + + _rfbScreenInfo->frameBuffer = (char *)IOSurfaceGetBaseAddress((IOSurfaceRef)CFRetain(_staticBuffer)); + _rfbScreenInfo->serverFormat.redShift = bitsPerSample * 2; + _rfbScreenInfo->serverFormat.greenShift = bitsPerSample * 1; + _rfbScreenInfo->serverFormat.blueShift = bitsPerSample * 0; + + _rfbScreenInfo->kbdAddEvent = &handleVNCKeyboard; + _rfbScreenInfo->ptrAddEvent = &handleVNCPointer; + _rfbScreenInfo->passwordCheck = &handleVNCAuthorization; + + free(arg0); + + _frameUpdater = [[FrameUpdater alloc] initWithSurfaceInfo:_screenSurface rfbScreenInfo:_rfbScreenInfo accelerator:_accelerator staticBuffer:_staticBuffer width:_width height:_height]; +} + +-(rfbBool)handleVNCAuthorization:(rfbClientPtr)client data:(const char *)data size:(int)size { + NSString *password = (__bridge NSString *)(_rfbScreenInfo->authPasswdData); + if (!password) { + return TRUE; + } + if ([password length] == 0) { + return TRUE; + } + rfbEncryptBytes(client->authChallenge, (char *)[password UTF8String]); + bool good = (memcmp(client->authChallenge, data, size) == 0); + return good; +} + +-(size_t)width { + return _width; +} + +-(size_t)height { + return _height; +} + +-(bool)enabled { + return _enabled; +} + +@end diff --git a/screendump/control b/screendump/control index 1b414f5..2a42fc4 100644 --- a/screendump/control +++ b/screendump/control @@ -8,4 +8,4 @@ Section: Tweaks Conflicts: ru.mostmodest.screendump.lowframe Depends: mobilesubstrate, preferenceloader Icon: file:///Library/PreferenceLoader/Preferences/screendump/ScreenDump@2x.png -Version: 0.0.5.2 +Version: 0.1.0 diff --git a/screendump/layout/Library/LaunchDaemons/ru.mostmodest.screendumpd.plist b/screendump/layout/Library/LaunchDaemons/ru.mostmodest.screendumpd.plist index 98eb973..d40b65a 100644 --- a/screendump/layout/Library/LaunchDaemons/ru.mostmodest.screendumpd.plist +++ b/screendump/layout/Library/LaunchDaemons/ru.mostmodest.screendumpd.plist @@ -12,5 +12,15 @@ KeepAlive + SoftResourceLimits + + Core + 9223372036854775807 + + HardResourceLimits + + Core + 9223372036854775807 + diff --git a/screendump/layout/Library/PreferenceLoader/Preferences/screendump/Preferences.plist b/screendump/layout/Library/PreferenceLoader/Preferences/screendump/Preferences.plist index c88b5bb..968f93c 100644 --- a/screendump/layout/Library/PreferenceLoader/Preferences/screendump/Preferences.plist +++ b/screendump/layout/Library/PreferenceLoader/Preferences/screendump/Preferences.plist @@ -29,7 +29,7 @@ defaults ru.mostmodest.screendump key - CCSisEnabled + enabled label Enabled @@ -41,7 +41,7 @@ defaults ru.mostmodest.screendump key - CCSPassword + password label Password diff --git a/screendump/main.m b/screendump/main.m new file mode 100644 index 0000000..cd15241 --- /dev/null +++ b/screendump/main.m @@ -0,0 +1,17 @@ +#import +#import +#import "ScreenDumpVNC.h" +#import "utils.h" + +#define kPreferencesNotify "ru.mostmodest.screendump/restart" + +int main(int argc, char *argv[], char *envp[]) { + @autoreleasepool { + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)exitProcess, CFSTR(kPreferencesNotify), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + + [ScreenDumpVNC load]; + [[NSRunLoop currentRunLoop] run]; + CFRunLoopRun(); + return 0; + } +} \ No newline at end of file diff --git a/screendump/main.mm b/screendump/main.mm deleted file mode 100755 index d424e33..0000000 --- a/screendump/main.mm +++ /dev/null @@ -1,551 +0,0 @@ -#import -#import -#import -#import -#import - -#import "FrameUpdater.h" - -#define kSettingsPath @"/var/mobile/Library/Preferences/ru.mostmodest.screendump.plist" - -static bool CCSisEnabled = true; -static NSString *CCSPassword = nil; -static rfbScreenInfoPtr screen; -static bool isVNCRunning; -// static NSCondition *condition_; -static NSLock *lock; -static size_t width; -static size_t height; -static size_t byte_per_pixel; -static size_t bytesPerRow; -static size_t pixelF; -static size_t bits_per_sample = 8; - -static size_t size_image; - -static size_t prefferH; -static size_t prefferW; - -static CFTypeRef (*$GSSystemCopyCapability)(CFStringRef); -static CFTypeRef (*$GSSystemGetCapability)(CFStringRef); -static BOOL (*$MGGetBoolAnswer)(CFStringRef); - -typedef void *IOMobileFramebufferRef; -typedef void *IOSurfaceAcceleratorRef; -typedef struct __IOMobileFramebuffer *IOMobileFramebufferConnection; - -extern CFStringRef kIOSurfaceMemoryRegion; -extern const CFStringRef kIOSurfaceIsGlobal; - -extern "C" void IOMobileFramebufferGetDisplaySize(IOMobileFramebufferRef connect, CGSize *size); -extern "C" int IOSurfaceAcceleratorCreate(CFAllocatorRef allocator, int type, IOSurfaceAcceleratorRef *accel); -extern "C" unsigned int IOSurfaceAcceleratorTransferSurface(IOSurfaceAcceleratorRef accelerator, IOSurfaceRef dest, IOSurfaceRef src, void *, void *, void *, void *); - -extern "C" kern_return_t IOMobileFramebufferSwapSetLayer( - IOMobileFramebufferRef fb, - int layer, - IOSurfaceRef buffer, - CGRect bounds, - CGRect frame, - int flags -); -typedef mach_port_t io_service_t; -typedef kern_return_t IOReturn; -typedef IOReturn IOMobileFramebufferReturn; -typedef io_service_t IOMobileFramebufferService; -// extern "C" mach_port_t mach_task_self(void); -extern "C" void IOSurfaceFlushProcessorCaches(IOSurfaceRef buffer); -extern "C" int IOSurfaceLock(IOSurfaceRef surface, uint32_t options, uint32_t *seed); -extern "C" int IOSurfaceUnlock(IOSurfaceRef surface, uint32_t options, uint32_t *seed); -extern "C" Boolean IOSurfaceIsInUse(IOSurfaceRef buffer); -extern "C" CFMutableDictionaryRef IOServiceMatching(const char *name); -extern "C" const mach_port_t kIOMasterPortDefault; -extern "C" io_service_t IOServiceGetMatchingService(mach_port_t masterPort, CFDictionaryRef matching); -extern "C" IOMobileFramebufferReturn IOMobileFramebufferGetLayerDefaultSurface(IOMobileFramebufferRef pointer, int surface, IOSurfaceRef *buffer); -extern "C" IOMobileFramebufferReturn IOMobileFramebufferCopyLayerDisplayedSurface(IOMobileFramebufferRef pointer, int surface, IOSurfaceRef *buffer); -extern "C" IOMobileFramebufferReturn IOMobileFramebufferOpen(IOMobileFramebufferService service, mach_port_t owningTask, unsigned int type, IOMobileFramebufferRef *pointer); -extern "C" IOMobileFramebufferReturn IOMobileFramebufferGetMainDisplay(IOMobileFramebufferRef *pointer); -extern "C" mach_port_t mach_task_self(); -static IOSurfaceAcceleratorRef accelerator; -static IOSurfaceRef static_buffer; - -static void VNCSettings(bool shouldStart, NSString *password); -static void VNCUpdateRunState(bool shouldStart); -static void handleVNCKeyboard(rfbBool down, rfbKeySym key, rfbClientPtr client); -static void handleVNCPointer(int buttons, int x, int y, rfbClientPtr client); - -static rfbBool VNCCheck(rfbClientPtr client, const char *data, int size) -{ - NSString *password = reinterpret_cast(screen->authPasswdData); - if(!password) { - return TRUE; - } - if ([password length] == 0) { - return TRUE; - } - NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); - rfbEncryptBytes(client->authChallenge, const_cast([password UTF8String])); - bool good(memcmp(client->authChallenge, data, size) == 0); - [pool release]; - return good; -} - -static IOSurfaceRef screenSurface = NULL; -static IOMobileFramebufferRef framebufferConnection = NULL; - -static void VNCSetup() -{ - if(!screenSurface) { - IOSurfaceAcceleratorCreate(kCFAllocatorDefault, 0, &accelerator); - - IOMobileFramebufferGetMainDisplay(&framebufferConnection); - - IOMobileFramebufferGetLayerDefaultSurface(framebufferConnection, 0, &screenSurface); - if(screenSurface == NULL) - IOMobileFramebufferCopyLayerDisplayedSurface(framebufferConnection, 0, &screenSurface); - - //CGSize size; - //IOMobileFramebufferGetDisplaySize(framebufferConnection, &size); - //width = size.width/2; - //height = size.height/2; - - width = prefferW == 0 ? IOSurfaceGetWidth(screenSurface) : prefferW; - height = prefferW == 0 ? IOSurfaceGetHeight(screenSurface) : prefferH; - - size_image = IOSurfaceGetAllocSize(screenSurface); - bytesPerRow = IOSurfaceGetBytesPerRow(screenSurface); - pixelF = IOSurfaceGetPixelFormat(screenSurface); - - byte_per_pixel = 4;//IOSurfaceGetBytesPerElement(screenSurface); - bits_per_sample = 8; - - - - static_buffer = IOSurfaceCreate((CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys: - @"PurpleEDRAM", kIOSurfaceMemoryRegion, - //[NSNumber numberWithBool:YES], kIOSurfaceIsGlobal, - [NSNumber numberWithInt:byte_per_pixel*width], kIOSurfaceBytesPerRow, - [NSNumber numberWithInt:byte_per_pixel], kIOSurfaceBytesPerElement, - [NSNumber numberWithInt:width], kIOSurfaceWidth, - [NSNumber numberWithInt:height], kIOSurfaceHeight, - [NSNumber numberWithInt:'BGRA'], kIOSurfacePixelFormat, - [NSNumber numberWithInt:(width*height*byte_per_pixel)], kIOSurfaceAllocSize, - nil]); - } - - int argc(1); - char *arg0(strdup("ScreenDumpVNC")); - char *argv[] = {arg0, NULL}; - screen = rfbGetScreen(&argc, argv, width, height, bits_per_sample, 3, byte_per_pixel); - screen->frameBuffer = reinterpret_cast(IOSurfaceGetBaseAddress((IOSurfaceRef)CFRetain(static_buffer))); - screen->serverFormat.redShift = bits_per_sample * 2; - screen->serverFormat.greenShift = bits_per_sample * 1; - screen->serverFormat.blueShift = bits_per_sample * 0; - screen->kbdAddEvent = &handleVNCKeyboard; - screen->ptrAddEvent = &handleVNCPointer; - screen->passwordCheck = &VNCCheck; - free(arg0); - VNCUpdateRunState(CCSisEnabled); -} - -static void VNCSettings(bool shouldStart, NSString* password) -{ - CCSisEnabled = shouldStart; - if(password) { - CCSPassword = password; - } - NSString *sEnabled = CCSisEnabled ? @"YES": @"NO"; - [[FrameUpdater shared] setIsEnabled:CCSisEnabled]; - VNCUpdateRunState(CCSisEnabled); -} - - - -static void VNCUpdateRunState(bool shouldStart) -{ - if(screen == NULL) { - return; - } - - if (CCSPassword && CCSPassword.length) { - screen->authPasswdData = (void *) CCSPassword; - } else { - screen->authPasswdData = NULL; - } - if (shouldStart == isVNCRunning) { - return; - } - if (shouldStart) { - rfbInitServer(screen); - rfbRunEventLoop(screen, -1, true); - [[FrameUpdater shared] startFrameLoop]; - } else { - [[FrameUpdater shared] stopFrameLoop]; - rfbShutdownServer(screen, true); - } - isVNCRunning = shouldStart; -} - -static void loadPrefs(void) -{ - @autoreleasepool { - NSDictionary* defaults = nil; - CFStringRef appID = CFSTR("ru.mostmodest.screendump"); - CFArrayRef keyList = CFPreferencesCopyKeyList(appID, CFSTR("mobile"), kCFPreferencesAnyHost); - if(keyList) { - defaults = (NSDictionary *)CFPreferencesCopyMultiple(keyList, appID, CFSTR("mobile"), kCFPreferencesAnyHost)?:@{}; - CFRelease(keyList); - } - - prefferH = [[defaults objectForKey:@"height"]?:@(0) intValue]; - prefferW = [[defaults objectForKey:@"width"]?:@(0) intValue]; - - BOOL isEnabled = [[defaults objectForKey:@"CCSisEnabled"]?:@NO boolValue]; - NSString *password = [defaults objectForKey:@"CCSPassword"]; - VNCSettings(isEnabled, password); - } -} - - -static uint32_t oldSeed; - -@implementation FrameUpdater { - NSOperationQueue *_q; - BOOL _isLoopFrame; -} -@synthesize myTimer; -@synthesize isEnabled; - -+(id)shared -{ - static dispatch_once_t onceToken = 0; - __strong static FrameUpdater* sharedInstance = nil; - dispatch_once(&onceToken, ^{ - sharedInstance = [[self alloc] init]; - }); - return sharedInstance; -} - --(id)init -{ - if ((self = [super init])) - { - _q = [[NSOperationQueue alloc] init]; - _isLoopFrame = NO; - isEnabled = NO; - } - return self; -} - --(void)_upFrameLoop -{ - if (_isLoopFrame && isEnabled) { - //check if screen changed - uint32_t newSeed = IOSurfaceGetSeed(screenSurface); - - if(oldSeed != newSeed && rfbIsActive(screen)) { - oldSeed = newSeed; - [_q addOperationWithBlock: ^{ - IOSurfaceAcceleratorTransferSurface(accelerator, screenSurface, static_buffer, NULL, NULL, NULL, NULL); - rfbMarkRectAsModified(screen, 0, 0, width, height); - }]; - } - } else { - [self stopFrameLoop]; - } -} - --(void)stopFrameLoop -{ - if(myTimer && [myTimer isValid]) { - dispatch_async(dispatch_get_main_queue(), ^(void){ - [myTimer invalidate]; - _isLoopFrame = NO; - }); - } -} - --(void)startFrameLoop -{ - if(size_image == 0) { - VNCSetup(); - } - [self stopFrameLoop]; - _isLoopFrame = YES; - dispatch_async(dispatch_get_main_queue(), ^(void){ - myTimer = [NSTimer scheduledTimerWithTimeInterval:1/400 target:self selector:@selector(_upFrameLoop) userInfo:nil repeats:YES]; - }); -} - --(void)dealloc -{ - [self stopFrameLoop]; -} -@end - - -static void restartServer() -{ - exit(0); -} - -int main(int argc, const char *argv[]) -{ - CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)loadPrefs, CFSTR("ru.mostmodest.screendump/preferences.changed"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); - CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)restartServer, CFSTR("ru.mostmodest.screendump/restart"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); - - loadPrefs(); - - VNCSetup(); - //VNCBlack(); - - - - [[NSRunLoop currentRunLoop] run]; - - return EXIT_SUCCESS; -} - - -#import -#import -#import -#import -#import "./include/IOKit/hid/IOHIDEventTypes.h" -#import "./include/IOKit/hidsystem/IOHIDUsageTables.h" - -typedef uint32_t IOHIDDigitizerTransducerType; - -#ifdef __LP64__ -typedef double IOHIDFloat; -#else -typedef float IOHIDFloat; -#endif - -typedef UInt32 IOOptionBits; -typedef uint32_t IOHIDEventField; - -extern "C" { - typedef uint32_t IOHIDEventOptionBits; - typedef struct __IOHIDEvent *IOHIDEventRef; - typedef struct CF_BRIDGED_TYPE(id) __IOHIDEventSystemClient * IOHIDEventSystemClientRef; - IOHIDEventRef IOHIDEventCreateKeyboardEvent( - CFAllocatorRef allocator, - uint64_t time, uint16_t page, uint16_t usage, - Boolean down, IOHIDEventOptionBits flags - ); - - IOHIDEventRef IOHIDEventCreateDigitizerEvent(CFAllocatorRef allocator, uint64_t timeStamp, IOHIDDigitizerTransducerType type, uint32_t index, uint32_t identity, uint32_t eventMask, uint32_t buttonMask, IOHIDFloat x, IOHIDFloat y, IOHIDFloat z, IOHIDFloat tipPressure, IOHIDFloat barrelPressure, Boolean range, Boolean touch, IOOptionBits options); - IOHIDEventRef IOHIDEventCreateDigitizerFingerEvent(CFAllocatorRef allocator, uint64_t timeStamp, uint32_t index, uint32_t identity, uint32_t eventMask, IOHIDFloat x, IOHIDFloat y, IOHIDFloat z, IOHIDFloat tipPressure, IOHIDFloat twist, Boolean range, Boolean touch, IOOptionBits options); - - IOHIDEventSystemClientRef IOHIDEventSystemClientCreate(CFAllocatorRef allocator); - - void IOHIDEventAppendEvent(IOHIDEventRef parent, IOHIDEventRef child); - void IOHIDEventSetIntegerValue(IOHIDEventRef event, IOHIDEventField field, int value); - void IOHIDEventSetSenderID(IOHIDEventRef event, uint64_t sender); - - void IOHIDEventSystemClientDispatchEvent(IOHIDEventSystemClientRef client, IOHIDEventRef event); - // void IOHIDEventSystemConnectionDispatchEvent(IOHIDEventSystemConnectionRef connection, IOHIDEventRef event); -} - -static void VNCPointerNew(int buttons, int x, int y, CGPoint location, int diff, bool twas, bool tis); - -static void SendHIDEvent(IOHIDEventRef event) -{ - static IOHIDEventSystemClientRef client_(NULL); - if (client_ == NULL) { - client_ = IOHIDEventSystemClientCreate(kCFAllocatorDefault); - } - IOHIDEventSetSenderID(event, 0x8000000817319372); - IOHIDEventSystemClientDispatchEvent(client_, event); - CFRelease(event); -} - -static void VNCKeyboard(rfbBool down, rfbKeySym key, rfbClientPtr client) -{ - uint16_t usage; - - switch (key) { - case XK_exclam: case XK_1: usage = kHIDUsage_Keyboard1; break; - case XK_at: case XK_2: usage = kHIDUsage_Keyboard2; break; - case XK_numbersign: case XK_3: usage = kHIDUsage_Keyboard3; break; - case XK_dollar: case XK_4: usage = kHIDUsage_Keyboard4; break; - case XK_percent: case XK_5: usage = kHIDUsage_Keyboard5; break; - case XK_asciicircum: case XK_6: usage = kHIDUsage_Keyboard6; break; - case XK_ampersand: case XK_7: usage = kHIDUsage_Keyboard7; break; - case XK_asterisk: case XK_8: usage = kHIDUsage_Keyboard8; break; - case XK_parenleft: case XK_9: usage = kHIDUsage_Keyboard9; break; - case XK_parenright: case XK_0: usage = kHIDUsage_Keyboard0; break; - - case XK_A: case XK_a: usage = kHIDUsage_KeyboardA; break; - case XK_B: case XK_b: usage = kHIDUsage_KeyboardB; break; - case XK_C: case XK_c: usage = kHIDUsage_KeyboardC; break; - case XK_D: case XK_d: usage = kHIDUsage_KeyboardD; break; - case XK_E: case XK_e: usage = kHIDUsage_KeyboardE; break; - case XK_F: case XK_f: usage = kHIDUsage_KeyboardF; break; - case XK_G: case XK_g: usage = kHIDUsage_KeyboardG; break; - case XK_H: case XK_h: usage = kHIDUsage_KeyboardH; break; - case XK_I: case XK_i: usage = kHIDUsage_KeyboardI; break; - case XK_J: case XK_j: usage = kHIDUsage_KeyboardJ; break; - case XK_K: case XK_k: usage = kHIDUsage_KeyboardK; break; - case XK_L: case XK_l: usage = kHIDUsage_KeyboardL; break; - case XK_M: case XK_m: usage = kHIDUsage_KeyboardM; break; - case XK_N: case XK_n: usage = kHIDUsage_KeyboardN; break; - case XK_O: case XK_o: usage = kHIDUsage_KeyboardO; break; - case XK_P: case XK_p: usage = kHIDUsage_KeyboardP; break; - case XK_Q: case XK_q: usage = kHIDUsage_KeyboardQ; break; - case XK_R: case XK_r: usage = kHIDUsage_KeyboardR; break; - case XK_S: case XK_s: usage = kHIDUsage_KeyboardS; break; - case XK_T: case XK_t: usage = kHIDUsage_KeyboardT; break; - case XK_U: case XK_u: usage = kHIDUsage_KeyboardU; break; - case XK_V: case XK_v: usage = kHIDUsage_KeyboardV; break; - case XK_W: case XK_w: usage = kHIDUsage_KeyboardW; break; - case XK_X: case XK_x: usage = kHIDUsage_KeyboardX; break; - case XK_Y: case XK_y: usage = kHIDUsage_KeyboardY; break; - case XK_Z: case XK_z: usage = kHIDUsage_KeyboardZ; break; - - case XK_underscore: case XK_minus: usage = kHIDUsage_KeyboardHyphen; break; - case XK_plus: case XK_equal: usage = kHIDUsage_KeyboardEqualSign; break; - case XK_braceleft: case XK_bracketleft: usage = kHIDUsage_KeyboardOpenBracket; break; - case XK_braceright: case XK_bracketright: usage = kHIDUsage_KeyboardCloseBracket; break; - case XK_bar: case XK_backslash: usage = kHIDUsage_KeyboardBackslash; break; - case XK_colon: case XK_semicolon: usage = kHIDUsage_KeyboardSemicolon; break; - case XK_quotedbl: case XK_apostrophe: usage = kHIDUsage_KeyboardQuote; break; - case XK_asciitilde: case XK_grave: usage = kHIDUsage_KeyboardGraveAccentAndTilde; break; - case XK_less: case XK_comma: usage = kHIDUsage_KeyboardComma; break; - case XK_greater: case XK_period: usage = kHIDUsage_KeyboardPeriod; break; - case XK_question: case XK_slash: usage = kHIDUsage_KeyboardSlash; break; - - case XK_Return: usage = kHIDUsage_KeyboardReturnOrEnter; break; - case XK_BackSpace: usage = kHIDUsage_KeyboardDeleteOrBackspace; break; - case XK_Tab: usage = kHIDUsage_KeyboardTab; break; - case XK_space: usage = kHIDUsage_KeyboardSpacebar; break; - - case XK_Shift_L: usage = kHIDUsage_KeyboardLeftShift; break; - case XK_Shift_R: usage = kHIDUsage_KeyboardRightShift; break; - case XK_Control_L: usage = kHIDUsage_KeyboardLeftGUI; break; - case XK_Control_R: usage = kHIDUsage_KeyboardRightGUI; break; - case XK_Meta_L: usage = kHIDUsage_KeyboardLeftControl; break; - case XK_Meta_R: usage = kHIDUsage_KeyboardRightControl; break; - case XK_Alt_L: usage = kHIDUsage_KeyboardLeftAlt; break; - case XK_Alt_R: usage = kHIDUsage_KeyboardRightAlt; break; - - case XK_Up: usage = kHIDUsage_KeyboardUpArrow; break; - case XK_Down: usage = kHIDUsage_KeyboardDownArrow; break; - case XK_Left: usage = kHIDUsage_KeyboardLeftArrow; break; - case XK_Right: usage = kHIDUsage_KeyboardRightArrow; break; - - case XK_Home: case XK_Begin: usage = kHIDUsage_KeyboardHome; break; - case XK_End: usage = kHIDUsage_KeyboardEnd; break; - case XK_Page_Up: usage = kHIDUsage_KeyboardPageUp; break; - case XK_Page_Down: usage = kHIDUsage_KeyboardPageDown; break; - - default: return; - } - - SendHIDEvent(IOHIDEventCreateKeyboardEvent(kCFAllocatorDefault, mach_absolute_time(), kHIDPage_KeyboardOrKeypad, usage, down, 0)); -} - -static int buttons_; -static int x_, y_; - -static void VNCPointer(int buttons, int x, int y, rfbClientPtr client) { - // if (ratio_ == 0) - // return; - - CGPoint location = {static_cast(x), static_cast(y)}; - - // if (width_ > height_) { - // int t(x); - // x = height_ - 1 - y; - // y = t; - - // if (!iPad1_) { - // x = height_ - 1 - x; - // y = width_ - 1 - y; - // } - // } - - // x /= ratio_; - // y /= ratio_; - - // x_ = x; y_ = y; - int diff = buttons_ ^ buttons; - bool twas((buttons_ & 0x1) != 0); - bool tis((buttons & 0x1) != 0); - buttons_ = buttons; - - rfbDefaultPtrAddEvent(buttons, x, y, client); - - // if (Ashikase(false)) { - // AshikaseSendEvent(x, y, buttons); - // return; - // } - - return VNCPointerNew(buttons, x, y, location, diff, twas, tis); -} - -static void VNCPointerNew(int buttons, int x, int y, CGPoint location, int diff, bool twas, bool tis) { - if ((diff & 0x10) != 0) - SendHIDEvent(IOHIDEventCreateKeyboardEvent(kCFAllocatorDefault, mach_absolute_time(), kHIDPage_Telephony, kHIDUsage_Tfon_Flash, (buttons & 0x10) != 0, 0)); - if ((diff & 0x04) != 0) - SendHIDEvent(IOHIDEventCreateKeyboardEvent(kCFAllocatorDefault, mach_absolute_time(), kHIDPage_Consumer, kHIDUsage_Csmr_Menu, (buttons & 0x04) != 0, 0)); - if ((diff & 0x02) != 0) - SendHIDEvent(IOHIDEventCreateKeyboardEvent(kCFAllocatorDefault, mach_absolute_time(), kHIDPage_Consumer, kHIDUsage_Csmr_Power, (buttons & 0x02) != 0, 0)); - - uint32_t handm; - uint32_t fingerm; - - if (twas == 0 && tis == 1) { - handm = kIOHIDDigitizerEventRange | kIOHIDDigitizerEventTouch | kIOHIDDigitizerEventIdentity; - fingerm = kIOHIDDigitizerEventRange | kIOHIDDigitizerEventTouch; - } else if (twas == 1 && tis == 1) { - handm = kIOHIDDigitizerEventPosition; - fingerm = kIOHIDDigitizerEventPosition; - } else if (twas == 1 && tis == 0) { - handm = kIOHIDDigitizerEventRange | kIOHIDDigitizerEventTouch | kIOHIDDigitizerEventIdentity | kIOHIDDigitizerEventPosition; - fingerm = kIOHIDDigitizerEventRange | kIOHIDDigitizerEventTouch; - } else return; - - // XXX: avoid division in VNCPointer() - // x *= ratio_; - // y *= ratio_; - - IOHIDFloat xf(x); - IOHIDFloat yf(y); - - xf /= width; - yf /= height; - - IOHIDEventRef hand(IOHIDEventCreateDigitizerEvent(kCFAllocatorDefault, mach_absolute_time(), kIOHIDDigitizerTransducerTypeHand, 1<<22, 1, handm, 0, xf, yf, 0, 0, 0, 0, 0, 0)); - IOHIDEventSetIntegerValue(hand, kIOHIDEventFieldIsBuiltIn, true); - IOHIDEventSetIntegerValue(hand, kIOHIDEventFieldDigitizerIsDisplayIntegrated, true); - - IOHIDEventRef finger(IOHIDEventCreateDigitizerFingerEvent(kCFAllocatorDefault, mach_absolute_time(), 3, 2, fingerm, xf, yf, 0, 0, 0, tis, tis, 0)); - IOHIDEventAppendEvent(hand, finger); - CFRelease(finger); - - SendHIDEvent(hand); -} - -static void handleVNCKeyboard(rfbBool down, rfbKeySym key, rfbClientPtr client) { - VNCKeyboard(down, key, client); -} - -static void handleVNCPointer(int buttons, int x, int y, rfbClientPtr client) { - VNCPointer(buttons, x, y, client); -} - -// 기본 22:11:52.331940+0900 kernel Corpse released, count at 0 -// 기본 22:11:52.414493+0900 kernel IOMFB: default_fb_surface: No Default FB Surface found. Return error -// 기본 22:11:52.414536+0900 kernel screendumpd[43722] Corpse allowed 1 of 5 -// 기본 22:11:52.606790+0900 kernel Corpse released, count at 0 -// 기본 22:11:52.682856+0900 kernel IOMFB: default_fb_surface: No Default FB Surface found. Return error -// 기본 22:11:52.682905+0900 kernel screendumpd[43723] Corpse allowed 1 of 5 -// 기본 22:11:52.876255+0900 kernel Corpse released, count at 0 -// 기본 22:11:52.915524+0900 kernel IOMFB: default_fb_surface: No Default FB Surface found. Return error -// 기본 22:11:52.915570+0900 kernel screendumpd[43724] Corpse allowed 1 of 5 -// 기본 22:11:53.105917+0900 kernel Corpse released, count at 0 -// 기본 22:11:53.277579+0900 kernel IOMFB: default_fb_surface: No Default FB Surface found. Return error -// 기본 22:11:53.277657+0900 kernel screendumpd[43725] Corpse allowed 1 of 5 -// 기본 22:11:53.407555+0900 kernel IOMFB: default_fb_surface: No Default FB Surface found. Return error diff --git a/screendump/utils.h b/screendump/utils.h new file mode 100644 index 0000000..2b7654e --- /dev/null +++ b/screendump/utils.h @@ -0,0 +1,4 @@ +#import + +extern NSDictionary* getPrefsForAppId(NSString *appID); +extern void exitProcess(); \ No newline at end of file diff --git a/screendump/utils.m b/screendump/utils.m new file mode 100644 index 0000000..48735a7 --- /dev/null +++ b/screendump/utils.m @@ -0,0 +1,15 @@ +#import "utils.h" + +NSDictionary* getPrefsForAppId(NSString *appID) { + NSDictionary* defaults = nil; + CFArrayRef keyList = CFPreferencesCopyKeyList((CFStringRef)appID, CFSTR("mobile"), kCFPreferencesAnyHost); + if (keyList) { + defaults = (NSDictionary *)CFPreferencesCopyMultiple(keyList, (CFStringRef)appID, CFSTR("mobile"), kCFPreferencesAnyHost) ? : @{}; + CFRelease(keyList); + } + return defaults; +} + +void exitProcess() { + exit(0); +} \ No newline at end of file diff --git a/screendump/vnc.h b/screendump/vnc.h new file mode 100644 index 0000000..f218529 --- /dev/null +++ b/screendump/vnc.h @@ -0,0 +1,8 @@ +#import +#import +#import +#import "IOHID.h" + +extern void handleVNCKeyboard(rfbBool down, rfbKeySym key, rfbClientPtr client); +extern void handleVNCPointer(int buttons, int x, int y, rfbClientPtr client); +extern rfbBool handleVNCAuthorization(rfbClientPtr client, const char *data, int size); \ No newline at end of file diff --git a/screendump/vnc.m b/screendump/vnc.m new file mode 100644 index 0000000..e8f544a --- /dev/null +++ b/screendump/vnc.m @@ -0,0 +1,195 @@ +#import "vnc.h" +#import "ScreenDumpVNC.h" + +static IOHIDEventSystemClientRef client_ = nil; + +void SendHIDEvent(IOHIDEventRef event) { + if (client_ == nil) { + client_ = IOHIDEventSystemClientCreate(kCFAllocatorDefault); + } + IOHIDEventSetSenderID(event, 0x8000000817319372); + IOHIDEventSystemClientDispatchEvent(client_, event); + CFRelease(event); +} + +rfbBool handleVNCAuthorization(rfbClientPtr client, const char *data, int size) { + ScreenDumpVNC *sharedInstance = [ScreenDumpVNC sharedInstance]; + return [sharedInstance handleVNCAuthorization:client data:data size:size]; +} + +void VNCKeyboard(rfbBool down, rfbKeySym key, rfbClientPtr client) { + uint16_t usage; + + switch (key) { + case XK_exclam: case XK_1: usage = kHIDUsage_Keyboard1; break; + case XK_at: case XK_2: usage = kHIDUsage_Keyboard2; break; + case XK_numbersign: case XK_3: usage = kHIDUsage_Keyboard3; break; + case XK_dollar: case XK_4: usage = kHIDUsage_Keyboard4; break; + case XK_percent: case XK_5: usage = kHIDUsage_Keyboard5; break; + case XK_asciicircum: case XK_6: usage = kHIDUsage_Keyboard6; break; + case XK_ampersand: case XK_7: usage = kHIDUsage_Keyboard7; break; + case XK_asterisk: case XK_8: usage = kHIDUsage_Keyboard8; break; + case XK_parenleft: case XK_9: usage = kHIDUsage_Keyboard9; break; + case XK_parenright: case XK_0: usage = kHIDUsage_Keyboard0; break; + + case XK_A: case XK_a: usage = kHIDUsage_KeyboardA; break; + case XK_B: case XK_b: usage = kHIDUsage_KeyboardB; break; + case XK_C: case XK_c: usage = kHIDUsage_KeyboardC; break; + case XK_D: case XK_d: usage = kHIDUsage_KeyboardD; break; + case XK_E: case XK_e: usage = kHIDUsage_KeyboardE; break; + case XK_F: case XK_f: usage = kHIDUsage_KeyboardF; break; + case XK_G: case XK_g: usage = kHIDUsage_KeyboardG; break; + case XK_H: case XK_h: usage = kHIDUsage_KeyboardH; break; + case XK_I: case XK_i: usage = kHIDUsage_KeyboardI; break; + case XK_J: case XK_j: usage = kHIDUsage_KeyboardJ; break; + case XK_K: case XK_k: usage = kHIDUsage_KeyboardK; break; + case XK_L: case XK_l: usage = kHIDUsage_KeyboardL; break; + case XK_M: case XK_m: usage = kHIDUsage_KeyboardM; break; + case XK_N: case XK_n: usage = kHIDUsage_KeyboardN; break; + case XK_O: case XK_o: usage = kHIDUsage_KeyboardO; break; + case XK_P: case XK_p: usage = kHIDUsage_KeyboardP; break; + case XK_Q: case XK_q: usage = kHIDUsage_KeyboardQ; break; + case XK_R: case XK_r: usage = kHIDUsage_KeyboardR; break; + case XK_S: case XK_s: usage = kHIDUsage_KeyboardS; break; + case XK_T: case XK_t: usage = kHIDUsage_KeyboardT; break; + case XK_U: case XK_u: usage = kHIDUsage_KeyboardU; break; + case XK_V: case XK_v: usage = kHIDUsage_KeyboardV; break; + case XK_W: case XK_w: usage = kHIDUsage_KeyboardW; break; + case XK_X: case XK_x: usage = kHIDUsage_KeyboardX; break; + case XK_Y: case XK_y: usage = kHIDUsage_KeyboardY; break; + case XK_Z: case XK_z: usage = kHIDUsage_KeyboardZ; break; + + case XK_underscore: case XK_minus: usage = kHIDUsage_KeyboardHyphen; break; + case XK_plus: case XK_equal: usage = kHIDUsage_KeyboardEqualSign; break; + case XK_braceleft: case XK_bracketleft: usage = kHIDUsage_KeyboardOpenBracket; break; + case XK_braceright: case XK_bracketright: usage = kHIDUsage_KeyboardCloseBracket; break; + case XK_bar: case XK_backslash: usage = kHIDUsage_KeyboardBackslash; break; + case XK_colon: case XK_semicolon: usage = kHIDUsage_KeyboardSemicolon; break; + case XK_quotedbl: case XK_apostrophe: usage = kHIDUsage_KeyboardQuote; break; + case XK_asciitilde: case XK_grave: usage = kHIDUsage_KeyboardGraveAccentAndTilde; break; + case XK_less: case XK_comma: usage = kHIDUsage_KeyboardComma; break; + case XK_greater: case XK_period: usage = kHIDUsage_KeyboardPeriod; break; + case XK_question: case XK_slash: usage = kHIDUsage_KeyboardSlash; break; + + case XK_Return: usage = kHIDUsage_KeyboardReturnOrEnter; break; + case XK_BackSpace: usage = kHIDUsage_KeyboardDeleteOrBackspace; break; + case XK_Tab: usage = kHIDUsage_KeyboardTab; break; + case XK_space: usage = kHIDUsage_KeyboardSpacebar; break; + + case XK_Shift_L: usage = kHIDUsage_KeyboardLeftShift; break; + case XK_Shift_R: usage = kHIDUsage_KeyboardRightShift; break; + case XK_Control_L: usage = kHIDUsage_KeyboardLeftGUI; break; + case XK_Control_R: usage = kHIDUsage_KeyboardRightGUI; break; + case XK_Meta_L: usage = kHIDUsage_KeyboardLeftControl; break; + case XK_Meta_R: usage = kHIDUsage_KeyboardRightControl; break; + case XK_Alt_L: usage = kHIDUsage_KeyboardLeftAlt; break; + case XK_Alt_R: usage = kHIDUsage_KeyboardRightAlt; break; + + case XK_Up: usage = kHIDUsage_KeyboardUpArrow; break; + case XK_Down: usage = kHIDUsage_KeyboardDownArrow; break; + case XK_Left: usage = kHIDUsage_KeyboardLeftArrow; break; + case XK_Right: usage = kHIDUsage_KeyboardRightArrow; break; + + case XK_Home: case XK_Begin: usage = kHIDUsage_KeyboardHome; break; + case XK_End: usage = kHIDUsage_KeyboardEnd; break; + case XK_Page_Up: usage = kHIDUsage_KeyboardPageUp; break; + case XK_Page_Down: usage = kHIDUsage_KeyboardPageDown; break; + + default: return; + } + + SendHIDEvent(IOHIDEventCreateKeyboardEvent(kCFAllocatorDefault, mach_absolute_time(), kHIDPage_KeyboardOrKeypad, usage, down, 0)); +} + +void VNCPointerNew(int buttons, int x, int y, CGPoint location, int diff, bool twas, bool tis) { + if ((diff & 0x10) != 0) + SendHIDEvent(IOHIDEventCreateKeyboardEvent(kCFAllocatorDefault, mach_absolute_time(), kHIDPage_Telephony, kHIDUsage_Tfon_Flash, (buttons & 0x10) != 0, 0)); + if ((diff & 0x04) != 0) + SendHIDEvent(IOHIDEventCreateKeyboardEvent(kCFAllocatorDefault, mach_absolute_time(), kHIDPage_Consumer, kHIDUsage_Csmr_Menu, (buttons & 0x04) != 0, 0)); + if ((diff & 0x02) != 0) + SendHIDEvent(IOHIDEventCreateKeyboardEvent(kCFAllocatorDefault, mach_absolute_time(), kHIDPage_Consumer, kHIDUsage_Csmr_Power, (buttons & 0x02) != 0, 0)); + + uint32_t handm; + uint32_t fingerm; + + if (twas == 0 && tis == 1) { + handm = kIOHIDDigitizerEventRange | kIOHIDDigitizerEventTouch | kIOHIDDigitizerEventIdentity; + fingerm = kIOHIDDigitizerEventRange | kIOHIDDigitizerEventTouch; + } else if (twas == 1 && tis == 1) { + handm = kIOHIDDigitizerEventPosition; + fingerm = kIOHIDDigitizerEventPosition; + } else if (twas == 1 && tis == 0) { + handm = kIOHIDDigitizerEventRange | kIOHIDDigitizerEventTouch | kIOHIDDigitizerEventIdentity | kIOHIDDigitizerEventPosition; + fingerm = kIOHIDDigitizerEventRange | kIOHIDDigitizerEventTouch; + } else return; + + // XXX: avoid division in VNCPointer() + // x *= ratio_; + // y *= ratio_; + + IOHIDFloat xf = (IOHIDFloat)x; + IOHIDFloat yf = (IOHIDFloat)y; + + ScreenDumpVNC *sharedInstance = [ScreenDumpVNC sharedInstance]; + + xf /= [sharedInstance width]; + yf /= [sharedInstance height]; + + + + IOHIDEventRef hand = IOHIDEventCreateDigitizerEvent(kCFAllocatorDefault, mach_absolute_time(), kIOHIDDigitizerTransducerTypeHand, 1<<22, 1, handm, 0, xf, yf, 0, 0, 0, 0, 0, 0); + IOHIDEventSetIntegerValue(hand, kIOHIDEventFieldIsBuiltIn, true); + IOHIDEventSetIntegerValue(hand, kIOHIDEventFieldDigitizerIsDisplayIntegrated, true); + + IOHIDEventRef finger = IOHIDEventCreateDigitizerFingerEvent(kCFAllocatorDefault, mach_absolute_time(), 3, 2, fingerm, xf, yf, 0, 0, 0, tis, tis, 0); + IOHIDEventAppendEvent(hand, finger); + CFRelease(finger); + + SendHIDEvent(hand); +} + +static int buttons_; + +void VNCPointer(int buttons, int x, int y, rfbClientPtr client) { + // if (ratio_ == 0) + // return; + + CGPoint location = {(CGFloat)x, (CGFloat)y}; + + // if (width_ > height_) { + // int t(x); + // x = height_ - 1 - y; + // y = t; + + // if (!iPad1_) { + // x = height_ - 1 - x; + // y = width_ - 1 - y; + // } + // } + + // x /= ratio_; + // y /= ratio_; + + // x_ = x; y_ = y; + int diff = buttons_ ^ buttons; + bool twas = (buttons_ & 0x1) != 0; + bool tis = (buttons & 0x1) != 0; + buttons_ = buttons; + + rfbDefaultPtrAddEvent(buttons, x, y, client); + + // if (Ashikase(false)) { + // AshikaseSendEvent(x, y, buttons); + // return; + // } + + return VNCPointerNew(buttons, x, y, location, diff, twas, tis); +} + +void handleVNCKeyboard(rfbBool down, rfbKeySym key, rfbClientPtr client) { + VNCKeyboard(down, key, client); +} + +void handleVNCPointer(int buttons, int x, int y, rfbClientPtr client) { + VNCPointer(buttons, x, y, client); +}