/** * FreeRDP: A Remote Desktop Protocol Implementation * FreeRDP Mac OS X Server (Input) * * Copyright 2013 Corey Clayton * * 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "mf_input.h" #include "mf_info.h" #include #define TAG SERVER_TAG("mac") static const CGKeyCode keymap[256] = { 0xFF, //0x0 kVK_Escape, //0x1 kVK_ANSI_1, //0x2 kVK_ANSI_2, //0x3 kVK_ANSI_3, //0x4 kVK_ANSI_4, //0x5 kVK_ANSI_5, //0x6 kVK_ANSI_6, //0x7 kVK_ANSI_7, //0x8 kVK_ANSI_8, //0x9 kVK_ANSI_9, //0xa kVK_ANSI_0, //0xb kVK_ANSI_Minus, //0xc kVK_ANSI_Equal, //0xd kVK_Delete, //0xe kVK_Tab, //0xf kVK_ANSI_Q, //0x10 kVK_ANSI_W, //0x11 kVK_ANSI_E, //0x12 kVK_ANSI_R, //0x13 kVK_ANSI_T, //0x14 kVK_ANSI_Y, //0x15 kVK_ANSI_U, //0x16 kVK_ANSI_I, //0x17 kVK_ANSI_O, //0x18 kVK_ANSI_P, //0x19 kVK_ANSI_LeftBracket, //0x1a kVK_ANSI_RightBracket, //0x1b kVK_Return, //0x1c kVK_Control, //0x1d kVK_ANSI_A, //0x1e kVK_ANSI_S, //0x1f kVK_ANSI_D, //0x20 kVK_ANSI_F, //0x21 kVK_ANSI_G, //0x22 kVK_ANSI_H, //0x23 kVK_ANSI_J, //0x24 kVK_ANSI_K, //0x25 kVK_ANSI_L, //0x26 kVK_ANSI_Semicolon, //0x27 kVK_ANSI_Quote, //0x28 kVK_ANSI_Grave, //0x29 kVK_Shift, //0x2a kVK_ANSI_Backslash, //0x2b kVK_ANSI_Z, //0x2c kVK_ANSI_X, //0x2d kVK_ANSI_C, //0x2e kVK_ANSI_V, //0x2f kVK_ANSI_B, //0x30 kVK_ANSI_N, //0x31 kVK_ANSI_M, //0x32 kVK_ANSI_Comma, //0x33 kVK_ANSI_Period, //0x34 kVK_ANSI_Slash, //0x35 kVK_Shift, //0x36 kVK_ANSI_KeypadMultiply, //0x37 kVK_Option, //0x38 kVK_Space, //0x39 kVK_CapsLock, //0x3a kVK_F1, //0x3b kVK_F2, //0x3c kVK_F3, //0x3d kVK_F4, //0x3e kVK_F5, //0x3f kVK_F6, //0x40 kVK_F7, //0x41 kVK_F8, //0x42 kVK_F9, //0x43 kVK_F10, //0x44 0xFF, //0x45 -- numlock 0xFF, //0x46 -- scroll lock kVK_ANSI_Keypad7, //0x47 kVK_ANSI_Keypad8, //0x48 kVK_ANSI_Keypad9, //0x49 kVK_ANSI_KeypadMinus, //0x4a kVK_ANSI_Keypad4, //0x4b kVK_ANSI_Keypad5, //0x4c kVK_ANSI_Keypad6, //0x4d kVK_ANSI_KeypadPlus, //0x4e kVK_ANSI_Keypad1, //0x4f kVK_ANSI_Keypad2, //0x50 kVK_ANSI_Keypad3, //0x51 kVK_ANSI_Keypad0, //0x52 kVK_ANSI_KeypadDecimal, //0x53 0xFF, //0x54 0xFF, //0x55 0xFF, //0x56 kVK_F11, //0x57 kVK_F12, //0x58 0xFF, //0x59 -- pause 0xFF, //0x5a kVK_Control, //0x5b kVK_Control, //0x5c 0xFF, //0x5d -- application 0xFF, //0x5e -- power 0xFF, //0x5f -- sleep 0xFF, //0x60 0xFF, //0x61 0xFF, //0x62 0xFF, //0x63 -- wake 0xFF, //0x64 0xFF, //0x65 0xFF, //0x66 0xFF, //0x67 0xFF, //0x68 0xFF, //0x69 0xFF, //0x6a 0xFF, //0x6b 0xFF, //0x6c 0xFF, //0x6d 0xFF, //0x6e 0xFF, //0x6f 0xFF, //0x70 0xFF, //0x71 0xFF, //0x72 0xFF, //0x73 0xFF, //0x74 0xFF, //0x75 0xFF, //0x76 0xFF, //0x77 0xFF, //0x78 0xFF, //0x79 0xFF, //0x7a 0xFF, //0x7b 0xFF, //0x7c 0xFF, //0x7d 0xFF, //0x7e 0xFF, //0x7f 0xFF, //0x80 0xFF, //0x81 0xFF, //0x82 0xFF, //0x83 0xFF, //0x84 0xFF, //0x85 0xFF, //0x86 0xFF, //0x87 0xFF, //0x88 0xFF, //0x89 0xFF, //0x8a 0xFF, //0x8b 0xFF, //0x8c 0xFF, //0x8d 0xFF, //0x8e 0xFF, //0x8f 0xFF, //0x90 0xFF, //0x91 0xFF, //0x92 0xFF, //0x93 0xFF, //0x94 0xFF, //0x95 0xFF, //0x96 0xFF, //0x97 0xFF, //0x98 0xFF, //0x99 0xFF, //0x9a 0xFF, //0x9b 0xFF, //0x9c 0xFF, //0x9d 0xFF, //0x9e 0xFF, //0x9f 0xFF, //0xa0 0xFF, //0xa1 0xFF, //0xa2 0xFF, //0xa3 0xFF, //0xa4 0xFF, //0xa5 0xFF, //0xa6 0xFF, //0xa7 0xFF, //0xa8 0xFF, //0xa9 0xFF, //0xaa 0xFF, //0xab 0xFF, //0xac 0xFF, //0xad 0xFF, //0xae 0xFF, //0xaf 0xFF, //0xb0 0xFF, //0xb1 0xFF, //0xb2 0xFF, //0xb3 0xFF, //0xb4 0xFF, //0xb5 0xFF, //0xb6 0xFF, //0xb7 0xFF, //0xb8 0xFF, //0xb9 0xFF, //0xba 0xFF, //0xbb 0xFF, //0xbc 0xFF, //0xbd 0xFF, //0xbe 0xFF, //0xbf 0xFF, //0xc0 0xFF, //0xc1 0xFF, //0xc2 0xFF, //0xc3 0xFF, //0xc4 0xFF, //0xc5 0xFF, //0xc6 0xFF, //0xc7 0xFF, //0xc8 0xFF, //0xc9 0xFF, //0xca 0xFF, //0xcb 0xFF, //0xcc 0xFF, //0xcd 0xFF, //0xce 0xFF, //0xcf 0xFF, //0xd0 0xFF, //0xd1 0xFF, //0xd2 0xFF, //0xd3 0xFF, //0xd4 0xFF, //0xd5 0xFF, //0xd6 0xFF, //0xd7 0xFF, //0xd8 0xFF, //0xd9 0xFF, //0xda 0xFF, //0xdb 0xFF, //0xdc 0xFF, //0xdd 0xFF, //0xde 0xFF, //0xdf 0xFF, //0xe0 0xFF, //0xe1 0xFF, //0xe2 0xFF, //0xe3 0xFF, //0xe4 0xFF, //0xe5 0xFF, //0xe6 0xFF, //0xe7 0xFF, //0xe8 0xFF, //0xe9 0xFF, //0xea 0xFF, //0xeb 0xFF, //0xec 0xFF, //0xed 0xFF, //0xee 0xFF, //0xef 0xFF, //0xf0 0xFF, //0xf1 0xFF, //0xf2 0xFF, //0xf3 0xFF, //0xf4 0xFF, //0xf5 0xFF, //0xf6 0xFF, //0xf7 0xFF, //0xf8 0xFF, //0xf9 0xFF, //0xfa 0xFF, //0xfb 0xFF, //0xfc 0xFF, //0xfd 0xFF, //0xfe }; BOOL mf_input_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) { CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); BOOL keyDown = TRUE; CGEventRef kbEvent; CGKeyCode kCode = 0xFF; if (flags & KBD_FLAGS_RELEASE) { keyDown = FALSE; } if (flags & KBD_FLAGS_EXTENDED) { switch (code) { //case 0x52: //insert case 0x53: kCode = kVK_ForwardDelete; break; case 0x4B: kCode = kVK_LeftArrow; break; case 0x47: kCode = kVK_Home; break; case 0x4F: kCode = kVK_End; break; case 0x48: kCode = kVK_UpArrow; break; case 0x50: kCode = kVK_DownArrow; break; case 0x49: kCode = kVK_PageUp; break; case 0x51: kCode = kVK_PageDown; break; case 0x4D: kCode = kVK_RightArrow; break; default: break; } } else { kCode = keymap[code]; } kbEvent = CGEventCreateKeyboardEvent(source, kCode, keyDown); CGEventPost(kCGHIDEventTap, kbEvent); CFRelease(kbEvent); CFRelease(source); return TRUE; } BOOL mf_input_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) { return FALSE; } BOOL mf_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) { float width, height; CGWheelCount wheelCount = 2; INT32 scroll_x = 0; INT32 scroll_y = 0; if (flags & (PTR_FLAGS_WHEEL | PTR_FLAGS_HWHEEL)) { INT32 scroll = flags & WheelRotationMask; if (flags & PTR_FLAGS_WHEEL_NEGATIVE) scroll = -(flags & WheelRotationMask) / 392; else scroll = (flags & WheelRotationMask) / 120; if (flags & PTR_FLAGS_WHEEL) scroll_y = scroll; else scroll_x = scroll; CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); CGEventRef scrollEvent = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitLine, wheelCount, scroll_y, scroll_x); CGEventPost(kCGHIDEventTap, scrollEvent); CFRelease(scrollEvent); CFRelease(source); } else { mfInfo* mfi; CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); CGEventType mouseType = kCGEventNull; CGMouseButton mouseButton = kCGMouseButtonLeft; mfi = mf_info_get_instance(); //width and height of primary screen (even in multimon setups width = (float) mfi->servscreen_width; height = (float) mfi->servscreen_height; x += mfi->servscreen_xoffset; y += mfi->servscreen_yoffset; if (flags & PTR_FLAGS_MOVE) { if (mfi->mouse_down_left == TRUE) { mouseType = kCGEventLeftMouseDragged; } else if (mfi->mouse_down_right == TRUE) { mouseType = kCGEventRightMouseDragged; } else if (mfi->mouse_down_other == TRUE) { mouseType = kCGEventOtherMouseDragged; } else { mouseType = kCGEventMouseMoved; } CGEventRef move = CGEventCreateMouseEvent(source, mouseType, CGPointMake(x, y), mouseButton // ignored for just movement ); CGEventPost(kCGHIDEventTap, move); CFRelease(move); } if (flags & PTR_FLAGS_BUTTON1) { mouseButton = kCGMouseButtonLeft; if (flags & PTR_FLAGS_DOWN) { mouseType = kCGEventLeftMouseDown; mfi->mouse_down_left = TRUE; } else { mouseType = kCGEventLeftMouseUp; mfi->mouse_down_right = FALSE; } } else if (flags & PTR_FLAGS_BUTTON2) { mouseButton = kCGMouseButtonRight; if (flags & PTR_FLAGS_DOWN) { mouseType = kCGEventRightMouseDown; mfi->mouse_down_right = TRUE; } else { mouseType = kCGEventRightMouseUp; mfi->mouse_down_right = FALSE; } } else if (flags & PTR_FLAGS_BUTTON3) { mouseButton = kCGMouseButtonCenter; if (flags & PTR_FLAGS_DOWN) { mouseType = kCGEventOtherMouseDown; mfi->mouse_down_other = TRUE; } else { mouseType = kCGEventOtherMouseUp; mfi->mouse_down_other = FALSE; } } CGEventRef mouseEvent = CGEventCreateMouseEvent(source, mouseType, CGPointMake(x, y), mouseButton ); CGEventPost(kCGHIDEventTap, mouseEvent); CFRelease(mouseEvent); CFRelease(source); } return TRUE; } BOOL mf_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) { return FALSE; } BOOL mf_input_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT16 code) { return FALSE; } BOOL mf_input_unicode_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT16 code) { return FALSE; } BOOL mf_input_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) { return FALSE; } BOOL mf_input_extended_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) { return FALSE; }