From a0f146b38d0fd6a6e7bc011198763647a08abc36 Mon Sep 17 00:00:00 2001 From: Bryan Roe Date: Fri, 11 Jan 2019 10:58:46 -0800 Subject: [PATCH] Added MacOS KVM files --- meshcore/KVM/MacOS/mac_events.c | 257 ++++++++++++ meshcore/KVM/MacOS/mac_events.h | 380 ++++++++++++++++++ meshcore/KVM/MacOS/mac_kvm.c | 691 ++++++++++++++++++++++++++++++++ meshcore/KVM/MacOS/mac_kvm.h | 36 ++ meshcore/KVM/MacOS/mac_tile.c | 507 +++++++++++++++++++++++ meshcore/KVM/MacOS/mac_tile.h | 41 ++ 6 files changed, 1912 insertions(+) create mode 100644 meshcore/KVM/MacOS/mac_events.c create mode 100644 meshcore/KVM/MacOS/mac_events.h create mode 100644 meshcore/KVM/MacOS/mac_kvm.c create mode 100644 meshcore/KVM/MacOS/mac_kvm.h create mode 100644 meshcore/KVM/MacOS/mac_tile.c create mode 100644 meshcore/KVM/MacOS/mac_tile.h diff --git a/meshcore/KVM/MacOS/mac_events.c b/meshcore/KVM/MacOS/mac_events.c new file mode 100644 index 0000000..204fec4 --- /dev/null +++ b/meshcore/KVM/MacOS/mac_events.c @@ -0,0 +1,257 @@ +#include "mac_events.h" +#include +#include +#include + +static const int g_keymapLen = 114; // Modify this when you change anything in g_keymap. +static int g_capsLock = 0; +static int g_lMouseDown = 0; +static int g_rMouseDown = 0; + +static struct keymap_t g_keymap[] = { + { kVK_Space, VK_SPACE }, + { kVK_CapsLock, VK_CAPITAL }, + { kVK_ANSI_Q, VK_Q }, + { kVK_ANSI_W, VK_W }, + { kVK_ANSI_E, VK_E }, + { kVK_ANSI_R, VK_R }, + { kVK_ANSI_T, VK_T }, + { kVK_ANSI_Y, VK_Y }, + { kVK_ANSI_U, VK_U }, + { kVK_ANSI_I, VK_I }, + { kVK_ANSI_O, VK_O }, + { kVK_ANSI_P, VK_P }, + { kVK_ANSI_A, VK_A }, + { kVK_ANSI_S, VK_S }, + { kVK_ANSI_D, VK_D }, + { kVK_ANSI_F, VK_F }, + { kVK_ANSI_G, VK_G }, + { kVK_ANSI_H, VK_H }, + { kVK_ANSI_J, VK_J }, + { kVK_ANSI_K, VK_K }, + { kVK_ANSI_L, VK_L }, + { kVK_ANSI_Z, VK_Z }, + { kVK_ANSI_X, VK_X }, + { kVK_ANSI_C, VK_C }, + { kVK_ANSI_V, VK_V }, + { kVK_ANSI_B, VK_B }, + { kVK_ANSI_N, VK_N }, + { kVK_ANSI_M, VK_M }, + { kVK_ANSI_1, VK_1 }, + { kVK_ANSI_2, VK_2 }, + { kVK_ANSI_3, VK_3 }, + { kVK_ANSI_4, VK_4 }, + { kVK_ANSI_5, VK_5 }, + { kVK_ANSI_6, VK_6 }, + { kVK_ANSI_7, VK_7 }, + { kVK_ANSI_8, VK_8 }, + { kVK_ANSI_9, VK_9 }, + { kVK_ANSI_0, VK_0 }, + { kVK_Delete, VK_BACK }, + { kVK_Tab, VK_TAB }, + { kVK_ANSI_KeypadClear, VK_CLEAR }, + { kVK_Return, VK_RETURN }, + { kVK_Help, VK_PAUSE }, + { kVK_Escape, VK_ESCAPE }, + { kVK_ForwardDelete, VK_DELETE }, + { kVK_Home, VK_HOME }, + { kVK_LeftArrow, VK_LEFT }, + { kVK_UpArrow, VK_UP }, + { kVK_RightArrow, VK_RIGHT }, + { kVK_DownArrow, VK_DOWN }, + { kVK_PageUp, VK_PRIOR }, + { kVK_PageDown, VK_NEXT }, + { kVK_End, VK_END }, + { kVK_Help, VK_SELECT }, + { kVK_Help, VK_SNAPSHOT }, + { kVK_Help, VK_EXECUTE }, + { kVK_Help, VK_INSERT }, + { kVK_Help, VK_HELP }, + { kVK_Escape, VK_CANCEL }, + { kVK_F1, VK_F1 }, + { kVK_F2, VK_F2 }, + { kVK_F3, VK_F3 }, + { kVK_F4, VK_F4 }, + { kVK_F5, VK_F5 }, + { kVK_F6, VK_F6 }, + { kVK_F7, VK_F7 }, + { kVK_F8, VK_F8 }, + { kVK_F9, VK_F9 }, + { kVK_F10, VK_F10 }, + { kVK_F11, VK_F11 }, + { kVK_F12, VK_F12 }, + { kVK_F13, VK_F13 }, + { kVK_F14, VK_F14 }, + { kVK_F15, VK_F15 }, + { kVK_F16, VK_F16 }, + { kVK_F17, VK_F17 }, + { kVK_F18, VK_F18 }, + { kVK_F19, VK_F19 }, + { kVK_F20, VK_F20 }, + { kVK_Home, VK_HOME }, + { kVK_ANSI_KeypadMultiply, VK_MULTIPLY }, + { kVK_ANSI_Equal, VK_ADD }, + { kVK_ANSI_Comma, VK_SEPARATOR }, + { kVK_ANSI_Minus, VK_SUBTRACT }, + { kVK_ANSI_KeypadDecimal, VK_DECIMAL }, + { kVK_ANSI_KeypadDivide, VK_DIVIDE }, + { kVK_ANSI_Keypad0, VK_NUMPAD0 }, + { kVK_ANSI_Keypad1, VK_NUMPAD1 }, + { kVK_ANSI_Keypad2, VK_NUMPAD2 }, + { kVK_ANSI_Keypad3, VK_NUMPAD3 }, + { kVK_ANSI_Keypad4, VK_NUMPAD4 }, + { kVK_ANSI_Keypad5, VK_NUMPAD5 }, + { kVK_ANSI_Keypad6, VK_NUMPAD6 }, + { kVK_ANSI_Keypad7, VK_NUMPAD7 }, + { kVK_ANSI_Keypad8, VK_NUMPAD8 }, + { kVK_ANSI_Keypad9, VK_NUMPAD9 }, + { kVK_Shift, VK_SHIFT }, + { kVK_Control, VK_CONTROL }, + { kVK_Option, VK_MENU }, + { kVK_Command, VK_RWIN }, + { kVK_Command, VK_LWIN }, + { kVK_Option, VK_APPS }, + { kVK_JIS_Kana, VK_KANA }, + { kVK_ANSI_Semicolon, VK_OEM_1 }, + { kVK_ANSI_Equal, VK_OEM_PLUS }, + { kVK_ANSI_Comma, VK_OEM_COMMA }, + { kVK_ANSI_Minus, VK_OEM_MINUS }, + { kVK_ANSI_Period, VK_OEM_PERIOD }, + { kVK_ANSI_Slash, VK_OEM_2 }, + { kVK_ANSI_Grave, VK_OEM_3 }, + { kVK_ANSI_LeftBracket, VK_OEM_4 }, + { kVK_ANSI_Backslash, VK_OEM_5 }, + { kVK_ANSI_RightBracket, VK_OEM_6 }, + { kVK_ANSI_Quote, VK_OEM_7 } +}; + +char* getCurrentSession() { + SCDynamicStoreRef store; + CFStringRef name; + uid_t uid; + char *buf; + Boolean ok; + + buf = (char *)malloc (BUFSIZ); + store = SCDynamicStoreCreate(NULL, CFSTR("GetConsoleUser"), NULL, NULL); + assert(store != NULL); + name = SCDynamicStoreCopyConsoleUser(store, &uid, NULL); + CFRelease(store); + + if (name != NULL) { + ok = CFStringGetCString(name, buf, BUFSIZ, kCFStringEncodingUTF8); + assert(ok == true); + CFRelease(name); + } else { + strcpy(buf, ""); + } + + return buf; +} + +void MouseAction(double absX, double absY, int button, short wheel) +{ + CGPoint curPos; + CGEventRef e; + CGEventType event; + CGEventSourceRef source; + + curPos.x = absX; + curPos.y = absY; + + source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); + + + if (g_lMouseDown || g_rMouseDown) { + event = g_lMouseDown ? kCGEventLeftMouseDragged : kCGEventRightMouseDragged; + e = CGEventCreateMouseEvent(source, event, curPos, 1); + CGEventPost(kCGHIDEventTap, e); + CGEventPost(kCGSessionEventTap, e); + CFRelease(e); + } + else { + CGWarpMouseCursorPosition (curPos); + } + + if (button != 0) { + + switch (button) { + case MOUSEEVENTF_LEFTDOWN: + event = kCGEventLeftMouseDown; + g_lMouseDown = 1; + break; + case MOUSEEVENTF_RIGHTDOWN: + g_rMouseDown = 1; + event = kCGEventRightMouseDown; + break; + case MOUSEEVENTF_LEFTUP: + g_lMouseDown = 0; + event = kCGEventLeftMouseUp; + break; + case MOUSEEVENTF_RIGHTUP: + g_rMouseDown = 0; + event = kCGEventRightMouseUp; + break; + default: + break; + } + + + /* + if (!strcmp(getCurrentSession(), "")) + { + // This call is deprecated in OSX 10.6 + CGPostMouseEvent(curPos, TRUE, 3, (event == kCGEventLeftMouseDown) ? TRUE : FALSE, (event == kCGEventRightMouseDown) ? TRUE : FALSE, FALSE); // mouse down + } + else + { + */ + e = CGEventCreateMouseEvent(source, event, curPos, 1); + CGEventPost(kCGHIDEventTap, e); + CFRelease(e); + /* + } + */ + } + else if (wheel != 0) + { + e = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitPixel, 1, wheel); + CGEventPost(kCGHIDEventTap, e); + CFRelease(e); + } + if (source != NULL) CFRelease(source); +} + +void KeyAction(unsigned char vk, int up) { + int i; + CGKeyCode keycode; + CGEventSourceRef source; + + source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); + for (i = 0 ; i < g_keymapLen; i++) { + if (g_keymap[i].vk == vk) { + keycode = g_keymap[i].keycode; + break; + } + } + + if (i == g_keymapLen) { return; } + if (vk == VK_CAPITAL && up) { g_capsLock = g_capsLock ? 0 : 1; } + + /* + if (!strcmp(getCurrentSession(), "")) { + // This call is deprecated in OSX 10.6 + CGPostKeyboardEvent(0, keycode, !up); + } + else + { + */ + CGEventRef key = CGEventCreateKeyboardEvent(source, keycode, !up); + if (g_capsLock) { CGEventSetFlags(key, kCGEventFlagMaskAlphaShift); } + CGEventPost(kCGHIDEventTap, key); + CFRelease(key); + /* + } + */ + if (source != NULL) CFRelease(source); +} diff --git a/meshcore/KVM/MacOS/mac_events.h b/meshcore/KVM/MacOS/mac_events.h new file mode 100644 index 0000000..d5320c4 --- /dev/null +++ b/meshcore/KVM/MacOS/mac_events.h @@ -0,0 +1,380 @@ +/* + * linux_events.h + * + * Created on: Jul 8, 2011 + * Author: Intel + */ + +#ifndef LINUX_EVENTS_H_ +#define LINUX_EVENTS_H_ + +#include +#include +#include +#include + +enum MOUSE_EVENTS { + MOUSEEVENTF_LEFTDOWN = 0x0002, + MOUSEEVENTF_RIGHTDOWN = 0x0008, + MOUSEEVENTF_MIDDLEDOWN = 0x0020, + MOUSEEVENTF_LEFTUP = 0x0004, + MOUSEEVENTF_RIGHTUP = 0x0010, + MOUSEEVENTF_MIDDLEUP = 0x0040 +}; + +// VK_LBUTTON (01) Left mouse button +#define VK_LBUTTON 0x01 +// VK_RBUTTON (02) Right mouse button +#define VK_RBUTTON 0x02 +// VK_CANCEL (03) Control-break processing +#define VK_CANCEL 0x03 +// VK_MBUTTON (04) Middle mouse button (three-button mouse) +#define VK_MBUTTON 0x04 +// VK_XBUTTON1 (05) +#define VK_XBUTTON1 0x05 +// VK_XBUTTON2 (06) +#define VK_XBUTTON2 0x06 + // VK_BACK (08) BACKSPACE key +#define VK_BACK 0x08 + // VK_TAB (09) TAB key +#define VK_TAB 0x09 + // VK_CLEAR (0C) CLEAR key +#define VK_CLEAR 0x0C + // VK_RETURN (0D) +#define VK_RETURN 0x0D + // VK_SHIFT (10) SHIFT key +#define VK_SHIFT 0x10 + // VK_CONTROL (11) CTRL key +#define VK_CONTROL 0x11 + // VK_MENU (12) ALT key +#define VK_MENU 0x12 + // VK_PAUSE (13) PAUSE key +#define VK_PAUSE 0x13 + // VK_CAPITAL (14) CAPS LOCK key +#define VK_CAPITAL 0x14 + // VK_KANA (15) Input Method Editor (IME) Kana mode +#define VK_KANA 0x15 + // VK_HANGUEL (15) IME Hanguel mode (maintained for compatibility; use VK_HANGUL) + // VK_HANGUL (15) IME Hangul mode +#define VK_HANGUL 0x15 + // VK_JUNJA (17) IME Junja mode +#define VK_JUNJA 0x17 + // VK_FINAL (18) IME final mode +#define VK_FINAL 0x18 + // VK_HANJA (19) IME Hanja mode +#define VK_HANJA 0x19 + // VK_KANJI (19) IME Kanji mode +#define VK_KANJI 0x19 + // VK_ESCAPE (1B) ESC key +#define VK_ESCAPE 0x1B + // VK_CONVERT (1C) IME convert +#define VK_CONVERT 0x1C + // VK_NONCONVERT (1D) IME nonconvert +#define VK_NONCONVERT 0x1D + // VK_ACCEPT (1E) IME accept +#define VK_ACCEPT 0x1E + // VK_MODECHANGE (1F) IME mode change request +#define VK_MODECHANGE 0x1F + // VK_SPACE (20) SPACEBAR +#define VK_SPACE 0x20 + // VK_PRIOR (21) PAGE UP key +#define VK_PRIOR 0x21 + // VK_NEXT (22) PAGE DOWN key +#define VK_NEXT 0x22 + // VK_END (23) END key +#define VK_END 0x23 + // VK_HOME (24) HOME key +#define VK_HOME 0x24 + // VK_LEFT (25) LEFT ARROW key +#define VK_LEFT 0x25 + // VK_UP (26) UP ARROW key +#define VK_UP 0x26 + // VK_RIGHT (27) RIGHT ARROW key +#define VK_RIGHT 0x27 + // VK_DOWN (28) DOWN ARROW key +#define VK_DOWN 0x28 + // VK_SELECT (29) SELECT key +#define VK_SELECT 0x29 + // VK_PRINT (2A) PRINT key +#define VK_PRINT 0x2A + // VK_EXECUTE (2B) EXECUTE key +#define VK_EXECUTE 0x2B + // VK_SNAPSHOT (2C) PRINT SCREEN key +#define VK_SNAPSHOT 0x2C + // VK_INSERT (2D) INS key +#define VK_INSERT 0x2D + // VK_DELETE (2E) DEL key +#define VK_DELETE 0x2E + // VK_HELP (2F) HELP key +#define VK_HELP 0x2F + // (30) 0 key +#define VK_0 0x30 + // (31) 1 key +#define VK_1 0x31 + // (32) 2 key +#define VK_2 0x32 + // (33) 3 key +#define VK_3 0x33 + // (34) 4 key +#define VK_4 0x34 + // (35) 5 key; +#define VK_5 0x35 + // (36) 6 key +#define VK_6 0x36 + // (37) 7 key +#define VK_7 0x37 + // (38) 8 key +#define VK_8 0x38 + // (39) 9 key +#define VK_9 0x39 + // (41) A key +#define VK_A 0x41 + // (42) B key +#define VK_B 0x42 + // (43) C key +#define VK_C 0x43 + // (44) D key +#define VK_D 0x44 + // (45) E key +#define VK_E 0x45 + // (46) F key +#define VK_F 0x46 + // (47) G key +#define VK_G 0x47 + // (48) H key +#define VK_H 0x48 + // (49) I key +#define VK_I 0x49 + // (4A) J key +#define VK_J 0x4A + // (4B) K key +#define VK_K 0x4B + // (4C) L key +#define VK_L 0x4C + // (4D) M key +#define VK_M 0x4D + // (4E) N key +#define VK_N 0x4E + // (4F) O key +#define VK_O 0x4F + // (50) P key +#define VK_P 0x50 + // (51) Q key +#define VK_Q 0x51 + // (52) R key +#define VK_R 0x52 + // (53) S key +#define VK_S 0x53 + // (54) T key +#define VK_T 0x54 + // (55) U key +#define VK_U 0x55 + // (56) V key +#define VK_V 0x56 + // (57) W key +#define VK_W 0x57 + // (58) X key +#define VK_X 0x58 + // (59) Y key +#define VK_Y 0x59 + // (5A) Z key +#define VK_Z 0x5A + // VK_LWIN (5B) Left Windows key (Microsoft Natural keyboard) +#define VK_LWIN 0x5B + // VK_RWIN (5C) Right Windows key (Natural keyboard) +#define VK_RWIN 0x5C + // VK_APPS (5D) Applications key (Natural keyboard) +#define VK_APPS 0x5D + // VK_SLEEP (5F) Computer Sleep key +#define VK_SLEEP 0x5F + // VK_NUMPAD0 (60) Numeric keypad 0 key +#define VK_NUMPAD0 0x60 + // VK_NUMPAD1 (61) Numeric keypad 1 key +#define VK_NUMPAD1 0x61 + // VK_NUMPAD2 (62) Numeric keypad 2 key +#define VK_NUMPAD2 0x62 + // VK_NUMPAD3 (63) Numeric keypad 3 key +#define VK_NUMPAD3 0x63 + // VK_NUMPAD4 (64) Numeric keypad 4 key +#define VK_NUMPAD4 0x64 + // VK_NUMPAD5 (65) Numeric keypad 5 key +#define VK_NUMPAD5 0x65 + // VK_NUMPAD6 (66) Numeric keypad 6 key +#define VK_NUMPAD6 0x66 + // VK_NUMPAD7 (67) Numeric keypad 7 key +#define VK_NUMPAD7 0x67 + // VK_NUMPAD8 (68) Numeric keypad 8 key +#define VK_NUMPAD8 0x68 + // VK_NUMPAD9 (69) Numeric keypad 9 key +#define VK_NUMPAD9 0x69 + // VK_MULTIPLY (6A) Multiply key +#define VK_MULTIPLY 0x6A + // VK_ADD (6B) Add key +#define VK_ADD 0x6B + // VK_SEPARATOR (6C) Separator key +#define VK_SEPARATOR 0x6C + // VK_SUBTRACT (6D) Subtract key +#define VK_SUBTRACT 0x6D + // VK_DECIMAL (6E) Decimal key +#define VK_DECIMAL 0x6E + // VK_DIVIDE (6F) Divide key +#define VK_DIVIDE 0x6F + // VK_F1 (70) F1 key +#define VK_F1 0x70 + // VK_F2 (71) F2 key +#define VK_F2 0x71 + // VK_F3 (72) F3 key +#define VK_F3 0x72 + // VK_F4 (73) F4 key +#define VK_F4 0x73 + // VK_F5 (74) F5 key +#define VK_F5 0x74 + // VK_F6 (75) F6 key +#define VK_F6 0x75 + // VK_F7 (76) F7 key +#define VK_F7 0x76 + // VK_F8 (77) F8 key +#define VK_F8 0x77 + // VK_F9 (78) F9 key +#define VK_F9 0x78 + // VK_F10 (79) F10 key +#define VK_F10 0x79 + // VK_F11 (7A) F11 key +#define VK_F11 0x7A + // VK_F12 (7B) F12 key +#define VK_F12 0x7B + // VK_F13 (7C) F13 key +#define VK_F13 0x7C + // VK_F14 (7D) F14 key +#define VK_F14 0x7D + // VK_F15 (7E) F15 key +#define VK_F15 0x7E + // VK_F16 (7F) F16 key +#define VK_F16 0x7F + // VK_F17 (80H) F17 key +#define VK_F17 0x80 + // VK_F18 (81H) F18 key +#define VK_F18 0x81 + // VK_F19 (82H) F19 key +#define VK_F19 0x82 + // VK_F20 (83H) F20 key +#define VK_F20 0x83 + // VK_F21 (84H) F21 key +#define VK_F21 0x84 + // VK_F22 (85H) F22 key +#define VK_F22 0x85 + // VK_F23 (86H) F23 key +#define VK_F23 0x86 + // VK_F24 (87H) F24 key +#define VK_F24 0x87 + // VK_NUMLOCK (90) NUM LOCK key +#define VK_NUMLOCK 0x90 + // VK_SCROLL (91) SCROLL LOCK key +#define VK_SCROLL 0x91 + // VK_LSHIFT (A0) Left SHIFT key +#define VK_LSHIFT 0xA0 + // VK_RSHIFT (A1) Right SHIFT key +#define VK_RSHIFT 0xA1 + // VK_LCONTROL (A2) Left CONTROL key +#define VK_LCONTROL 0xA2 + // VK_RCONTROL (A3) Right CONTROL key +#define VK_RCONTROL 0xA3 + // VK_LMENU (A4) Left MENU key +#define VK_LMENU 0xA4 + // VK_RMENU (A5) Right MENU key +#define VK_RMENU 0xA5 + // VK_BROWSER_BACK (A6) Windows 2000/XP: Browser Back key +#define VK_BROWSER_BACK 0xA6 + // VK_BROWSER_FORWARD (A7) Windows 2000/XP: Browser Forward key +#define VK_BROWSER_FORWARD 0xA7 + // VK_BROWSER_REFRESH (A8) Windows 2000/XP: Browser Refresh key +#define VK_BROWSER_REFRESH 0xA8 + // VK_BROWSER_STOP (A9) Windows 2000/XP: Browser Stop key +#define VK_BROWSER_STOP 0xA9 + // VK_BROWSER_SEARCH (AA) Windows 2000/XP: Browser Search key +#define VK_BROWSER_SEARCH 0xAA + // VK_BROWSER_FAVORITES (AB) Windows 2000/XP: Browser Favorites key +#define VK_BROWSER_FAVORITES 0xAB + // VK_BROWSER_HOME (AC) Windows 2000/XP: Browser Start and Home key +#define VK_BROWSER_HOME 0xAC + // VK_VOLUME_MUTE (AD) Windows 2000/XP: Volume Mute key +#define VK_VOLUME_MUTE 0xAD + // VK_VOLUME_DOWN (AE) Windows 2000/XP: Volume Down key +#define VK_VOLUME_DOWN 0xAE + // VK_VOLUME_UP (AF) Windows 2000/XP: Volume Up key +#define VK_VOLUME_UP 0xAF + // VK_MEDIA_NEXT_TRACK (B0) Windows 2000/XP: Next Track key +#define VK_MEDIA_NEXT_TRACK 0xB0 + // VK_MEDIA_PREV_TRACK (B1) Windows 2000/XP: Previous Track key +#define VK_MEDIA_PREV_TRACK 0xB1 + // VK_MEDIA_STOP (B2) Windows 2000/XP: Stop Media key +#define VK_MEDIA_STOP 0xB2 + // VK_MEDIA_PLAY_PAUSE (B3) Windows 2000/XP: Play/Pause Media key +#define VK_MEDIA_PLAY_PAUSE 0xB3 + // VK_LAUNCH_MAIL (B4) Windows 2000/XP: Start Mail key +#define VK_MEDIA_LAUNCH_MAIL 0xB4 + // VK_LAUNCH_MEDIA_SELECT (B5) Windows 2000/XP: Select Media key +#define VK_MEDIA_LAUNCH_MEDIA_SELECT 0xB5 + // VK_LAUNCH_APP1 (B6) Windows 2000/XP: Start Application 1 key +#define VK_MEDIA_LAUNCH_APP1 0xB6 + // VK_LAUNCH_APP2 (B7) Windows 2000/XP: Start Application 2 key +#define VK_MEDIA_LAUNCH_APP2 0xB7 + // VK_OEM_1 (BA) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ';:' key +#define VK_OEM_1 0xBA + // VK_OEM_PLUS (BB) Windows 2000/XP: For any country/region, the '+' key +#define VK_OEM_PLUS 0xBB + // VK_OEM_COMMA (BC) Windows 2000/XP: For any country/region, the ',' key +#define VK_OEM_COMMA 0xBC + // VK_OEM_MINUS (BD) Windows 2000/XP: For any country/region, the '-' key +#define VK_OEM_MINUS 0xBD + // VK_OEM_PERIOD (BE) Windows 2000/XP: For any country/region, the '.' key +#define VK_OEM_PERIOD 0xBE + // VK_OEM_2 (BF) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '/?' key +#define VK_OEM_2 0xBF + // VK_OEM_3 (C0) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '`~' key +#define VK_OEM_3 0xC0 + // VK_OEM_4 (DB) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '[{' key +#define VK_OEM_4 0xDB + // VK_OEM_5 (DC) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '\|' key +#define VK_OEM_5 0xDC + // VK_OEM_6 (DD) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ']}' key +#define VK_OEM_6 0xDD + // VK_OEM_7 (DE) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key +#define VK_OEM_7 0xDE + // VK_OEM_8 (DF) Used for miscellaneous characters; it can vary by keyboard. +#define VK_OEM_8 0xDF + // VK_OEM_102 (E2) Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard +#define VK_OEM_102 0xE2 + // VK_PROCESSKEY (E5) Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key +#define VK_PROCESSKEY 0xE5 + // VK_PACKET (E7) Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT,SendInput, WM_KEYDOWN, and WM_KEYUP +#define VK_PACKET 0xE7 + // VK_ATTN (F6) Attn key +#define VK_ATTN 0xF6 + // VK_CRSEL (F7) CrSel key +#define VK_CRSEL 0xF7 + // VK_EXSEL (F8) ExSel key +#define VK_EXSEL 0xF8 + // VK_EREOF (F9) Erase EOF key +#define VK_EREOF 0xF9 + // VK_PLAY (FA) Play key +#define VK_PLAY 0xFA + // VK_ZOOM (FB) Zoom key +#define VK_ZOOM 0xFB + // VK_NONAME (FC) Reserved for future use +#define VK_NONAME 0xFC + // VK_PA1 (FD) PA1 key +#define VK_PA1 0xFD + // VK_OEM_CLEAR (FE) Clear key +#define VK_OEM_CLEAR 0xFE +#define VK_UNKNOWN 0 + +struct keymap_t { + unsigned int keycode; + unsigned char vk; +}; + +extern void MouseAction(double absX, double absY, int button, short wheel); +extern void KeyAction(unsigned char vk, int up); + +#endif /* LINUX_EVENTS_H_ */ diff --git a/meshcore/KVM/MacOS/mac_kvm.c b/meshcore/KVM/MacOS/mac_kvm.c new file mode 100644 index 0000000..78f960b --- /dev/null +++ b/meshcore/KVM/MacOS/mac_kvm.c @@ -0,0 +1,691 @@ +/* +Copyright 2010 - 2018 Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "mac_kvm.h" +#include "../../meshdefines.h" +#include "../../meshinfo.h" +#include "../../../microstack/ILibParsers.h" +#include "../../../microstack/ILibAsyncSocket.h" +#include "../../../microstack/ILibAsyncServerSocket.h" +#include "../../../microstack/ILibProcessPipe.h" +#include +#include +#include +#include + +int KVM_Listener_FD = -1; +#define KVM_Listener_Path "/usr/local/mesh_services/mesh2/kvm" + +int KVM_AGENT_FD = -1; +int KVM_SEND(char *buffer, int bufferLen) +{ + int retVal = -1; + retVal = write(KVM_AGENT_FD == -1 ? STDOUT_FILENO : KVM_AGENT_FD, buffer, bufferLen); + if (KVM_AGENT_FD == -1) { fsync(STDOUT_FILENO); } + else + { + if (retVal < 0) + { + char tmp[255]; + int tmpLen = sprintf_s(tmp, sizeof(tmp), "Write Error: %d on %d\n", errno, KVM_AGENT_FD); + write(STDOUT_FILENO, tmp, tmpLen); + fsync(STDOUT_FILENO); + } + } + return(retVal); +} + + + +CGDirectDisplayID SCREEN_NUM = 0; +int SH_HANDLE = 0; +int SCREEN_WIDTH = 0; +int SCREEN_HEIGHT = 0; +int SCREEN_DEPTH = 0; +int TILE_WIDTH = 0; +int TILE_HEIGHT = 0; +int TILE_WIDTH_COUNT = 0; +int TILE_HEIGHT_COUNT = 0; +int COMPRESSION_RATIO = 0; +int FRAME_RATE_TIMER = 0; +struct tileInfo_t **g_tileInfo = NULL; +int g_remotepause = 0; +int g_pause = 0; +int g_shutdown = 0; +int g_resetipc = 0; +int kvm_clientProcessId = 0; +int g_restartcount = 0; +int g_totalRestartCount = 0; +int restartKvm = 0; +extern void* tilebuffer; +pid_t g_slavekvm = 0; +pthread_t kvmthread = (pthread_t)NULL; +ILibProcessPipe_Process gChildProcess; + +//int logenabled = 1; +//FILE *logfile = NULL; +//#define MASTERLOGFILE "/dev/null" +//#define SLAVELOGFILE "/dev/null" +//#define LOGFILE "/dev/null" + + +#define KvmDebugLog(...) +//#define KvmDebugLog(...) printf(__VA_ARGS__); //if (logfile != NULL) fprintf(logfile, __VA_ARGS__); +//#define KvmDebugLog(x) if (logenabled) printf(x); +//#define KvmDebugLog(x) if (logenabled) fprintf(logfile, "Writing from slave in kvm_send_resolution\n"); + +void senddebug(int val) +{ + char buffer[8]; + + ((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_DEBUG); // Write the type + ((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)8); // Write the size + ((int*)buffer)[1] = val; + + KVM_SEND(buffer, 8); +} + + + +void kvm_send_resolution() +{ + char buffer[8]; + + ((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_SCREEN); // Write the type + ((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)8); // Write the size + ((unsigned short*)buffer)[2] = (unsigned short)htons((unsigned short)SCREEN_WIDTH); // X position + ((unsigned short*)buffer)[3] = (unsigned short)htons((unsigned short)SCREEN_HEIGHT); // Y position + + + // Write the reply to the pipe. + KVM_SEND(buffer, 8); +} + +#define BUFSIZE 65535 + +int kvm_init() +{ + int old_height_count = TILE_HEIGHT_COUNT; + + SCREEN_NUM = CGMainDisplayID(); + SCREEN_HEIGHT = CGDisplayPixelsHigh(SCREEN_NUM); + SCREEN_WIDTH = CGDisplayPixelsWide(SCREEN_NUM); + + // Some magic numbers. + TILE_WIDTH = 32; + TILE_HEIGHT = 32; + COMPRESSION_RATIO = 50; + FRAME_RATE_TIMER = 100; + + TILE_HEIGHT_COUNT = SCREEN_HEIGHT / TILE_HEIGHT; + TILE_WIDTH_COUNT = SCREEN_WIDTH / TILE_WIDTH; + if (SCREEN_WIDTH % TILE_WIDTH) { TILE_WIDTH_COUNT++; } + if (SCREEN_HEIGHT % TILE_HEIGHT) { TILE_HEIGHT_COUNT++; } + + kvm_send_resolution(); + + reset_tile_info(old_height_count); + + return 0; +} + +// void CheckDesktopSwitch(int checkres) { return; } + +int kvm_server_inputdata(char* block, int blocklen) +{ + unsigned short type, size; + //CheckDesktopSwitch(0); + + //senddebug(100+blocklen); + + // Decode the block header + if (blocklen < 4) return 0; + type = ntohs(((unsigned short*)(block))[0]); + size = ntohs(((unsigned short*)(block))[1]); + + if (size > blocklen) return 0; + + switch (type) + { + case MNG_KVM_KEY: // Key + { + if (size != 6 || KVM_AGENT_FD != -1) { break; } + KeyAction(block[5], block[4]); + break; + } + case MNG_KVM_MOUSE: // Mouse + { + int x, y; + short w = 0; + if (KVM_AGENT_FD != -1) { break; } + if (size == 10 || size == 12) + { + x = ((int)ntohs(((unsigned short*)(block))[3])); + y = ((int)ntohs(((unsigned short*)(block))[4])); + if (size == 12) w = ((short)ntohs(((short*)(block))[5])); + //printf("x:%d, y:%d, b:%d, w:%d\n", x, y, block[5], w); + MouseAction(x, y, block[5], w); + } + break; + } + case MNG_KVM_COMPRESSION: // Compression + { + if (size != 6) break; + set_tile_compression((int)block[4], (int)block[5]); + COMPRESSION_RATIO = 100; + break; + } + case MNG_KVM_REFRESH: // Refresh + { + int row, col; + if (size != 4) break; + if (g_tileInfo == NULL) { + if ((g_tileInfo = (struct tileInfo_t **) malloc(TILE_HEIGHT_COUNT * sizeof(struct tileInfo_t *))) == NULL) ILIBCRITICALEXIT(254); + for (row = 0; row < TILE_HEIGHT_COUNT; row++) { + if ((g_tileInfo[row] = (struct tileInfo_t *) malloc(TILE_WIDTH_COUNT * sizeof(struct tileInfo_t))) == NULL) ILIBCRITICALEXIT(254); + } + } + for (row = 0; row < TILE_HEIGHT_COUNT; row++) { + for (col = 0; col < TILE_WIDTH_COUNT; col++) { + g_tileInfo[row][col].crc = 0xFF; + g_tileInfo[row][col].flag = 0; + } + } + break; + } + case MNG_KVM_PAUSE: // Pause + { + if (size != 5) break; + g_remotepause = block[4]; + break; + } + case MNG_KVM_FRAME_RATE_TIMER: + { + //int fr = ((int)ntohs(((unsigned short*)(block))[2])); + //if (fr > 20 && fr < 2000) FRAME_RATE_TIMER = fr; + break; + } + } + + return size; +} + + +int kvm_relay_feeddata(char* buf, int len) +{ + ILibProcessPipe_Process_WriteStdIn(gChildProcess, buf, len, ILibTransport_MemoryOwnership_USER); + return(len); +} + +// Set the KVM pause state +void kvm_pause(int pause) +{ + g_pause = pause; +} + + +void* kvm_mainloopinput(void* param) +{ + int ptr = 0; + int ptr2 = 0; + int len = 0; + char* pchRequest2[30000]; + int cbBytesRead = 0; + + char tmp[255]; + int tmpLen; + + if (KVM_AGENT_FD == -1) + { + int flags; + flags = fcntl(STDIN_FILENO, F_GETFL, 0); + if (fcntl(STDIN_FILENO, F_SETFL, (O_NONBLOCK | flags) ^ O_NONBLOCK) == -1) { senddebug(-999); } + } + + while (!g_shutdown) + { + if (KVM_AGENT_FD != -1) + { + tmpLen = sprintf_s(tmp, sizeof(tmp), "About to read from IPC Socket\n"); + write(STDOUT_FILENO, tmp, tmpLen); + fsync(STDOUT_FILENO); + } + + KvmDebugLog("Reading from master in kvm_mainloopinput\n"); + cbBytesRead = read(KVM_AGENT_FD == -1 ? STDIN_FILENO: KVM_AGENT_FD, pchRequest2 + len, 30000 - len); + KvmDebugLog("Read %d bytes from master in kvm_mainloopinput\n", cbBytesRead); + + if (KVM_AGENT_FD != -1) + { + tmpLen = sprintf_s(tmp, sizeof(tmp), "Read %d bytes from IPC-xx-Socket\n", cbBytesRead); + write(STDOUT_FILENO, tmp, tmpLen); + fsync(STDOUT_FILENO); + } + + if (cbBytesRead == -1 || cbBytesRead == 0) + { + /*ILIBMESSAGE("KVMBREAK-K1\r\n"); g_shutdown = 1; printf("shutdown\n");*/ + if (KVM_AGENT_FD == -1) + { + g_shutdown = 1; + } + else + { + g_resetipc = 1; + } + break; + } + len += cbBytesRead; + ptr2 = 0; + + if (KVM_AGENT_FD != -1) + { + tmpLen = sprintf_s(tmp, sizeof(tmp), "enter while\n"); + write(STDOUT_FILENO, tmp, tmpLen); + fsync(STDOUT_FILENO); + } + while ((ptr2 = kvm_server_inputdata((char*)pchRequest2 + ptr, cbBytesRead - ptr)) != 0) { ptr += ptr2; } + + if (KVM_AGENT_FD != -1) + { + tmpLen = sprintf_s(tmp, sizeof(tmp), "exited while\n"); + write(STDOUT_FILENO, tmp, tmpLen); + fsync(STDOUT_FILENO); + } + + if (ptr == len) { len = 0; ptr = 0; } + // TODO: else move the reminder. + } + + return 0; +} +void ExitSink(int s) +{ + UNREFERENCED_PARAMETER(s); + + signal(SIGTERM, SIG_IGN); + + if (KVM_Listener_FD > 0) + { + write(STDOUT_FILENO, "EXITING\n", 8); + fsync(STDOUT_FILENO); + close(KVM_Listener_FD); + } + g_shutdown = 1; +} +void* kvm_server_mainloop(void* param) +{ + CGDirectDisplayID displays[10]; + int x, y, height, width, r, c = 0; + long long desktopsize = 0; + long long tilesize = 0; + long long prev_timestamp = 0; + long long cur_timestamp = 0; + long long time_diff = 50; + struct timeb tp; + void *desktop = NULL; + void *buf = NULL; + int screen_height, screen_width, screen_num; + int written = 0; + struct sockaddr_un serveraddr; + + if (param == NULL) + { + // This is doing I/O via StdIn/StdOut + + int flags; + flags = fcntl(STDOUT_FILENO, F_GETFL, 0); + if (fcntl(STDOUT_FILENO, F_SETFL, (O_NONBLOCK | flags) ^ O_NONBLOCK) == -1) {} + } + else + { + // this is doing I/O via a Unix Domain Socket + if ((KVM_Listener_FD = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + { + char tmp[255]; + int tmplen = sprintf_s(tmp, sizeof(tmp), "ERROR CREATING DOMAIN SOCKET: %d\n", errno); + // Error creating domain socket + written = write(STDOUT_FILENO, tmp, tmplen); + fsync(STDOUT_FILENO); + return(NULL); + } + + int flags; + flags = fcntl(KVM_Listener_FD, F_GETFL, 0); + if (fcntl(KVM_Listener_FD, F_SETFL, (O_NONBLOCK | flags) ^ O_NONBLOCK) == -1) { } + + written = write(STDOUT_FILENO, "Set FCNTL2\n", 11); + fsync(STDOUT_FILENO); + + memset(&serveraddr, 0, sizeof(serveraddr)); + serveraddr.sun_family = AF_UNIX; + strcpy(serveraddr.sun_path, KVM_Listener_Path); + remove(KVM_Listener_Path); + if (bind(KVM_Listener_FD, (struct sockaddr *)&serveraddr, SUN_LEN(&serveraddr)) < 0) + { + char tmp[255]; + int tmplen = sprintf_s(tmp, sizeof(tmp), "BIND ERROR on DOMAIN SOCKET: %d\n", errno); + // Error creating domain socket + written = write(STDOUT_FILENO, tmp, tmplen); + fsync(STDOUT_FILENO); + return(NULL); + } + + if (listen(KVM_Listener_FD, 1) < 0) + { + written = write(STDOUT_FILENO, "LISTEN ERROR ON DOMAIN SOCKET", 29); + fsync(STDOUT_FILENO); + return(NULL); + } + + written = write(STDOUT_FILENO, "LISTENING ON DOMAIN SOCKET\n", 27); + fsync(STDOUT_FILENO); + + signal(SIGTERM, ExitSink); + + if ((KVM_AGENT_FD = accept(KVM_Listener_FD, NULL, NULL)) < 0) + { + written = write(STDOUT_FILENO, "ACCEPT ERROR ON DOMAIN SOCKET", 29); + fsync(STDOUT_FILENO); + return(NULL); + } + else + { + char tmp[255]; + int tmpLen = sprintf_s(tmp, sizeof(tmp), "ACCEPTed new connection %d on Domain Socket\n", KVM_AGENT_FD); + written = write(STDOUT_FILENO, tmp, tmpLen); + fsync(STDOUT_FILENO); + + } + } + // Init the kvm + if (kvm_init() != 0) { return (void*)-1; } + + + g_shutdown = 0; + pthread_create(&kvmthread, NULL, kvm_mainloopinput, param); + + + if (KVM_AGENT_FD != -1) + { + written = write(STDOUT_FILENO, "Starting Loop []\n", 14); + fsync(STDOUT_FILENO); + + char stmp[255]; + int stmpLen = sprintf_s(stmp, sizeof(stmp), "TILE_HEIGHT_COUNT=%d, TILE_WIDTH_COUNT=%d\n", TILE_HEIGHT_COUNT, TILE_WIDTH_COUNT); + written = write(STDOUT_FILENO, stmp, stmpLen); + fsync(STDOUT_FILENO); + } + + while (!g_shutdown) + { + if (g_resetipc != 0) + { + g_resetipc = 0; + close(KVM_AGENT_FD); + + SCREEN_HEIGHT = SCREEN_WIDTH = 0; + + char stmp[255]; + int stmpLen = sprintf_s(stmp, sizeof(stmp), "Waiting for NEXT DomainSocket, TILE_HEIGHT_COUNT=%d, TILE_WIDTH_COUNT=%d\n", TILE_HEIGHT_COUNT, TILE_WIDTH_COUNT); + written = write(STDOUT_FILENO, stmp, stmpLen); + fsync(STDOUT_FILENO); + + if ((KVM_AGENT_FD = accept(KVM_Listener_FD, NULL, NULL)) < 0) + { + g_shutdown = 1; + written = write(STDOUT_FILENO, "ACCEPT ERROR ON DOMAIN SOCKET", 29); + fsync(STDOUT_FILENO); + break; + } + else + { + char tmp[255]; + int tmpLen = sprintf_s(tmp, sizeof(tmp), "ACCEPTed new connection %d on Domain Socket\n", KVM_AGENT_FD); + written = write(STDOUT_FILENO, tmp, tmpLen); + fsync(STDOUT_FILENO); + pthread_create(&kvmthread, NULL, kvm_mainloopinput, param); + } + } + + for (r = 0; r < TILE_HEIGHT_COUNT; r++) { + for (c = 0; c < TILE_WIDTH_COUNT; c++) { + g_tileInfo[r][c].flag = TILE_TODO; + } + } + //senddebug(2); + screen_num = CGMainDisplayID(); + + if (screen_num == 0) { g_shutdown = 1; senddebug(-2); break; } + screen_height = CGDisplayPixelsHigh(screen_num); + screen_width = CGDisplayPixelsWide(screen_num); + + if ((SCREEN_HEIGHT != screen_height || SCREEN_WIDTH != screen_width || SCREEN_NUM != screen_num)) + { + kvm_init(); + continue; + } + + //senddebug(screen_num); + CGImageRef image = CGDisplayCreateImage(screen_num); + //senddebug(99); + if (image == NULL) + { + g_shutdown = 1; + senddebug(0); + } + else { + //senddebug(100); + getScreenBuffer((unsigned char **)&desktop, &desktopsize, image); + + if (KVM_AGENT_FD != -1) + { + char tmp[255]; + int tmpLen = sprintf_s(tmp, sizeof(tmp), "...Enter for loop\n"); + written = write(STDOUT_FILENO, tmp, tmpLen); + fsync(STDOUT_FILENO); + } + + + + for (y = 0; y < TILE_HEIGHT_COUNT; y++) + { + for (x = 0; x < TILE_WIDTH_COUNT; x++) { + height = TILE_HEIGHT * y; + width = TILE_WIDTH * x; + if (!g_shutdown && (g_pause)) { usleep(100000); g_pause = 0; } //HACK: Change this + + if (g_shutdown) { x = TILE_WIDTH_COUNT; y = TILE_HEIGHT_COUNT; break; } + + if (g_tileInfo[y][x].flag == TILE_SENT || g_tileInfo[y][x].flag == TILE_DONT_SEND) { + continue; + } + + getTileAt(width, height, &buf, &tilesize, desktop, desktopsize, y, x); + + if (buf && !g_shutdown) + { + // Write the reply to the pipe. + //KvmDebugLog("Writing to master in kvm_server_mainloop\n"); + + written = KVM_SEND(buf, tilesize); + + //KvmDebugLog("Wrote %d bytes to master in kvm_server_mainloop\n", written); + if (written == -1) + { + /*ILIBMESSAGE("KVMBREAK-K2\r\n");*/ + if(KVM_AGENT_FD == -1) + { + // This is a User Session, so if the connection fails, we exit out... We can be spawned again later + g_shutdown = 1; height = SCREEN_HEIGHT; width = SCREEN_WIDTH; break; + } + } + //else + //{ + // char tmp[255]; + // int tmpLen = sprintf_s(tmp, sizeof(tmp), "KVM_SEND => tilesize: %d\n", tilesize); + // written = write(STDOUT_FILENO, tmp, tmpLen); + // fsync(STDOUT_FILENO); + //} + free(buf); + + } + } + } + + if (KVM_AGENT_FD != -1) + { + char tmp[255]; + int tmpLen = sprintf_s(tmp, sizeof(tmp), "...exit for loop\n"); + written = write(STDOUT_FILENO, tmp, tmpLen); + fsync(STDOUT_FILENO); + } + + } + CGImageRelease(image); + } + + pthread_join(kvmthread, NULL); + kvmthread = (pthread_t)NULL; + + if (g_tileInfo != NULL) { for (r = 0; r < TILE_HEIGHT_COUNT; r++) { free(g_tileInfo[r]); } } + g_tileInfo = NULL; + if(tilebuffer != NULL) { + free(tilebuffer); + tilebuffer = NULL; + } + + if (KVM_AGENT_FD != -1) + { + written = write(STDOUT_FILENO, "Exiting...\n", 11); + fsync(STDOUT_FILENO); + } + return (void*)0; +} + +void kvm_relay_ExitHandler(ILibProcessPipe_Process sender, int exitCode, void* user) +{ + ILibKVM_WriteHandler writeHandler = (ILibKVM_WriteHandler)((void**)user)[0]; + void *reserved = ((void**)user)[1]; + void *pipeMgr = ((void**)user)[2]; + char *exePath = (char*)((void**)user)[3]; +} +void kvm_relay_StdOutHandler(ILibProcessPipe_Process sender, char *buffer, int bufferLen, int* bytesConsumed, void* user) +{ + unsigned short size = 0; + UNREFERENCED_PARAMETER(sender); + ILibKVM_WriteHandler writeHandler = (ILibKVM_WriteHandler)((void**)user)[0]; + void *reserved = ((void**)user)[1]; + + if (bufferLen > 4) + { + size = ntohs(((unsigned short*)(buffer))[1]); + if (size <= bufferLen) + { + if (ntohs(((unsigned short*)(buffer))[0]) == MNG_DEBUG) + { + char tmp[255]; + int x = sprintf_s(tmp, sizeof(tmp), "DEBUG: %d\n", ((int*)buffer)[1]); + + write(STDOUT_FILENO, tmp, x); + } + *bytesConsumed = size; + writeHandler(buffer, size, reserved); + return; + } + } + *bytesConsumed = 0; +} +void kvm_relay_StdErrHandler(ILibProcessPipe_Process sender, char *buffer, int bufferLen, int* bytesConsumed, void* user) +{ + //KVMDebugLog *log = (KVMDebugLog*)buffer; + + //UNREFERENCED_PARAMETER(sender); + //UNREFERENCED_PARAMETER(user); + + //if (bufferLen < sizeof(KVMDebugLog) || bufferLen < log->length) { *bytesConsumed = 0; return; } + //*bytesConsumed = log->length; + ////ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), (ILibRemoteLogging_Modules)log->logType, (ILibRemoteLogging_Flags)log->logFlags, "%s", log->logData); + //ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), ILibRemoteLogging_Modules_Microstack_Generic, (ILibRemoteLogging_Flags)log->logFlags, "%s", log->logData); + *bytesConsumed = bufferLen; +} + + +// Setup the KVM session. Return 1 if ok, 0 if it could not be setup. +void* kvm_relay_setup(char *exePath, void *processPipeMgr, ILibKVM_WriteHandler writeHandler, void *reserved, int uid) +{ + char * parms0[] = { "meshagent_osx64", "-kvm0", NULL }; + void **user = (void**)ILibMemory_Allocate(4 * sizeof(void*), 0, NULL, NULL); + user[0] = writeHandler; + user[1] = reserved; + user[2] = processPipeMgr; + user[3] = exePath; + + char tmp[255]; + int x; + + if (uid != 0) + { + // Spawn child kvm process into a specific user session + + x = sprintf_s(tmp, sizeof(tmp), "Spawning Process: %d\n", uid); + write(STDOUT_FILENO, tmp, x); + gChildProcess = ILibProcessPipe_Manager_SpawnProcessEx3(processPipeMgr, exePath, parms0, ILibProcessPipe_SpawnTypes_DEFAULT, (void*)(uint64_t)uid, 0); + + x = sprintf_s(tmp, sizeof(tmp), "Result: %p\n", (void*)gChildProcess); + write(STDOUT_FILENO, tmp, x); + + g_slavekvm = ILibProcessPipe_Process_GetPID(gChildProcess); + ILibProcessPipe_Process_AddHandlers(gChildProcess, 65535, &kvm_relay_ExitHandler, &kvm_relay_StdOutHandler, &kvm_relay_StdErrHandler, NULL, user); + + // Run the relay + g_shutdown = 0; + return(ILibProcessPipe_Process_GetStdOut(gChildProcess)); + } + else + { + // No users are logged in. This is a special case for MacOS + //int fd = socket(AF_UNIX, SOCK_STREAM, 0); + //if (!fd < 0) + //{ + // struct sockaddr_un serveraddr; + // memset(&serveraddr, 0, sizeof(serveraddr)); + // serveraddr.sun_family = AF_UNIX; + // strcpy(serveraddr.sun_path, KVM_Listener_Path); + // if (!connect(fd, (struct sockaddr *)&serveraddr, SUN_LEN(&serveraddr)) < 0) + // { + // return((void*)(uint64_t)fd); + // } + //} + return((void*)KVM_Listener_Path); + } +} + +// Force a KVM reset & refresh +void kvm_relay_reset() +{ + char buffer[4]; + ((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_REFRESH); // Write the type + ((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)4); // Write the size + kvm_relay_feeddata(buffer, 4); +} + +// Clean up the KVM session. +void kvm_cleanup() +{ + KvmDebugLog("kvm_cleanup\n"); + g_shutdown = 1; +} diff --git a/meshcore/KVM/MacOS/mac_kvm.h b/meshcore/KVM/MacOS/mac_kvm.h new file mode 100644 index 0000000..df988f9 --- /dev/null +++ b/meshcore/KVM/MacOS/mac_kvm.h @@ -0,0 +1,36 @@ +/* + * mac_kvm.h + * + * + * Created by Ylian Saint-Hilaire on 8/17/11. + * Copyright 2011 __MyCompanyName__. All rights reserved. + * + */ +#ifndef LINUX_KVM_H_ +#define LINUX_KVM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mac_tile.h" +#include "mac_events.h" +#include "../../../microstack/ILibParsers.h" + +typedef ILibTransport_DoneState(*ILibKVM_WriteHandler)(char *buffer, int bufferLen, void *reserved); + +int kvm_relay_feeddata(char* buf, int len); +void kvm_pause(int pause); +void* kvm_relay_setup(char *exePath, void *processPipeMgr, ILibKVM_WriteHandler writeHandler, void *reserved, int uid); +void kvm_relay_reset(); +void kvm_cleanup(); + +#endif /* LINUX_KVM_H_ */ + diff --git a/meshcore/KVM/MacOS/mac_tile.c b/meshcore/KVM/MacOS/mac_tile.c new file mode 100644 index 0000000..4edd429 --- /dev/null +++ b/meshcore/KVM/MacOS/mac_tile.c @@ -0,0 +1,507 @@ +/* + * mac_tile.c + * + * + * Created by Ylian Saint-Hilaire on 8/18/11. + * Copyright 2011 __MyCompanyName__. All rights reserved. + * + */ + +#include "mac_tile.h" +#include "../../meshinfo.h" +#include "../../meshdefines.h" + +extern CGDirectDisplayID SCREEN_NUM; +extern int SCREEN_WIDTH; +extern int SCREEN_HEIGHT; +extern int SCREEN_DEPTH; +extern int TILE_WIDTH; +extern int TILE_HEIGHT; +extern int TILE_WIDTH_COUNT; +extern int TILE_HEIGHT_COUNT; +extern int COMPRESSION_RATIO; +extern struct tileInfo_t **g_tileInfo; +extern unsigned char *jpeg_buffer; +extern int jpeg_buffer_length; + +int tilebuffersize = 0; +void* tilebuffer = NULL; +int COMPRESSION_QUALITY = 50; + +/****************************************************************************** + * INTERNAL FUNCTIONS + ******************************************************************************/ + +//Extracts the required tile buffer from the desktop buffer +int get_tile_buffer(int x, int y, void **buffer, long long bufferSize, void *desktop, long long desktopsize, int tilewidth, int tileheight) +{ + char *target = *buffer; + int height = 0; + + for (height = y; height < y + tileheight; height++) { + memcpy(target, (const void *)(((char *)desktop) + (3 * ((height * adjust_screen_size(SCREEN_WIDTH)) + x))), (size_t)(tilewidth * 3)); + target = (char *) (target + (3 * tilewidth)); + } + + return 0; +} + +//This function returns 0 and *buffer != NULL if everything was good. retval = jpegsize if the captured image was too large. +int calc_opt_compr_send(int x, int y, int captureWidth, int captureHeight, void* desktop, long long desktopsize, void ** buffer, long long *bufferSize) +{ + + *buffer = NULL; + *bufferSize = 0; + + // Make sure a tile buffer is available. Most of the time, this is skipped. + if (tilebuffersize != captureWidth * captureHeight * 3) + { + if (tilebuffer != NULL) free(tilebuffer); + tilebuffersize = captureWidth * captureHeight * 3; + if ((tilebuffer = malloc(tilebuffersize)) == NULL) return 0; + } + + //Get the final coalesced tile + get_tile_buffer(x, y, &tilebuffer, tilebuffersize, desktop, desktopsize, captureWidth, captureHeight); + + write_JPEG_buffer(tilebuffer, captureWidth, captureHeight, COMPRESSION_QUALITY); + + if (jpeg_buffer_length > 65500) { + return jpeg_buffer_length; + } + else { + return 0; + } +} + +#if 0 +void dump32bit (const XImage * input) +{ + int row, col; + static char head[256]; + + static FILE *fp2 = NULL; + char *ptr2, *output; + long size; + + register unsigned int + rm = input->red_mask, + gm = input->green_mask, + bm = input->blue_mask, + rs = 16, + gs = 8, + bs = 0, *p32 = (unsigned int *) input->data; + + + printf("%x %x %x\n", rm, gm, bm); + sprintf (head, "P6\n%d %d\n%d\n", input->width, input->height, 255); + size = ((input->bytes_per_line * input->height) / 4) * 3; + output = malloc (size); + ptr2 = output; + + for (row = 0; row < input->height; row++) { + for (col = 0; col < input->width; col++) { + *output++ = ((*p32 & rm) >> rs); + *output++ = ((*p32 & gm) >> gs); + *output++ = ((*p32 & bm) >> bs); + p32++; // ignore alpha values + } + // + // eat padded bytes, for better speed we use shifting, + // (bytes_per_line - bits_per_pixel / 8 * width ) / 4 + // + p32 += (input->bytes_per_line - (input->bits_per_pixel >> 3) + * input->width) >> 2; + } + + fp2 = fopen ("/tmp/pic.rgb.pnm", "w"); + fwrite (head, strlen (head), 1, fp2); + + fwrite (ptr2, size, 1, fp2); + fclose (fp2); + free (ptr2); +} +#endif + +// Really fast CRC-like method. Used for the KVM. + +int util_crc(int x, int y, long long bufferSize, void *desktop, long long desktopsize, int tilewidth, int tileheight) +{ + int hval = 0; + int *bp = NULL; + int *be = NULL; + int height = 0; + + for (height = y; height < y + tileheight; height++) { + bp = (int *)(((char *)desktop) + (3 * ((height * adjust_screen_size(SCREEN_WIDTH)) + x))); + be = (int *)(((char *)desktop) + (3 * ((height * adjust_screen_size(SCREEN_WIDTH)) + x + tilewidth))); + while ((bp + 1) <= be) + { + //hval *= 0x01000193; + hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24); + hval ^= *bp++; + } + + /*if ((int)be - (int)bp >= 0) { + hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24); + hval ^= (*(int *)(((int)be) - 3)); + }*/ + } + + return hval; +} + +/****************************************************************************** + * EXTERNAL FUNCTIONS + ******************************************************************************/ + +//Adjusts the screen size(width or height) to be exactly divisible by TILE_WIDTH +int adjust_screen_size(int pixles) +{ + int extra = pixles % TILE_WIDTH; //Assuming tile width and height will remain the same. + + if (extra != 0) { return pixles + TILE_WIDTH - extra; } + + return pixles; +} + +// Reset the tile info structure +int reset_tile_info(int old_height_count) { + int row, col; + + if (g_tileInfo != NULL) + { + for (row = 0; row < old_height_count; row++) { free(g_tileInfo[row]); } + free(g_tileInfo); + g_tileInfo = NULL; + } + + g_tileInfo = (struct tileInfo_t **) malloc(sizeof(struct tileInfo_t *) * TILE_HEIGHT_COUNT); + for (row = 0; row < TILE_HEIGHT_COUNT; row++) { + g_tileInfo[row] = (struct tileInfo_t *) calloc (TILE_WIDTH_COUNT, sizeof(struct tileInfo_t)); + for (col = 0; col < TILE_WIDTH_COUNT; col++) { g_tileInfo[row][col].crc = 0xff; } + } + + return 0; +} + +//Fetches the encoded jpeg tile at the given location. The neighboring tiles are coalesced to form a larger jpeg before returning. +int getTileAt(int x, int y, void** buffer, long long *bufferSize, void *desktop, long long desktopsize, int row, int col) +{ + int CRC, rcol, i, r, c; + int rightcol = col; //Used in coalescing. Indicates the rightmost column to be coalesced. + int botrow = row; //Used in coalescing. Indicates the bottom most row to be coalesced. + int r_x = x; + int r_y = y; + int captureWidth = TILE_WIDTH; + int captureHeight = TILE_HEIGHT; + + *buffer = NULL; // If anything fails, this will be the indication. + *bufferSize = 0; + + if (g_tileInfo[row][col].flag == TILE_TODO) { //First check whether the tile-crc needs to be calculated or not. + if ((CRC = util_crc(x, y, TILE_HEIGHT * TILE_WIDTH * 3, desktop, desktopsize, TILE_WIDTH, TILE_HEIGHT)) == g_tileInfo[row][col].crc) return 0; + g_tileInfo[row][col].crc = CRC; //Update the tile CRC in the global data structure. + } + + g_tileInfo[row][col].flag = TILE_MARKED_NOT_SENT; + + //COALESCING SECTION + + // First got to the right most changed tile and record it + while (rightcol + 1 < TILE_WIDTH_COUNT) { + rightcol++; + r_x = rightcol * TILE_WIDTH; + + CRC = g_tileInfo[row][rightcol].crc; + + if (g_tileInfo[row][rightcol].flag == TILE_TODO) { + CRC = util_crc(r_x, y, TILE_HEIGHT * TILE_WIDTH * 3, desktop, desktopsize, TILE_WIDTH, TILE_HEIGHT); + } + + if (CRC != g_tileInfo[row][rightcol].crc || g_tileInfo[row][rightcol].flag == TILE_MARKED_NOT_SENT) { //If the tile has changed, increment the capturewidth. + g_tileInfo[row][rightcol].crc = CRC; + //Here we check whether the size of the coalesced bitmap is greater than the threshold (65500) + if ((captureWidth + TILE_WIDTH) * TILE_HEIGHT * 3 / COMPRESSION_RATIO > 65500) { + g_tileInfo[row][rightcol].flag = TILE_MARKED_NOT_SENT; + --rightcol; + break; + } + + g_tileInfo[row][rightcol].flag = TILE_MARKED_NOT_SENT; + captureWidth += TILE_WIDTH; + } + else { + g_tileInfo[row][rightcol].flag = TILE_DONT_SEND; + --rightcol; + break; + } + } + + //int TOLERANCE = (rightcol - col) / 3; + + // Now go to the bottom tiles, check if they have changed and record them + while ((botrow + 1 < TILE_HEIGHT_COUNT) && ((captureHeight + TILE_HEIGHT) * captureWidth * 3 / COMPRESSION_RATIO <= 65500)) { + botrow++; + r_y = botrow * TILE_HEIGHT; + int fail = 0; + r_x = x; + + //int missCount = 0; + + for (rcol = col; rcol <= rightcol; rcol++) { + + CRC = g_tileInfo[botrow][rcol].crc; + if (g_tileInfo[botrow][rcol].flag == TILE_TODO) { + CRC = util_crc(r_x, r_y, TILE_HEIGHT * TILE_WIDTH * 3, desktop, desktopsize, TILE_WIDTH, TILE_HEIGHT); + } + + if (CRC != g_tileInfo[botrow][rcol].crc || g_tileInfo[botrow][rcol].flag == TILE_MARKED_NOT_SENT) { + g_tileInfo[botrow][rcol].flag = TILE_MARKED_NOT_SENT; + g_tileInfo[botrow][rcol].crc = CRC; + r_x += TILE_WIDTH; + } + else { + /*//Keep this part commented. Adding tolerance adds to the complexity of this code. + missCount++; + + if (missCount > TOLERANCE) { + fail = 1; + for (int i = col; i < rcol; i++) { + if (g_tileInfo[botrow][i].flag == TILE_SKIPPED) { + g_tileInfo[botrow][i].flag = TILE_DONT_SEND; + } + else { + g_tileInfo[botrow][i].flag = TILE_MARKED_NOT_SENT; + } + } + g_tileInfo[botrow][rcol].flag = TILE_DONT_SEND; + botrow--; + break; + } + else { + g_tileInfo[botrow][rcol].flag = TILE_SKIPPED; + g_tileInfo[botrow][rcol].crc = CRC; + r_x += TILE_WIDTH; + }*/ + fail = 1; + for (i = col; i < rcol; i++) { + g_tileInfo[botrow][i].flag = TILE_MARKED_NOT_SENT; + } + g_tileInfo[botrow][rcol].flag = TILE_DONT_SEND; + botrow--; + break; + } + } + + if (!fail) { + captureHeight += TILE_HEIGHT; + } + else { + break; + } + } + + int retval = 0; + int firstTime = 1; + + //This loop is used to adjust the COMPRESSION_RATIO. This loop runs only once most of the time. + do { + //retval here is 0 if everything was good. It is > 0 if it contains the size of the jpeg that was created and not sent. + retval = calc_opt_compr_send(x, y, captureWidth, captureHeight, desktop, desktopsize, buffer, bufferSize); + if (retval != 0) { + if (firstTime) { + //Re-adjust the compression ratio. + COMPRESSION_RATIO = (int)(((double)COMPRESSION_RATIO/(double)retval) * 60000);//Magic number: 60000 ~= 65500 + if (COMPRESSION_RATIO <= 1) { + COMPRESSION_RATIO = 2; + } + + firstTime = 0; + } + + if (botrow > row) { //First time, try reducing the height. + botrow = row + ((botrow - row + 1) / 2); + captureHeight = (botrow - row + 1) * TILE_HEIGHT; + } + else if (rightcol > col){ //If it is not possible, reduce the width + rightcol = col + ((rightcol - col + 1) / 2); + captureWidth = (rightcol - col + 1) * TILE_WIDTH; + } + else { //This never happens in any case. + retval = 0; + break; + } + + } + } while (retval != 0); + + //Set the flags to TILE_SENT + if (jpeg_buffer != NULL) { + *bufferSize = jpeg_buffer_length + 8; + + *buffer = malloc (*bufferSize); + ((unsigned short*)*buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_PICTURE); // Write the type + ((unsigned short*)*buffer)[1] = (unsigned short)htons((unsigned short)*bufferSize); // Write the size + ((unsigned short*)*buffer)[2] = (unsigned short)htons((unsigned short)x); // X position + ((unsigned short*)*buffer)[3] = (unsigned short)htons((unsigned short)y); // Y position + memcpy((char *)(*buffer) + 8, jpeg_buffer, jpeg_buffer_length); + free(jpeg_buffer); + jpeg_buffer = NULL; + jpeg_buffer_length = 0; + + for (r = row; r <= botrow; r++) { + for (c = col; c <= rightcol; c++) { + g_tileInfo[r][c].flag = TILE_SENT; + } + } + } + + return retval; +} + + +// Get screen buffer from the CGImageRef structure +int getScreenBuffer(unsigned char **desktop, long long *desktopsize, CGImageRef image) +{ + unsigned int row, col, bpp, len, width_padding_size, height_padding_size, i; + unsigned char *output; + int height = CGImageGetHeight(image); + int width = CGImageGetWidth(image); + + CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(image); + + CFDataRef dataRef = CGDataProviderCopyData(CGImageGetDataProvider(image)); + const unsigned char *sourceBytesPtr = CFDataGetBytePtr(dataRef); + len = CFDataGetLength(dataRef); + + if (*desktopsize != len) { + if (*desktop != NULL) { free(*desktop); } + *desktopsize = len; + *desktop = (unsigned char *) malloc (*desktopsize); + } + + output = *desktop; + bpp = CGImageGetBitsPerPixel(image); + width_padding_size = (adjust_screen_size(SCREEN_WIDTH) - width) * 3; + + switch(bpp) { + case 16: + { + const unsigned short *tmpPtr = (const unsigned short *)sourceBytesPtr; + if(alphaInfo == kCGImageAlphaNoneSkipFirst || + alphaInfo == kCGImageAlphaPremultipliedFirst || + alphaInfo == kCGImageAlphaFirst) { + for (row = 0; row < height; row++) { + for (col = 0; col < width; col++) { + *output++ = (*tmpPtr & 0x7C00) >> 7; + *output++ = (*tmpPtr & 0x3E0) >> 2; + *output++ = (*tmpPtr & 0x1F) << 3; + tmpPtr++; + } + + if (width_padding_size != 0) { + for (i = 0; i < width_padding_size; i++) { + *output++ = 0; + } + } + tmpPtr += (CGImageGetBytesPerRow(image) - (bpp >> 3) * width) >> 2; + } + } + else if (alphaInfo == kCGImageAlphaNone || + alphaInfo == kCGImageAlphaNoneSkipLast || + alphaInfo == kCGImageAlphaPremultipliedLast || + alphaInfo == kCGImageAlphaLast) { + for (row = 0; row < height; row++) { + for (col = 0; col < width; col++) { + *output++ = (*tmpPtr & 0xF800) >> 8; + *output++ = (*tmpPtr & 0x7C0) >> 3; + *output++ = (*tmpPtr & 0x3E) << 2; + tmpPtr++; + } + if (width_padding_size != 0) { + for (i = 0; i < width_padding_size; i++) { + *output++ = 0; + } + } + tmpPtr += (CGImageGetBytesPerRow(image) - (bpp >> 3) * width) >> 2; + } + } + } + break; + case 32: + { + const unsigned int *tmpPtr1 = (const unsigned int *)sourceBytesPtr; + if(alphaInfo == kCGImageAlphaNoneSkipFirst || + alphaInfo == kCGImageAlphaPremultipliedFirst || + alphaInfo == kCGImageAlphaFirst) { + for (row = 0; row < height; row++) { + for (col = 0; col < width; col++) { + *output++ = (*tmpPtr1 & 0x0ff0000) >> 16; + *output++ = (*tmpPtr1 & 0x0ff00) >> 8; + *output++ = (*tmpPtr1 & 0x0FF); + tmpPtr1++; + } + if (width_padding_size != 0) { + for (i = 0; i < width_padding_size; i++) { + *output++ = 0; + } + } + tmpPtr1 += (CGImageGetBytesPerRow(image) - (bpp >> 3) * width) >> 2; + } + } + else if (alphaInfo == kCGImageAlphaNone || + alphaInfo == kCGImageAlphaNoneSkipLast || + alphaInfo == kCGImageAlphaPremultipliedLast || + alphaInfo == kCGImageAlphaLast) { + for (row = 0; row < height; row++) { + for (col = 0; col < width; col++) { + *output++ = (*tmpPtr1 & 0xFF000000) >> 24; + *output++ = (*tmpPtr1 & 0x0ff0000) >> 16; + *output++ = (*tmpPtr1 & 0x0ff00) >> 8; + tmpPtr1++; + } + if (width_padding_size != 0) { + for (i = 0; i < width_padding_size; i++) { + *output++ = 0; + } + } + tmpPtr1 += (CGImageGetBytesPerRow(image) - (bpp >> 3) * width) >> 2; + } + } + } + break; + default: + fprintf(stderr, "This image depth is not supported.\n"); + return -1; + } + + height_padding_size = adjust_screen_size(SCREEN_HEIGHT) - height; + + if (height_padding_size != 0) { + for (row = 0; row < height_padding_size; row++) { + for (col = 0; col < (width * 3) + width_padding_size; col++) { + *output++ = 0; + } + } + } + + CFRelease(dataRef); + + return 0; +} + + +// Set the compression quality +void set_tile_compression(int type, int level) +{ + if (level > 0 && level <= 100) { + COMPRESSION_QUALITY = level; + } + else { + COMPRESSION_QUALITY = 60; + } + + // TODO Make sure the all the types are handled. We ignore the type variable for now. +} + diff --git a/meshcore/KVM/MacOS/mac_tile.h b/meshcore/KVM/MacOS/mac_tile.h new file mode 100644 index 0000000..9541c97 --- /dev/null +++ b/meshcore/KVM/MacOS/mac_tile.h @@ -0,0 +1,41 @@ +/* + * mac_tile.h + * + * + * Created by Ylian Saint-Hilaire on 8/18/11. + * Copyright 2011 __MyCompanyName__. All rights reserved. + * + */ + +#ifndef LINUX_TILE_H_ +#define LINUX_TILE_H_ + +#include +#include +#include +#include +#include +#include "../Linux/linux_compression.h" + +enum TILE_FLAGS_ENUM { + TILE_TODO, //The tile CRC needs to be calculated. + TILE_SENT, //CRC has been calculated and the tile has been sent. + TILE_MARKED_NOT_SENT, //CRC has been calculated, but the tile was not sent. + TILE_DONT_SEND //CRC has been calculated, tile need not be sent. + //TILE_SKIPPED //CRC has been calculated, tile need not be sent, but was skipped to include a greater region +}; + +struct tileInfo_t { + int crc; + enum TILE_FLAGS_ENUM flag; +}; + +extern int reset_tile_info(int old_height_count); +extern int adjust_screen_size(int pixles); +extern int getTileAt(int x, int y, void** buffer, long long *bufferSize, void *desktop, long long desktopsize, int row, int col); +extern int getScreenBuffer(unsigned char **desktop, long long *desktopsize, CGImageRef image); +extern void set_tile_compression(int type, int level); + + +#endif /* LINUX_TILE_H_ */ +