// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you 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. package rdpclient.adapter; import java.awt.event.KeyEvent; import streamer.BaseElement; import streamer.ByteBuffer; import streamer.Link; import common.KeyOrder; public class AwtRdpKeyboardAdapter extends BaseElement { /** * Absence of this flag indicates a key-down event, while its presence * indicates a key-release event. */ public static final int FASTPATH_INPUT_KBDFLAGS_RELEASE = 0x01; /** * Keystroke message contains an extended scancode. For enhanced 101-key and * 102-key keyboards, extended keys include the right ALT and right CTRL keys * on the main section of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE * DOWN and ARROW keys in the clusters to the left of the numeric keypad; and * the Divide ("/") and ENTER keys in the numeric keypad. */ public static final int FASTPATH_INPUT_KBDFLAGS_EXTENDED = 0x02; public static final int FASTPATH_INPUT_EVENT_SCANCODE = 0; public AwtRdpKeyboardAdapter(String id) { super(id); } @Override public void handleData(ByteBuffer buf, Link link) { if (verbose) System.out.println("[" + this + "] INFO: Data received: " + buf + "."); KeyOrder order = (KeyOrder)buf.getOrder(); buf.unref(); ByteBuffer outBuf = new ByteBuffer(2, true); int scanCode = map_en_us(order.event); // eventHeader (1 byte): An 8-bit, unsigned integer. The format of this // field is the same as the eventHeader byte field described in section // 2.2.8.1.2.2. The eventCode bitfield (3 bits in size) MUST be set to // FASTPATH_INPUT_EVENT_SCANCODE (0). The eventFlags bitfield (5 bits in // size) contains flags describing the keyboard event. outBuf.writeByte((scanCode >> 8) | (FASTPATH_INPUT_EVENT_SCANCODE << 5) | ((order.pressed) ? 0 : FASTPATH_INPUT_KBDFLAGS_RELEASE)); // keyCode (1 byte): An 8-bit, unsigned integer. The scancode of the key // which triggered the event. outBuf.writeByte(scanCode); // Push buffer to one pad only, so it can be modified without copying of // data pushDataToPad(STDOUT, outBuf); } /** * Return key scan code (in lower byte) and extended flags (in second byte). */ private int map_en_us(KeyEvent event) { // Also set extended key flag when necessary. // For enhanced 101-key and 102-key keyboards, extended keys include the // right ALT and right CTRL keys on the main section of the keyboard; the // INS, DEL, HOME, END, PAGE UP, PAGE DOWN and ARROW keys in the clusters to // the left of the numeric keypad; and the Divide ("/") and ENTER keys in // the numeric keypad. switch (event.getKeyCode()) { // Functional keys case KeyEvent.VK_ESCAPE: return 1; case KeyEvent.VK_F1: return 59; case KeyEvent.VK_F2: return 60; case KeyEvent.VK_F3: return 61; case KeyEvent.VK_F4: return 62; case KeyEvent.VK_F5: return 63; case KeyEvent.VK_F6: return 64; case KeyEvent.VK_F7: return 65; case KeyEvent.VK_F8: return 66; case KeyEvent.VK_F9: return 67; case KeyEvent.VK_F10: return 68; case KeyEvent.VK_F11: return 87; case KeyEvent.VK_F12: return 88; // Row #1 case KeyEvent.VK_BACK_QUOTE: return 41; case KeyEvent.VK_1: return 2; case KeyEvent.VK_2: return 3; case KeyEvent.VK_3: return 4; case KeyEvent.VK_4: return 5; case KeyEvent.VK_5: return 6; case KeyEvent.VK_6: return 7; case KeyEvent.VK_7: return 8; case KeyEvent.VK_8: return 9; case KeyEvent.VK_9: return 10; case KeyEvent.VK_0: return 11; case KeyEvent.VK_MINUS: return 12; case KeyEvent.VK_EQUALS: return 13; case KeyEvent.VK_BACK_SPACE: return 14; // Row #2 case KeyEvent.VK_TAB: return 15; case KeyEvent.VK_Q: return 16; case KeyEvent.VK_W: return 17; case KeyEvent.VK_E: return 18; case KeyEvent.VK_R: return 19; case KeyEvent.VK_T: return 20; case KeyEvent.VK_Y: return 21; case KeyEvent.VK_U: return 22; case KeyEvent.VK_I: return 23; case KeyEvent.VK_O: return 24; case KeyEvent.VK_P: return 25; case KeyEvent.VK_OPEN_BRACKET: return 26; case KeyEvent.VK_CLOSE_BRACKET: return 27; case KeyEvent.VK_ENTER: switch (event.getKeyLocation()) { default: case KeyEvent.KEY_LOCATION_STANDARD: return 28; case KeyEvent.KEY_LOCATION_NUMPAD: return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 28; } // Row #3 case KeyEvent.VK_CAPS_LOCK: return 58; case KeyEvent.VK_A: return 30; case KeyEvent.VK_S: return 31; case KeyEvent.VK_D: return 32; case KeyEvent.VK_F: return 33; case KeyEvent.VK_G: return 34; case KeyEvent.VK_H: return 35; case KeyEvent.VK_J: return 36; case KeyEvent.VK_K: return 37; case KeyEvent.VK_L: return 38; case KeyEvent.VK_SEMICOLON: return 39; case KeyEvent.VK_QUOTE: return 40; // Row #4 case KeyEvent.VK_SHIFT: switch (event.getKeyLocation()) { default: case KeyEvent.KEY_LOCATION_LEFT: return 42; case KeyEvent.KEY_LOCATION_RIGHT: return 54; } case KeyEvent.VK_BACK_SLASH: return 43; case KeyEvent.VK_Z: return 44; case KeyEvent.VK_X: return 45; case KeyEvent.VK_C: return 46; case KeyEvent.VK_V: return 47; case KeyEvent.VK_B: return 48; case KeyEvent.VK_N: return 49; case KeyEvent.VK_M: return 50; case KeyEvent.VK_COMMA: return 51; case KeyEvent.VK_PERIOD: return 52; case KeyEvent.VK_SLASH: return 53; // // Bottom row case KeyEvent.VK_CONTROL: switch (event.getKeyLocation()) { default: case KeyEvent.KEY_LOCATION_LEFT: return 29; case KeyEvent.KEY_LOCATION_RIGHT: return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 29; } case KeyEvent.VK_WINDOWS: switch (event.getKeyLocation()) { default: case KeyEvent.KEY_LOCATION_LEFT: return 91; case KeyEvent.KEY_LOCATION_RIGHT: return 92; } case KeyEvent.VK_ALT: switch (event.getKeyLocation()) { default: case KeyEvent.KEY_LOCATION_LEFT: return 56; case KeyEvent.KEY_LOCATION_RIGHT: return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 56; } case KeyEvent.VK_ALT_GRAPH: return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 56; case KeyEvent.VK_SPACE: return 57; case KeyEvent.VK_CONTEXT_MENU: return 93; // // Special keys case KeyEvent.VK_PRINTSCREEN: return 55; case KeyEvent.VK_SCROLL_LOCK: return 70; case KeyEvent.VK_PAUSE: return 29; // Text navigation keys case KeyEvent.VK_INSERT: return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 82; case KeyEvent.VK_HOME: return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 71; case KeyEvent.VK_PAGE_UP: return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 73; case KeyEvent.VK_DELETE: return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 83; case KeyEvent.VK_END: return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 79; case KeyEvent.VK_PAGE_DOWN: return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 81; // Cursor keys case KeyEvent.VK_UP: return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 72; case KeyEvent.VK_LEFT: return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 75; case KeyEvent.VK_DOWN: return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 80; case KeyEvent.VK_RIGHT: return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 77; // Keypad case KeyEvent.VK_NUM_LOCK: return 69; case KeyEvent.VK_DIVIDE: return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 53; case KeyEvent.VK_MULTIPLY: return 55; case KeyEvent.VK_SUBTRACT: return 74; case KeyEvent.VK_ADD: return 78; case KeyEvent.VK_NUMPAD7: return 71; case KeyEvent.VK_NUMPAD8: return 72; case KeyEvent.VK_NUMPAD9: return 73; case KeyEvent.VK_NUMPAD4: return 75; case KeyEvent.VK_NUMPAD5: return 76; case KeyEvent.VK_NUMPAD6: return 77; case KeyEvent.VK_NUMPAD1: return 79; case KeyEvent.VK_NUMPAD2: return 80; case KeyEvent.VK_NUMPAD3: return 81; case KeyEvent.VK_NUMPAD0: return 82; case KeyEvent.VK_DECIMAL: return 83; default: System.err.println("Key is not mapped: " + event + "."); return event.getKeyCode(); } } }