1/* 2 * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26#import "java_awt_event_InputEvent.h" 27#import "java_awt_event_KeyEvent.h" 28#import "LWCToolkit.h" 29 30#import "JNIUtilities.h" 31 32#import <sys/time.h> 33#import <Carbon/Carbon.h> 34 35/* 36 * Table to map typed characters to their Java virtual key equivalent and back. 37 * We use the incoming unichar (ignoring all modifiers) and try to figure out 38 * which virtual key code is appropriate. A lot of them just have direct 39 * mappings (the function keys, arrow keys, etc.) so they aren't a problem. 40 * We had to do something a little funky to catch the keys on the numeric 41 * key pad (i.e. using event mask to distinguish between period on regular 42 * keyboard and decimal on keypad). We also have to do something incredibly 43 * hokey with regards to the shifted punctuation characters. For examples, 44 * consider '&' which is usually Shift-7. For the Java key typed events, 45 * that's no problem, we just say pass the unichar. But for the 46 * KeyPressed/Released events, we need to identify the virtual key code 47 * (which roughly correspond to hardware keys) which means we are supposed 48 * to say the virtual 7 key was pressed. But how are we supposed to know 49 * when we get a punctuation char what was the real hardware key was that 50 * was pressed? Although '&' often comes from Shift-7 the keyboard can be 51 * remapped! I don't think there really is a good answer, and hopefully 52 * all good applets are only interested in logical key typed events not 53 * press/release. Meanwhile, we are hard-coding the shifted punctuation 54 * to trigger the virtual keys that are the expected ones under a standard 55 * keymapping. Looking at Windows & Mac, they don't actually do this, the 56 * Mac seems to just put the ascii code in for the shifted punctuation 57 * (which means they actually end up with bogus key codes on the Java side), 58 * Windows I can't even figure out what it's doing. 59 */ 60#define KL_STANDARD java_awt_event_KeyEvent_KEY_LOCATION_STANDARD 61#define KL_NUMPAD java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD 62#define KL_UNKNOWN java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN 63static struct _key 64{ 65 unsigned short keyCode; 66 BOOL postsTyped; 67 jint javaKeyLocation; 68 jint javaKeyCode; 69} 70const keyTable[] = 71{ 72 {0x00, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_A}, 73 {0x01, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_S}, 74 {0x02, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_D}, 75 {0x03, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_F}, 76 {0x04, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_H}, 77 {0x05, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_G}, 78 {0x06, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_Z}, 79 {0x07, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_X}, 80 {0x08, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_C}, 81 {0x09, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_V}, 82 {0x0A, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_BACK_QUOTE}, 83 {0x0B, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_B}, 84 {0x0C, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_Q}, 85 {0x0D, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_W}, 86 {0x0E, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_E}, 87 {0x0F, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_R}, 88 {0x10, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_Y}, 89 {0x11, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_T}, 90 {0x12, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_1}, 91 {0x13, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_2}, 92 {0x14, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_3}, 93 {0x15, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_4}, 94 {0x16, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_6}, 95 {0x17, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_5}, 96 {0x18, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_EQUALS}, 97 {0x19, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_9}, 98 {0x1A, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_7}, 99 {0x1B, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_MINUS}, 100 {0x1C, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_8}, 101 {0x1D, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_0}, 102 {0x1E, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_CLOSE_BRACKET}, 103 {0x1F, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_O}, 104 {0x20, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_U}, 105 {0x21, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_OPEN_BRACKET}, 106 {0x22, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_I}, 107 {0x23, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_P}, 108 {0x24, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_ENTER}, 109 {0x25, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_L}, 110 {0x26, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_J}, 111 {0x27, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_QUOTE}, 112 {0x28, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_K}, 113 {0x29, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_SEMICOLON}, 114 {0x2A, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_BACK_SLASH}, 115 {0x2B, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_COMMA}, 116 {0x2C, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_SLASH}, 117 {0x2D, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_N}, 118 {0x2E, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_M}, 119 {0x2F, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_PERIOD}, 120 {0x30, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_TAB}, 121 {0x31, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_SPACE}, 122 {0x32, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_BACK_QUOTE}, 123 {0x33, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_BACK_SPACE}, 124 {0x34, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_ENTER}, 125 {0x35, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_ESCAPE}, 126 {0x36, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, 127 {0x37, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_META}, // **** 128 {0x38, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_SHIFT}, // **** 129 {0x39, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_CAPS_LOCK}, 130 {0x3A, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_ALT}, // **** 131 {0x3B, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_CONTROL}, // **** 132 {0x3C, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, 133 {0x3D, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_ALT_GRAPH}, 134 {0x3E, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, 135 {0x3F, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, // the 'fn' key on PowerBooks 136 {0x40, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F17}, 137 {0x41, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_DECIMAL}, 138 {0x42, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, 139 {0x43, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_MULTIPLY}, 140 {0x44, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, 141 {0x45, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_ADD}, 142 {0x46, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, 143 {0x47, NO, KL_NUMPAD, java_awt_event_KeyEvent_VK_CLEAR}, 144 {0x48, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, 145 {0x49, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, 146 {0x4A, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, 147 {0x4B, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_DIVIDE}, 148 {0x4C, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_ENTER}, 149 {0x4D, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, 150 {0x4E, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_SUBTRACT}, 151 {0x4F, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F18}, 152 {0x50, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F19}, 153 {0x51, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_EQUALS}, 154 {0x52, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD0}, 155 {0x53, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD1}, 156 {0x54, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD2}, 157 {0x55, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD3}, 158 {0x56, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD4}, 159 {0x57, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD5}, 160 {0x58, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD6}, 161 {0x59, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD7}, 162 {0x5A, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F20}, 163 {0x5B, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD8}, 164 {0x5C, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD9}, 165 {0x5D, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_BACK_SLASH}, // This is a combo yen/backslash on JIS keyboards. 166 {0x5E, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_UNDERSCORE}, 167 {0x5F, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_COMMA}, 168 {0x60, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F5}, 169 {0x61, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F6}, 170 {0x62, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F7}, 171 {0x63, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F3}, 172 {0x64, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F8}, 173 {0x65, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F9}, 174 {0x66, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_ALPHANUMERIC}, 175 {0x67, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F11}, 176 {0x68, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_KATAKANA}, 177 {0x69, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F13}, 178 {0x6A, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F16}, 179 {0x6B, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F14}, 180 {0x6C, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, 181 {0x6D, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F10}, 182 {0x6E, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, 183 {0x6F, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F12}, 184 {0x70, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, 185 {0x71, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F15}, 186 {0x72, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_HELP}, 187 {0x73, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_HOME}, 188 {0x74, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_PAGE_UP}, 189 {0x75, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_DELETE}, 190 {0x76, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F4}, 191 {0x77, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_END}, 192 {0x78, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F2}, 193 {0x79, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_PAGE_DOWN}, 194 {0x7A, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F1}, 195 {0x7B, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_LEFT}, 196 {0x7C, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_RIGHT}, 197 {0x7D, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_DOWN}, 198 {0x7E, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_UP}, 199 {0x7F, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, 200}; 201 202/* 203 * This table was stolen from the Windows implementation for mapping 204 * Unicode values to VK codes for dead keys. On Windows, some layouts 205 * return ASCII punctuation for dead accents, while some return spacing 206 * accent chars, so both should be listed. However, in all of the 207 * keyboard layouts I tried only the Unicode values are used. 208 */ 209struct CharToVKEntry { 210 UniChar c; 211 jint javaKey; 212}; 213static const struct CharToVKEntry charToDeadVKTable[] = { 214 {0x0060, java_awt_event_KeyEvent_VK_DEAD_GRAVE}, 215 {0x00B4, java_awt_event_KeyEvent_VK_DEAD_ACUTE}, 216 {0x0384, java_awt_event_KeyEvent_VK_DEAD_ACUTE}, // Unicode "GREEK TONOS" -- Greek keyboard, semicolon key 217 {0x005E, java_awt_event_KeyEvent_VK_DEAD_CIRCUMFLEX}, 218 {0x007E, java_awt_event_KeyEvent_VK_DEAD_TILDE}, 219 {0x02DC, java_awt_event_KeyEvent_VK_DEAD_TILDE}, // Unicode "SMALL TILDE" 220 {0x00AF, java_awt_event_KeyEvent_VK_DEAD_MACRON}, 221 {0x02D8, java_awt_event_KeyEvent_VK_DEAD_BREVE}, 222 {0x02D9, java_awt_event_KeyEvent_VK_DEAD_ABOVEDOT}, 223 {0x00A8, java_awt_event_KeyEvent_VK_DEAD_DIAERESIS}, 224 {0x02DA, java_awt_event_KeyEvent_VK_DEAD_ABOVERING}, 225 {0x02DD, java_awt_event_KeyEvent_VK_DEAD_DOUBLEACUTE}, 226 {0x02C7, java_awt_event_KeyEvent_VK_DEAD_CARON}, 227 {0x00B8, java_awt_event_KeyEvent_VK_DEAD_CEDILLA}, 228 {0x02DB, java_awt_event_KeyEvent_VK_DEAD_OGONEK}, 229 {0x037A, java_awt_event_KeyEvent_VK_DEAD_IOTA}, 230 {0x309B, java_awt_event_KeyEvent_VK_DEAD_VOICED_SOUND}, 231 {0x309C, java_awt_event_KeyEvent_VK_DEAD_SEMIVOICED_SOUND}, 232 {0,0} 233}; 234 235// TODO: some constants below are part of CGS (private interfaces)... 236// for now we will look at the raw key code to determine left/right status 237// but not sure this is foolproof... 238static struct _nsKeyToJavaModifier 239{ 240 NSUInteger nsMask; 241 //NSUInteger cgsLeftMask; 242 //NSUInteger cgsRightMask; 243 unsigned short leftKeyCode; 244 unsigned short rightKeyCode; 245 jint javaExtMask; 246 jint javaMask; 247 jint javaKey; 248} 249const nsKeyToJavaModifierTable[] = 250{ 251 { 252 NSAlphaShiftKeyMask, 253 0, 254 0, 255 0, // no Java equivalent 256 0, // no Java equivalent 257 java_awt_event_KeyEvent_VK_CAPS_LOCK 258 }, 259 { 260 NSShiftKeyMask, 261 //kCGSFlagsMaskAppleShiftKey, 262 //kCGSFlagsMaskAppleRightShiftKey, 263 56, 264 60, 265 java_awt_event_InputEvent_SHIFT_DOWN_MASK, 266 java_awt_event_InputEvent_SHIFT_MASK, 267 java_awt_event_KeyEvent_VK_SHIFT 268 }, 269 { 270 NSControlKeyMask, 271 //kCGSFlagsMaskAppleControlKey, 272 //kCGSFlagsMaskAppleRightControlKey, 273 59, 274 62, 275 java_awt_event_InputEvent_CTRL_DOWN_MASK, 276 java_awt_event_InputEvent_CTRL_MASK, 277 java_awt_event_KeyEvent_VK_CONTROL 278 }, 279 { 280 NSCommandKeyMask, 281 //kCGSFlagsMaskAppleLeftCommandKey, 282 //kCGSFlagsMaskAppleRightCommandKey, 283 55, 284 54, 285 java_awt_event_InputEvent_META_DOWN_MASK, 286 java_awt_event_InputEvent_META_MASK, 287 java_awt_event_KeyEvent_VK_META 288 }, 289 { 290 NSAlternateKeyMask, 291 //kCGSFlagsMaskAppleLeftAlternateKey, 292 //kCGSFlagsMaskAppleRightAlternateKey, 293 58, 294 0, 295 java_awt_event_InputEvent_ALT_DOWN_MASK, 296 java_awt_event_InputEvent_ALT_MASK, 297 java_awt_event_KeyEvent_VK_ALT 298 }, 299 { 300 NSAlternateKeyMask, 301 0, 302 61, 303 java_awt_event_InputEvent_ALT_DOWN_MASK | java_awt_event_InputEvent_ALT_GRAPH_DOWN_MASK, 304 java_awt_event_InputEvent_ALT_MASK | java_awt_event_InputEvent_ALT_GRAPH_MASK, 305 java_awt_event_KeyEvent_VK_ALT | java_awt_event_KeyEvent_VK_ALT_GRAPH 306 }, 307 // NSNumericPadKeyMask 308 { 309 NSHelpKeyMask, 310 0, 311 0, 312 0, // no Java equivalent 313 0, // no Java equivalent 314 java_awt_event_KeyEvent_VK_HELP 315 }, 316 // NSFunctionKeyMask 317 {0, 0, 0, 0, 0, 0} 318}; 319 320static BOOL leftAltKeyPressed; 321static BOOL altGRPressed = NO; 322 323/* 324 * Almost all unicode characters just go from NS to Java with no translation. 325 * For the few exceptions, we handle it here with this small table. 326 */ 327#define ALL_NS_KEY_MODIFIERS_MASK \ 328 (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask) 329 330static struct _char { 331 NSUInteger modifier; 332 unichar nsChar; 333 unichar javaChar; 334} 335const charTable[] = { 336 // map enter on keypad to same as return key 337 {0, NSEnterCharacter, NSNewlineCharacter}, 338 339 // [3134616] return newline instead of carriage return 340 {0, NSCarriageReturnCharacter, NSNewlineCharacter}, 341 342 // "delete" means backspace in Java 343 {ALL_NS_KEY_MODIFIERS_MASK, NSDeleteCharacter, NSBackspaceCharacter}, 344 {ALL_NS_KEY_MODIFIERS_MASK, NSDeleteFunctionKey, NSDeleteCharacter}, 345 346 // back-tab is only differentiated from tab by Shift flag 347 {NSShiftKeyMask, NSBackTabCharacter, NSTabCharacter}, 348 349 {0, 0, 0} 350}; 351 352unichar NsCharToJavaChar(unichar nsChar, NSUInteger modifiers, BOOL spaceKeyTyped) 353{ 354 const struct _char *cur; 355 // Mask off just the keyboard modifiers from the event modifier mask. 356 NSUInteger testableFlags = (modifiers & ALL_NS_KEY_MODIFIERS_MASK); 357 358 // walk through table & find the match 359 for (cur = charTable; cur->nsChar != 0 ; cur++) { 360 // <rdar://Problem/3476426> Need to determine if we are looking at 361 // a plain keypress or a modified keypress. Don't adjust the 362 // character of a keypress with a modifier. 363 if (cur->nsChar == nsChar) { 364 if (cur->modifier == 0 && testableFlags == 0) { 365 // If the modifier field is 0, that means to transform 366 // this character if no additional keyboard modifiers are set. 367 // This lets ctrl-C be reported as ctrl-C and not transformed 368 // into Newline. 369 return cur->javaChar; 370 } else if (cur->modifier != 0 && 371 (testableFlags & cur->modifier) == testableFlags) 372 { 373 // Likewise, if the modifier field is nonzero, that means 374 // transform this character if only these modifiers are 375 // set in the testable flags. 376 return cur->javaChar; 377 } 378 } 379 } 380 381 if (nsChar >= NSUpArrowFunctionKey && nsChar <= NSModeSwitchFunctionKey) { 382 return java_awt_event_KeyEvent_CHAR_UNDEFINED; 383 } 384 385 // nsChar receives value 0 when SPACE key is typed. 386 if (nsChar == 0 && spaceKeyTyped == YES) { 387 return java_awt_event_KeyEvent_VK_SPACE; 388 } 389 390 // otherwise return character unchanged 391 return nsChar; 392} 393 394static unichar NsGetDeadKeyChar(unsigned short keyCode) 395{ 396 TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); 397 CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData); 398 if (uchr == nil) { return 0; } 399 const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr); 400 // Carbon modifiers should be used instead of NSEvent modifiers 401 UInt32 modifierKeyState = (GetCurrentEventKeyModifiers() >> 8) & 0xFF; 402 403 if (keyboardLayout) { 404 UInt32 deadKeyState = 0; 405 UniCharCount maxStringLength = 255; 406 UniCharCount actualStringLength = 0; 407 UniChar unicodeString[maxStringLength]; 408 409 // get the deadKeyState 410 OSStatus status = UCKeyTranslate(keyboardLayout, 411 keyCode, kUCKeyActionDown, modifierKeyState, 412 LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit, 413 &deadKeyState, 414 maxStringLength, 415 &actualStringLength, unicodeString); 416 417 if (status == noErr && deadKeyState != 0) { 418 // Press SPACE to get the dead key char 419 status = UCKeyTranslate(keyboardLayout, 420 kVK_Space, kUCKeyActionDown, 0, 421 LMGetKbdType(), 0, 422 &deadKeyState, 423 maxStringLength, 424 &actualStringLength, unicodeString); 425 426 if (status == noErr && actualStringLength > 0) { 427 return unicodeString[0]; 428 } 429 } 430 } 431 return 0; 432} 433 434/* 435 * This is the function that uses the table above to take incoming 436 * NSEvent keyCodes and translate to the Java virtual key code. 437 */ 438static void 439NsCharToJavaVirtualKeyCode(unichar ch, BOOL isDeadChar, 440 NSUInteger flags, unsigned short key, 441 jint *keyCode, jint *keyLocation, BOOL *postsTyped, 442 unichar *deadChar) 443{ 444 static size_t size = sizeof(keyTable) / sizeof(struct _key); 445 NSInteger offset; 446 447 if (isDeadChar) { 448 unichar testDeadChar = NsGetDeadKeyChar(key); 449 const struct CharToVKEntry *map; 450 for (map = charToDeadVKTable; map->c != 0; ++map) { 451 if (testDeadChar == map->c) { 452 *keyCode = map->javaKey; 453 *postsTyped = NO; 454 // TODO: use UNKNOWN here? 455 *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN; 456 *deadChar = testDeadChar; 457 return; 458 } 459 } 460 // If we got here, we keep looking for a normal key. 461 } 462 463 if ([[NSCharacterSet letterCharacterSet] characterIsMember:ch]) { 464 // key is an alphabetic character 465 unichar lower; 466 lower = tolower(ch); 467 offset = lower - 'a'; 468 if (offset >= 0 && offset <= 25) { 469 // some chars in letter set are NOT actually A-Z characters?! 470 // skip them... 471 *postsTyped = YES; 472 // do quick conversion 473 *keyCode = java_awt_event_KeyEvent_VK_A + offset; 474 *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_STANDARD; 475 return; 476 } 477 } 478 479 if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:ch]) { 480 // key is a digit 481 offset = ch - '0'; 482 // make sure in range for decimal digits 483 if (offset >= 0 && offset <= 9) { 484 jboolean numpad = ((flags & NSNumericPadKeyMask) && 485 (key > 81 && key < 93)); 486 *postsTyped = YES; 487 if (numpad) { 488 *keyCode = offset + java_awt_event_KeyEvent_VK_NUMPAD0; 489 *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD; 490 } else { 491 *keyCode = offset + java_awt_event_KeyEvent_VK_0; 492 *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_STANDARD; 493 } 494 return; 495 } 496 } 497 498 if (key < size) { 499 *postsTyped = keyTable[key].postsTyped; 500 *keyCode = keyTable[key].javaKeyCode; 501 *keyLocation = keyTable[key].javaKeyLocation; 502 } else { 503 // Should we report this? This means we've got a keyboard 504 // we don't know about... 505 *postsTyped = NO; 506 *keyCode = java_awt_event_KeyEvent_VK_UNDEFINED; 507 *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN; 508 } 509} 510 511/* 512 * This returns the java key data for the key NSEvent modifiers 513 * (after NSFlagChanged). 514 */ 515static void 516NsKeyModifiersToJavaKeyInfo(NSUInteger nsFlags, unsigned short eventKeyCode, 517 jint *javaKeyCode, 518 jint *javaKeyLocation, 519 jint *javaKeyType) 520{ 521 static NSUInteger sPreviousNSFlags = 0; 522 523 const struct _nsKeyToJavaModifier* cur; 524 NSUInteger oldNSFlags = sPreviousNSFlags; 525 NSUInteger changedNSFlags = oldNSFlags ^ nsFlags; 526 sPreviousNSFlags = nsFlags; 527 528 *javaKeyCode = java_awt_event_KeyEvent_VK_UNDEFINED; 529 *javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN; 530 *javaKeyType = java_awt_event_KeyEvent_KEY_PRESSED; 531 532 for (cur = nsKeyToJavaModifierTable; cur->nsMask != 0; ++cur) { 533 if (changedNSFlags & cur->nsMask) { 534 *javaKeyCode = cur->javaKey; 535 *javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_STANDARD; 536 // TODO: uses SPI... 537 //if (changedNSFlags & cur->cgsLeftMask) { 538 // *javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_LEFT; 539 //} else if (changedNSFlags & cur->cgsRightMask) { 540 // *javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_RIGHT; 541 //} 542 if (eventKeyCode == cur->leftKeyCode) { 543 leftAltKeyPressed = YES; 544 *javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_LEFT; 545 } else if (eventKeyCode == cur->rightKeyCode) { 546 *javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_RIGHT; 547 } else if (cur->nsMask == NSAlternateKeyMask) { 548 leftAltKeyPressed = NO; 549 continue; 550 } 551 *javaKeyType = (cur->nsMask & nsFlags) ? 552 java_awt_event_KeyEvent_KEY_PRESSED : 553 java_awt_event_KeyEvent_KEY_RELEASED; 554 break; 555 } 556 } 557} 558 559/* 560 * This returns the java modifiers for a key NSEvent. 561 */ 562jint NsKeyModifiersToJavaModifiers(NSUInteger nsFlags, BOOL isExtMods) 563{ 564 jint javaModifiers = 0; 565 const struct _nsKeyToJavaModifier* cur; 566 567 for (cur = nsKeyToJavaModifierTable; cur->nsMask != 0; ++cur) { 568 if ((cur->nsMask & nsFlags) != 0) { 569 570 if (cur->nsMask == NSAlternateKeyMask) { 571 if (leftAltKeyPressed == YES) { 572 javaModifiers |= isExtMods? cur->javaExtMask : cur->javaMask; 573 if (altGRPressed == NO) 574 break; 575 } else { 576 leftAltKeyPressed = YES; 577 altGRPressed = YES; 578 continue; 579 } 580 } 581 javaModifiers |= isExtMods ? cur->javaExtMask : cur->javaMask; 582 } 583 } 584 585 return javaModifiers; 586} 587 588/* 589 * This returns the NSEvent flags for java key modifiers. 590 */ 591NSUInteger JavaModifiersToNsKeyModifiers(jint javaModifiers, BOOL isExtMods) 592{ 593 NSUInteger nsFlags = 0; 594 const struct _nsKeyToJavaModifier* cur; 595 596 for (cur = nsKeyToJavaModifierTable; cur->nsMask != 0; ++cur) { 597 jint mask = isExtMods? cur->javaExtMask : cur->javaMask; 598 if ((mask & javaModifiers) != 0) { 599 nsFlags |= cur->nsMask; 600 } 601 } 602 603 // special case 604 jint mask = isExtMods? java_awt_event_InputEvent_ALT_GRAPH_DOWN_MASK : 605 java_awt_event_InputEvent_ALT_GRAPH_MASK; 606 607 if ((mask & javaModifiers) != 0) { 608 nsFlags |= NSAlternateKeyMask; 609 } 610 611 return nsFlags; 612} 613 614 615jint GetJavaMouseModifiers(NSUInteger modifierFlags) 616{ 617 // Mousing needs the key modifiers 618 jint modifiers = NsKeyModifiersToJavaModifiers(modifierFlags, YES); 619 620 621 /* 622 * Ask Quartz about mouse buttons state 623 */ 624 625 if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, 626 kCGMouseButtonLeft)) { 627 modifiers |= java_awt_event_InputEvent_BUTTON1_DOWN_MASK; 628 } 629 630 if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, 631 kCGMouseButtonRight)) { 632 modifiers |= java_awt_event_InputEvent_BUTTON3_DOWN_MASK; 633 } 634 635 if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, 636 kCGMouseButtonCenter)) { 637 modifiers |= java_awt_event_InputEvent_BUTTON2_DOWN_MASK; 638 } 639 640 NSInteger extraButton = 3; 641 for (; extraButton < gNumberOfButtons; extraButton++) { 642 if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, 643 extraButton)) { 644 modifiers |= gButtonDownMasks[extraButton]; 645 } 646 } 647 648 return modifiers; 649} 650 651jlong UTC(NSEvent *event) { 652 struct timeval tv; 653 if (gettimeofday(&tv, NULL) == 0) { 654 long long sec = (long long)tv.tv_sec; 655 return (sec*1000) + (tv.tv_usec/1000); 656 } 657 return 0; 658} 659 660JNIEXPORT void JNICALL 661Java_java_awt_AWTEvent_nativeSetSource 662 (JNIEnv *env, jobject self, jobject newSource) 663{ 664} 665 666/* 667 * Class: sun_lwawt_macosx_NSEvent 668 * Method: nsToJavaModifiers 669 * Signature: (II)I 670 */ 671JNIEXPORT jint JNICALL 672Java_sun_lwawt_macosx_NSEvent_nsToJavaModifiers 673(JNIEnv *env, jclass cls, jint modifierFlags) 674{ 675 jint jmodifiers = 0; 676 677JNI_COCOA_ENTER(env); 678 679 jmodifiers = GetJavaMouseModifiers(modifierFlags); 680 681JNI_COCOA_EXIT(env); 682 683 return jmodifiers; 684} 685 686/* 687 * Class: sun_lwawt_macosx_NSEvent 688 * Method: nsToJavaKeyInfo 689 * Signature: ([I[I)Z 690 */ 691JNIEXPORT jboolean JNICALL 692Java_sun_lwawt_macosx_NSEvent_nsToJavaKeyInfo 693(JNIEnv *env, jclass cls, jintArray inData, jintArray outData) 694{ 695 BOOL postsTyped = NO; 696 697JNI_COCOA_ENTER(env); 698 699 jboolean copy = JNI_FALSE; 700 jint *data = (*env)->GetIntArrayElements(env, inData, ©); 701 CHECK_NULL_RETURN(data, postsTyped); 702 703 // in = [testChar, testDeadChar, modifierFlags, keyCode] 704 jchar testChar = (jchar)data[0]; 705 BOOL isDeadChar = (data[1] != 0); 706 jint modifierFlags = data[2]; 707 jshort keyCode = (jshort)data[3]; 708 709 jint jkeyCode = java_awt_event_KeyEvent_VK_UNDEFINED; 710 jint jkeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN; 711 jint testDeadChar = 0; 712 713 NsCharToJavaVirtualKeyCode((unichar)testChar, isDeadChar, 714 (NSUInteger)modifierFlags, (unsigned short)keyCode, 715 &jkeyCode, &jkeyLocation, &postsTyped, 716 (unichar *) &testDeadChar); 717 718 // out = [jkeyCode, jkeyLocation, deadChar]; 719 (*env)->SetIntArrayRegion(env, outData, 0, 1, &jkeyCode); 720 (*env)->SetIntArrayRegion(env, outData, 1, 1, &jkeyLocation); 721 (*env)->SetIntArrayRegion(env, outData, 2, 1, &testDeadChar); 722 723 (*env)->ReleaseIntArrayElements(env, inData, data, 0); 724 725JNI_COCOA_EXIT(env); 726 727 return postsTyped; 728} 729 730/* 731 * Class: sun_lwawt_macosx_NSEvent 732 * Method: nsKeyModifiersToJavaKeyInfo 733 * Signature: ([I[I)V 734 */ 735JNIEXPORT void JNICALL 736Java_sun_lwawt_macosx_NSEvent_nsKeyModifiersToJavaKeyInfo 737(JNIEnv *env, jclass cls, jintArray inData, jintArray outData) 738{ 739JNI_COCOA_ENTER(env); 740 741 jboolean copy = JNI_FALSE; 742 jint *data = (*env)->GetIntArrayElements(env, inData, ©); 743 CHECK_NULL(data); 744 745 // in = [modifierFlags, keyCode] 746 jint modifierFlags = data[0]; 747 jshort keyCode = (jshort)data[1]; 748 749 jint jkeyCode = java_awt_event_KeyEvent_VK_UNDEFINED; 750 jint jkeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN; 751 jint jkeyType = java_awt_event_KeyEvent_KEY_PRESSED; 752 753 NsKeyModifiersToJavaKeyInfo(modifierFlags, 754 keyCode, 755 &jkeyCode, 756 &jkeyLocation, 757 &jkeyType); 758 759 // out = [jkeyCode, jkeyLocation, jkeyType]; 760 (*env)->SetIntArrayRegion(env, outData, 0, 1, &jkeyCode); 761 (*env)->SetIntArrayRegion(env, outData, 1, 1, &jkeyLocation); 762 (*env)->SetIntArrayRegion(env, outData, 2, 1, &jkeyType); 763 764 (*env)->ReleaseIntArrayElements(env, inData, data, 0); 765 766JNI_COCOA_EXIT(env); 767} 768 769/* 770 * Class: sun_lwawt_macosx_NSEvent 771 * Method: nsToJavaChar 772 * Signature: (CI)C 773 */ 774JNIEXPORT jint JNICALL 775Java_sun_lwawt_macosx_NSEvent_nsToJavaChar 776(JNIEnv *env, jclass cls, jchar nsChar, jint modifierFlags, jboolean spaceKeyTyped) 777{ 778 jchar javaChar = 0; 779 780JNI_COCOA_ENTER(env); 781 782 javaChar = NsCharToJavaChar(nsChar, modifierFlags, spaceKeyTyped); 783 784JNI_COCOA_EXIT(env); 785 786 return javaChar; 787} 788