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