// // KeyboardSupport.m // Moonlight // // Created by Diego Waxemberg on 8/25/18. // Copyright © 2018 Moonlight Game Streaming Project. All rights reserved. // #import "KeyboardSupport.h" #include @implementation KeyboardSupport + (BOOL)sendKeyEvent:(UIKey*)key down:(BOOL)down API_AVAILABLE(ios(13.4)){ char modifierFlags = 0; short keyCode = 0; if (key.modifierFlags & UIKeyModifierShift) { modifierFlags |= MODIFIER_SHIFT; } if (key.modifierFlags & UIKeyModifierAlternate) { modifierFlags |= MODIFIER_ALT; } if (key.modifierFlags & UIKeyModifierControl) { modifierFlags |= MODIFIER_CTRL; } if (key.modifierFlags & UIKeyModifierCommand) { modifierFlags |= MODIFIER_META; } // This converts UIKeyboardHIDUsage values to Win32 VK_* values // https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes if (key.keyCode >= UIKeyboardHIDUsageKeyboardA && key.keyCode <= UIKeyboardHIDUsageKeyboardZ) { keyCode = (key.keyCode - UIKeyboardHIDUsageKeyboardA) + 0x41; } else if (key.keyCode == UIKeyboardHIDUsageKeyboard0) { // This key is at the beginning of the VK_ range but the end // of the UIKeyboardHIDUsageKeyboard range. keyCode = 0x30; } else if (key.keyCode >= UIKeyboardHIDUsageKeyboard1 && key.keyCode <= UIKeyboardHIDUsageKeyboard9) { keyCode = (key.keyCode - UIKeyboardHIDUsageKeyboard1) + 0x31; } else if (key.keyCode == UIKeyboardHIDUsageKeypad0) { // This key is at the beginning of the VK_ range but the end // of the UIKeyboardHIDUsageKeypad range. keyCode = 0x60; } else if (key.keyCode >= UIKeyboardHIDUsageKeypad1 && key.keyCode <= UIKeyboardHIDUsageKeypad9) { keyCode = (key.keyCode - UIKeyboardHIDUsageKeypad1) + 0x61; } else if (key.keyCode >= UIKeyboardHIDUsageKeyboardF1 && key.keyCode <= UIKeyboardHIDUsageKeyboardF12) { keyCode = (key.keyCode - UIKeyboardHIDUsageKeyboardF1) + 0x70; } else if (key.keyCode >= UIKeyboardHIDUsageKeyboardF13 && key.keyCode <= UIKeyboardHIDUsageKeyboardF24) { keyCode = (key.keyCode - UIKeyboardHIDUsageKeyboardF13) + 0x7C; } else { switch (key.keyCode) { case UIKeyboardHIDUsageKeyboardReturnOrEnter: keyCode = 0x0D; break; case UIKeyboardHIDUsageKeyboardEscape: keyCode = 0x1B; break; case UIKeyboardHIDUsageKeyboardDeleteOrBackspace: keyCode = 0x08; break; case UIKeyboardHIDUsageKeyboardTab: keyCode = 0x09; break; case UIKeyboardHIDUsageKeyboardSpacebar: keyCode = 0x20; break; case UIKeyboardHIDUsageKeyboardHyphen: keyCode = 0xBD; break; case UIKeyboardHIDUsageKeyboardEqualSign: keyCode = 0xBB; break; case UIKeyboardHIDUsageKeyboardOpenBracket: keyCode = 0xDB; break; case UIKeyboardHIDUsageKeyboardCloseBracket: keyCode = 0xDD; break; case UIKeyboardHIDUsageKeyboardBackslash: keyCode = 0xDC; break; case UIKeyboardHIDUsageKeyboardSemicolon: keyCode = 0xBA; break; case UIKeyboardHIDUsageKeyboardQuote: keyCode = 0xDE; break; case UIKeyboardHIDUsageKeyboardGraveAccentAndTilde: keyCode = 0xC0; break; case UIKeyboardHIDUsageKeyboardComma: keyCode = 0xBC; break; case UIKeyboardHIDUsageKeyboardPeriod: keyCode = 0xBE; break; case UIKeyboardHIDUsageKeyboardSlash: keyCode = 0xBF; break; case UIKeyboardHIDUsageKeyboardCapsLock: keyCode = 0x14; break; case UIKeyboardHIDUsageKeyboardPrintScreen: keyCode = 0x2A; break; case UIKeyboardHIDUsageKeyboardScrollLock: keyCode = 0x91; break; case UIKeyboardHIDUsageKeyboardPause: keyCode = 0x13; break; case UIKeyboardHIDUsageKeyboardInsert: keyCode = 0x2D; break; case UIKeyboardHIDUsageKeyboardHome: keyCode = 0x24; break; case UIKeyboardHIDUsageKeyboardPageUp: keyCode = 0x21; break; case UIKeyboardHIDUsageKeyboardDeleteForward: keyCode = 0x2E; break; case UIKeyboardHIDUsageKeyboardEnd: keyCode = 0x23; break; case UIKeyboardHIDUsageKeyboardPageDown: keyCode = 0x22; break; case UIKeyboardHIDUsageKeyboardRightArrow: keyCode = 0x27; break; case UIKeyboardHIDUsageKeyboardLeftArrow: keyCode = 0x25; break; case UIKeyboardHIDUsageKeyboardDownArrow: keyCode = 0x28; break; case UIKeyboardHIDUsageKeyboardUpArrow: keyCode = 0x26; break; case UIKeyboardHIDUsageKeypadNumLock: keyCode = 0x90; break; case UIKeyboardHIDUsageKeypadSlash: keyCode = 0x6F; break; case UIKeyboardHIDUsageKeypadAsterisk: keyCode = 0x6A; break; case UIKeyboardHIDUsageKeypadHyphen: keyCode = 0x6D; break; case UIKeyboardHIDUsageKeypadPlus: keyCode = 0x6B; break; case UIKeyboardHIDUsageKeypadEnter: keyCode = 0x0D; // FIXME: Is this correct? break; case UIKeyboardHIDUsageKeypadPeriod: keyCode = 0x6E; break; case UIKeyboardHIDUsageKeyboardNonUSBackslash: keyCode = 0xE2; break; case UIKeyboardHIDUsageKeypadComma: keyCode = 0x6C; break; case UIKeyboardHIDUsageKeyboardCancel: keyCode = 0x03; break; case UIKeyboardHIDUsageKeyboardClear: keyCode = 0x0C; break; case UIKeyboardHIDUsageKeyboardCrSelOrProps: keyCode = 0xF7; break; case UIKeyboardHIDUsageKeyboardExSel: keyCode = 0xF8; break; case UIKeyboardHIDUsageKeyboardLeftGUI: keyCode = 0x5B; break; case UIKeyboardHIDUsageKeyboardLeftControl: keyCode = 0xA2; break; case UIKeyboardHIDUsageKeyboardLeftShift: keyCode = 0xA0; break; case UIKeyboardHIDUsageKeyboardLeftAlt: keyCode = 0xA4; break; case UIKeyboardHIDUsageKeyboardRightGUI: keyCode = 0x5C; break; case UIKeyboardHIDUsageKeyboardRightControl: keyCode = 0xA3; break; case UIKeyboardHIDUsageKeyboardRightShift: keyCode = 0xA1; break; case UIKeyboardHIDUsageKeyboardRightAlt: keyCode = 0xA5; break; default: NSLog(@"Unhandled HID usage: %lu", (unsigned long)key.keyCode); assert(0); return false; } } LiSendKeyboardEvent(0x8000 | keyCode, down ? KEY_ACTION_DOWN : KEY_ACTION_UP, modifierFlags); return true; } + (struct KeyEvent)translateKeyEvent:(unichar)inputChar withModifierFlags:(UIKeyModifierFlags)modifierFlags { struct KeyEvent event; event.keycode = 0; event.modifier = 0; event.modifierKeycode = 0; switch (modifierFlags) { case UIKeyModifierAlphaShift: case UIKeyModifierShift: [KeyboardSupport addShiftModifier:&event]; break; case UIKeyModifierControl: [KeyboardSupport addControlModifier:&event]; break; case UIKeyModifierCommand: [KeyboardSupport addMetaModifier:&event]; break; case UIKeyModifierAlternate: [KeyboardSupport addAltModifier:&event]; break; case UIKeyModifierNumericPad: break; } if (inputChar >= 0x30 && inputChar <= 0x39) { // Numbers 0-9 event.keycode = inputChar; } else if (inputChar >= 0x41 && inputChar <= 0x5A) { // Capital letters event.keycode = inputChar; [KeyboardSupport addShiftModifier:&event]; } else if (inputChar >= 0x61 && inputChar <= 0x7A) { // Lower case letters event.keycode = inputChar - (0x61 - 0x41); } switch (inputChar) { case ' ': // Spacebar event.keycode = 0x20; break; case '-': // Hyphen '-' event.keycode = 0xBD; break; case '/': // Forward slash '/' event.keycode = 0xBF; break; case ':': // Colon ':' event.keycode = 0xBA; [KeyboardSupport addShiftModifier:&event]; break; case ';': // Semi-colon ';' event.keycode = 0xBA; break; case '(': // Open parenthesis '(' event.keycode = 0x39; // '9' [KeyboardSupport addShiftModifier:&event]; break; case ')': // Close parenthesis ')' event.keycode = 0x30; // '0' [KeyboardSupport addShiftModifier:&event]; break; case '$': // Dollar sign '$' event.keycode = 0x34; // '4' [KeyboardSupport addShiftModifier:&event]; break; case '&': // Ampresand '&' event.keycode = 0x37; // '7' [KeyboardSupport addShiftModifier:&event]; break; case '@': // At-sign '@' event.keycode = 0x32; // '2' [KeyboardSupport addShiftModifier:&event]; break; case '"': event.keycode = 0xDE; [KeyboardSupport addShiftModifier:&event]; break; case '\'': event.keycode = 0xDE; break; case '!': event.keycode = 0x31; // '1' [KeyboardSupport addShiftModifier:&event]; break; case '?': event.keycode = 0xBF; // '/' [KeyboardSupport addShiftModifier:&event]; break; case ',': event.keycode = 0xBC; break; case '<': event.keycode = 0xBC; [KeyboardSupport addShiftModifier:&event]; break; case '.': event.keycode = 0xBE; break; case '>': event.keycode = 0xBE; [KeyboardSupport addShiftModifier:&event]; break; case '[': event.keycode = 0xDB; break; case ']': event.keycode = 0xDD; break; case '{': event.keycode = 0xDB; [KeyboardSupport addShiftModifier:&event]; break; case '}': event.keycode = 0xDD; [KeyboardSupport addShiftModifier:&event]; break; case '#': event.keycode = 0x33; // '3' [KeyboardSupport addShiftModifier:&event]; break; case '%': event.keycode = 0x35; // '5' [KeyboardSupport addShiftModifier:&event]; break; case '^': event.keycode = 0x36; // '6' [KeyboardSupport addShiftModifier:&event]; break; case '*': event.keycode = 0x38; // '8' [KeyboardSupport addShiftModifier:&event]; break; case '+': event.keycode = 0xBB; [KeyboardSupport addShiftModifier:&event]; break; case '=': event.keycode = 0xBB; break; case '_': event.keycode = 0xBD; [KeyboardSupport addShiftModifier:&event]; break; case '\\': event.keycode = 0xDC; break; case '|': event.keycode = 0xDC; [KeyboardSupport addShiftModifier:&event]; break; case '~': event.keycode = 0xC0; [KeyboardSupport addShiftModifier:&event]; break; case '`': event.keycode = 0xC0; break; case '\t': event.keycode = 0x09; break; default: break; } return event; } + (void) addShiftModifier:(struct KeyEvent*)event { event->modifier = MODIFIER_SHIFT; event->modifierKeycode = 0x10; } + (void) addControlModifier:(struct KeyEvent*)event { event->modifier = MODIFIER_CTRL; event->modifierKeycode = 0x11; } + (void) addMetaModifier:(struct KeyEvent*)event { event->modifier = MODIFIER_META; event->modifierKeycode = 0x5B; } + (void) addAltModifier:(struct KeyEvent*)event { event->modifier = MODIFIER_ALT; event->modifierKeycode = 0x12; } @end