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