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 javaExtMask;
 248     jint javaMask;
 249     jint javaKey;
 250 }
 251 const nsKeyToJavaModifierTable[] =
 252 {
 253     {
 254         NSAlphaShiftKeyMask,
 255         0,
 256         0,
 257         0, // no Java equivalent
 258         0, // no Java equivalent
 259         java_awt_event_KeyEvent_VK_CAPS_LOCK
 260     },
 261     {
 262         NSShiftKeyMask,
 263         //kCGSFlagsMaskAppleShiftKey,
 264         //kCGSFlagsMaskAppleRightShiftKey,
 265         56,
 266         60,
 267         java_awt_event_InputEvent_SHIFT_DOWN_MASK,
 268         java_awt_event_InputEvent_SHIFT_MASK,
 269         java_awt_event_KeyEvent_VK_SHIFT
 270     },
 271     {
 272         NSControlKeyMask,
 273         //kCGSFlagsMaskAppleControlKey,
 274         //kCGSFlagsMaskAppleRightControlKey,
 275         59,
 276         62,
 277         java_awt_event_InputEvent_CTRL_DOWN_MASK,
 278         java_awt_event_InputEvent_CTRL_MASK,
 279         java_awt_event_KeyEvent_VK_CONTROL
 280     },
 281     {
 282         NSAlternateKeyMask,
 283         //kCGSFlagsMaskAppleLeftAlternateKey,
 284         //kCGSFlagsMaskAppleRightAlternateKey,
 285         58,
 286         61,
 287         java_awt_event_InputEvent_ALT_DOWN_MASK,
 288         java_awt_event_InputEvent_ALT_MASK,
 289         java_awt_event_KeyEvent_VK_ALT
 290     },
 291     {
 292         NSCommandKeyMask,
 293         //kCGSFlagsMaskAppleLeftCommandKey,
 294         //kCGSFlagsMaskAppleRightCommandKey,
 295         55,
 296         54,
 297         java_awt_event_InputEvent_META_DOWN_MASK,
 298         java_awt_event_InputEvent_META_MASK,
 299         java_awt_event_KeyEvent_VK_META
 300     },
 301     // NSNumericPadKeyMask
 302     {
 303         NSHelpKeyMask,
 304         0,
 305         0,
 306         0, // no Java equivalent
 307         0, // no Java equivalent
 308         java_awt_event_KeyEvent_VK_HELP
 309     },
 310     // NSFunctionKeyMask
 311     {0, 0, 0, 0, 0, 0}
 312 };
 313 
 314 /*
 315  * Almost all unicode characters just go from NS to Java with no translation.
 316  *  For the few exceptions, we handle it here with this small table.
 317  */
 318 #define ALL_NS_KEY_MODIFIERS_MASK \
 319     (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask)
 320 
 321 static struct _char {
 322     NSUInteger modifier;
 323     unichar nsChar;
 324     unichar javaChar;
 325 }
 326 const charTable[] = {
 327     // map enter on keypad to same as return key
 328     {0,                         NSEnterCharacter,          NSNewlineCharacter},
 329 
 330     // [3134616] return newline instead of carriage return
 331     {0,                         NSCarriageReturnCharacter, NSNewlineCharacter},
 332 
 333     // "delete" means backspace in Java
 334     {ALL_NS_KEY_MODIFIERS_MASK, NSDeleteCharacter,         NSBackspaceCharacter},
 335     {ALL_NS_KEY_MODIFIERS_MASK, NSDeleteFunctionKey,       NSDeleteCharacter},
 336 
 337     // back-tab is only differentiated from tab by Shift flag
 338     {NSShiftKeyMask,            NSBackTabCharacter,        NSTabCharacter},
 339 
 340     {0, 0, 0}
 341 };
 342 
 343 static unichar
 344 NsCharToJavaChar(unichar nsChar, NSUInteger modifiers)
 345 {
 346     const struct _char *cur;
 347     // Mask off just the keyboard modifiers from the event modifier mask.
 348     NSUInteger testableFlags = (modifiers & ALL_NS_KEY_MODIFIERS_MASK);
 349 
 350     // walk through table & find the match
 351     for (cur = charTable; cur->nsChar != 0 ; cur++) {
 352         // <rdar://Problem/3476426> Need to determine if we are looking at
 353         // a plain keypress or a modified keypress.  Don't adjust the
 354         // character of a keypress with a modifier.
 355         if (cur->nsChar == nsChar) {
 356             if (cur->modifier == 0 && testableFlags == 0) {
 357                 // If the modifier field is 0, that means to transform
 358                 // this character if no additional keyboard modifiers are set.
 359                 // This lets ctrl-C be reported as ctrl-C and not transformed
 360                 // into Newline.
 361                 return cur->javaChar;
 362             } else if (cur->modifier != 0 &&
 363                        (testableFlags & cur->modifier) == testableFlags)
 364             {
 365                 // Likewise, if the modifier field is nonzero, that means
 366                 // transform this character if only these modifiers are
 367                 // set in the testable flags.
 368                 return cur->javaChar;
 369             }
 370         }
 371     }
 372 
 373     if (nsChar >= NSUpArrowFunctionKey && nsChar <= NSModeSwitchFunctionKey) {
 374         return java_awt_event_KeyEvent_CHAR_UNDEFINED;
 375     }
 376 
 377     // otherwise return character unchanged
 378     return nsChar;
 379 }
 380 
 381 /*
 382  * This is the function that uses the table above to take incoming
 383  * NSEvent keyCodes and translate to the Java virtual key code.
 384  */
 385 static void
 386 NsCharToJavaVirtualKeyCode(unichar ch, unichar deadChar,
 387                            NSUInteger flags, unsigned short key,
 388                            jint *keyCode, jint *keyLocation, BOOL *postsTyped)
 389 {
 390     static size_t size = sizeof(keyTable) / sizeof(struct _key);
 391     NSInteger offset;
 392 
 393     if (deadChar) {
 394         const struct CharToVKEntry *map;
 395         for (map = charToDeadVKTable; map->c != 0; ++map) {
 396             if (deadChar == map->c) {
 397                 *keyCode = map->javaKey;
 398                 *postsTyped = NO;
 399                 // TODO: use UNKNOWN here?
 400                 *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;
 401                 return;
 402             }
 403         }
 404         // If we got here, we keep looking for a normal key.
 405     }
 406 
 407     if ([[NSCharacterSet letterCharacterSet] characterIsMember:ch]) {
 408         // key is an alphabetic character
 409         unichar lower;
 410         lower = tolower(ch);
 411         offset = lower - 'a';
 412         if (offset >= 0 && offset <= 25) {
 413             // some chars in letter set are NOT actually A-Z characters?!
 414             // skip them...
 415             *postsTyped = YES;
 416             // do quick conversion
 417             *keyCode = java_awt_event_KeyEvent_VK_A + offset;
 418             *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_STANDARD;
 419             return;
 420         }
 421     }
 422 
 423     if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:ch]) {
 424         // key is a digit
 425         offset = ch - '0';
 426         // make sure in range for decimal digits
 427         if (offset >= 0 && offset <= 9)    {
 428             jboolean numpad = (flags & NSNumericPadKeyMask) != 0;
 429             *postsTyped = YES;
 430             if (numpad) {
 431                 *keyCode = offset + java_awt_event_KeyEvent_VK_NUMPAD0;
 432                 *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD;
 433             } else {
 434                 *keyCode = offset + java_awt_event_KeyEvent_VK_0;
 435                 *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_STANDARD;
 436             }
 437             return;
 438         }
 439     }
 440 
 441     if (key < size) {
 442         *postsTyped = keyTable[key].postsTyped;
 443         *keyCode = keyTable[key].javaKeyCode;
 444         *keyLocation = keyTable[key].javaKeyLocation;
 445     } else {
 446         // Should we report this? This means we've got a keyboard
 447         // we don't know about...
 448         *postsTyped = NO;
 449         *keyCode = java_awt_event_KeyEvent_VK_UNDEFINED;
 450         *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;
 451     }
 452 }
 453 
 454 /*
 455  * This returns the java key data for the key NSEvent modifiers
 456  * (after NSFlagChanged).
 457  */
 458 static void
 459 NsKeyModifiersToJavaKeyInfo(NSUInteger nsFlags, unsigned short eventKeyCode,
 460                             jint *javaKeyCode,
 461                             jint *javaKeyLocation,
 462                             jint *javaKeyType)
 463 {
 464     static NSUInteger sPreviousNSFlags = 0;
 465 
 466     const struct _nsKeyToJavaModifier* cur;
 467     NSUInteger oldNSFlags = sPreviousNSFlags;
 468     NSUInteger changedNSFlags = oldNSFlags ^ nsFlags;
 469     sPreviousNSFlags = nsFlags;
 470 
 471     *javaKeyCode = java_awt_event_KeyEvent_VK_UNDEFINED;
 472     *javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;
 473     *javaKeyType = java_awt_event_KeyEvent_KEY_PRESSED;
 474 
 475     for (cur = nsKeyToJavaModifierTable; cur->nsMask != 0; ++cur) {
 476         if (changedNSFlags & cur->nsMask) {
 477             *javaKeyCode = cur->javaKey;
 478             *javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_STANDARD;
 479             // TODO: uses SPI...
 480             //if (changedNSFlags & cur->cgsLeftMask) {
 481             //    *javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_LEFT;
 482             //} else if (changedNSFlags & cur->cgsRightMask) {
 483             //    *javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_RIGHT;
 484             //}
 485             if (eventKeyCode == cur->leftKeyCode) {
 486                 *javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_LEFT;
 487             } else if (eventKeyCode == cur->rightKeyCode) {
 488                 *javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_RIGHT;
 489             }
 490             *javaKeyType = (cur->nsMask & nsFlags) ?
 491                 java_awt_event_KeyEvent_KEY_PRESSED :
 492                 java_awt_event_KeyEvent_KEY_RELEASED;
 493             break;
 494         }
 495     }
 496 }
 497 
 498 /*
 499  * This returns the java modifiers for a key NSEvent.
 500  */
 501 jint NsKeyModifiersToJavaModifiers(NSUInteger nsFlags, BOOL isExtMods)
 502 {
 503     jint javaModifiers = 0;
 504     const struct _nsKeyToJavaModifier* cur;
 505 
 506     for (cur = nsKeyToJavaModifierTable; cur->nsMask != 0; ++cur) {
 507         if ((cur->nsMask & nsFlags) != 0) {
 508             javaModifiers |= isExtMods? cur->javaExtMask : cur->javaMask;
 509         }
 510     }
 511 
 512     return javaModifiers;
 513 }
 514 
 515 /*
 516  * This returns the NSEvent flags for java key modifiers.
 517  */
 518 NSUInteger JavaModifiersToNsKeyModifiers(jint javaModifiers, BOOL isExtMods)
 519 {
 520     NSUInteger nsFlags = 0;
 521     const struct _nsKeyToJavaModifier* cur;
 522 
 523     for (cur = nsKeyToJavaModifierTable; cur->nsMask != 0; ++cur) {
 524         jint mask = isExtMods? cur->javaExtMask : cur->javaMask; 
 525         if ((mask & javaModifiers) != 0) {
 526             nsFlags |= cur->nsMask;
 527         }
 528     }
 529 
 530     // special case
 531     jint mask = isExtMods? java_awt_event_InputEvent_ALT_GRAPH_DOWN_MASK : 
 532                            java_awt_event_InputEvent_ALT_GRAPH_MASK;
 533 
 534     if ((mask & javaModifiers) != 0) {
 535         nsFlags |= NSAlternateKeyMask;      
 536     }
 537 
 538     return nsFlags;
 539 }
 540 
 541 
 542 jint GetJavaMouseModifiers(NSInteger button, NSUInteger modifierFlags)
 543 {
 544     // Mousing needs the key modifiers
 545     jint modifiers = NsKeyModifiersToJavaModifiers(modifierFlags, YES);
 546 
 547 
 548     /*
 549      * Ask Quartz about mouse buttons state
 550      */
 551 
 552     if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,
 553                                  kCGMouseButtonLeft)) {
 554         modifiers |= java_awt_event_InputEvent_BUTTON1_DOWN_MASK;
 555     }
 556 
 557     if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,
 558                                  kCGMouseButtonRight)) {
 559         modifiers |= java_awt_event_InputEvent_BUTTON3_DOWN_MASK;
 560     }
 561 
 562     if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,
 563                                  kCGMouseButtonCenter)) {
 564         modifiers |= java_awt_event_InputEvent_BUTTON2_DOWN_MASK;
 565     }
 566 
 567     NSInteger extraButton = 3;
 568     for (; extraButton < gNumberOfButtons; extraButton++) {
 569         if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,
 570                                  extraButton)) {
 571             modifiers |= gButtonDownMasks[extraButton];
 572         }
 573     }
 574 
 575     return modifiers;
 576 }
 577 
 578 jlong UTC(NSEvent *event) {
 579     struct timeval tv;
 580     if (gettimeofday(&tv, NULL) == 0) {
 581         long long sec = (long long)tv.tv_sec;
 582         return (sec*1000) + (tv.tv_usec/1000);
 583     }
 584     return 0;
 585 }
 586 
 587 JNIEXPORT void JNICALL
 588 Java_java_awt_AWTEvent_nativeSetSource
 589     (JNIEnv *env, jobject self, jobject newSource)
 590 {
 591 }
 592 
 593 /*
 594  * Class:     sun_lwawt_macosx_event_NSEvent
 595  * Method:    nsToJavaMouseModifiers
 596  * Signature: (II)I
 597  */
 598 JNIEXPORT jint JNICALL
 599 Java_sun_lwawt_macosx_event_NSEvent_nsToJavaMouseModifiers
 600 (JNIEnv *env, jclass cls, jint buttonNumber, jint modifierFlags)
 601 {
 602     jint jmodifiers = 0;
 603 
 604 JNF_COCOA_ENTER(env);
 605 
 606     jmodifiers = GetJavaMouseModifiers(buttonNumber, modifierFlags);
 607 
 608 JNF_COCOA_EXIT(env);
 609 
 610     return jmodifiers;
 611 }
 612 
 613 /*
 614  * Class:     sun_lwawt_macosx_event_NSEvent
 615  * Method:    nsToJavaKeyModifiers
 616  * Signature: (I)I
 617  */
 618 JNIEXPORT jint JNICALL
 619 Java_sun_lwawt_macosx_event_NSEvent_nsToJavaKeyModifiers
 620 (JNIEnv *env, jclass cls, jint modifierFlags)
 621 {
 622     jint jmodifiers = 0;
 623 
 624 JNF_COCOA_ENTER(env);
 625 
 626     jmodifiers = NsKeyModifiersToJavaModifiers(modifierFlags, YES);
 627 
 628 JNF_COCOA_EXIT(env);
 629 
 630     return jmodifiers;
 631 }
 632 
 633 /*
 634  * Class:     sun_lwawt_macosx_event_NSEvent
 635  * Method:    nsToJavaKeyInfo
 636  * Signature: ([I[I)Z
 637  */
 638 JNIEXPORT jboolean JNICALL
 639 Java_sun_lwawt_macosx_event_NSEvent_nsToJavaKeyInfo
 640 (JNIEnv *env, jclass cls, jintArray inData, jintArray outData)
 641 {
 642     BOOL postsTyped = NO;
 643 
 644 JNF_COCOA_ENTER(env);
 645 
 646     jboolean copy = JNI_FALSE;
 647     jint *data = (*env)->GetIntArrayElements(env, inData, &copy);
 648 
 649     // in  = [testChar, testDeadChar, modifierFlags, keyCode]
 650     jchar testChar = (jchar)data[0];
 651     jchar testDeadChar = (jchar)data[1];
 652     jint modifierFlags = data[2];
 653     jshort keyCode = (jshort)data[3];
 654 
 655     jint jkeyCode = java_awt_event_KeyEvent_VK_UNDEFINED;
 656     jint jkeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;
 657 
 658     NsCharToJavaVirtualKeyCode((unichar)testChar, (unichar)testDeadChar,
 659                                (NSUInteger)modifierFlags, (unsigned short)keyCode,
 660                                &jkeyCode, &jkeyLocation, &postsTyped);
 661 
 662     // out = [jkeyCode, jkeyLocation];
 663     (*env)->SetIntArrayRegion(env, outData, 0, 1, &jkeyCode);
 664     (*env)->SetIntArrayRegion(env, outData, 1, 1, &jkeyLocation);
 665 
 666     (*env)->ReleaseIntArrayElements(env, inData, data, 0);
 667 
 668 JNF_COCOA_EXIT(env);
 669 
 670     return postsTyped;
 671 }
 672 
 673 /*
 674  * Class:     sun_lwawt_macosx_event_NSEvent
 675  * Method:    nsKeyModifiersToJavaKeyInfo
 676  * Signature: ([I[I)V
 677  */
 678 JNIEXPORT void JNICALL
 679 Java_sun_lwawt_macosx_event_NSEvent_nsKeyModifiersToJavaKeyInfo
 680 (JNIEnv *env, jclass cls, jintArray inData, jintArray outData)
 681 {
 682 JNF_COCOA_ENTER(env);
 683 
 684     jboolean copy = JNI_FALSE;
 685     jint *data = (*env)->GetIntArrayElements(env, inData, &copy);
 686 
 687     // in  = [modifierFlags, keyCode]
 688     jint modifierFlags = data[0];
 689     jshort keyCode = (jshort)data[1];
 690 
 691     jint jkeyCode = java_awt_event_KeyEvent_VK_UNDEFINED;
 692     jint jkeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;
 693     jint jkeyType = java_awt_event_KeyEvent_KEY_PRESSED;
 694 
 695     NsKeyModifiersToJavaKeyInfo(modifierFlags,
 696                                 keyCode,
 697                                 &jkeyCode,
 698                                 &jkeyLocation,
 699                                 &jkeyType);
 700 
 701     // out = [jkeyCode, jkeyLocation, jkeyType];
 702     (*env)->SetIntArrayRegion(env, outData, 0, 1, &jkeyCode);
 703     (*env)->SetIntArrayRegion(env, outData, 1, 1, &jkeyLocation);
 704     (*env)->SetIntArrayRegion(env, outData, 2, 1, &jkeyType);
 705 
 706     (*env)->ReleaseIntArrayElements(env, inData, data, 0);
 707 
 708 JNF_COCOA_EXIT(env);
 709 }
 710 
 711 /*
 712  * Class:     sun_lwawt_macosx_event_NSEvent
 713  * Method:    nsToJavaChar
 714  * Signature: (CI)C
 715  */
 716 JNIEXPORT jint JNICALL
 717 Java_sun_lwawt_macosx_event_NSEvent_nsToJavaChar
 718 (JNIEnv *env, jclass cls, char nsChar, jint modifierFlags)
 719 {
 720     jchar javaChar = 0;
 721     
 722 JNF_COCOA_ENTER(env);
 723     
 724     javaChar = NsCharToJavaChar(nsChar, modifierFlags);
 725 
 726 JNF_COCOA_EXIT(env);
 727     
 728     return javaChar;
 729 }