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, &copy);
 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, &copy);
 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 }