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