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, NO,  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 /*
 510  * Returns the correct java character for a key event.  Most unicode
 511  * characters don't require any fussing, but a few seem to need adjusting,
 512  * see nsCharToJavaChar.
 513  */
 514 static unichar
 515 GetJavaCharacter(NSEvent *event, unsigned int index)
 516 {
 517     unichar returnValue = java_awt_event_KeyEvent_CHAR_UNDEFINED;
 518     NSString *chars = nil;
 519     unichar testChar = 0, testDeadChar = 0;
 520     jint javaModifiers = NsKeyModifiersToJavaModifiers([event modifierFlags]);
 521 
 522     switch ([event type]) {
 523     case NSFlagsChanged:
 524         // no character for modifier keys
 525         returnValue = java_awt_event_KeyEvent_CHAR_UNDEFINED;
 526         break;
 527 
 528     case NSKeyDown:
 529     case NSKeyUp:
 530         chars = [event characters];
 531         if ([chars length] > 0) {
 532             testChar = [chars characterAtIndex:index];
 533         }
 534 
 535         if (javaModifiers == 0) {
 536             // TODO: uses SPI...
 537             //if (TSMGetDeadKeyState() != 0) {
 538             //    testDeadChar = [self deadKeyCharacter];
 539             //}
 540         }
 541 
 542         if (testChar != 0) {
 543             returnValue = NsCharToJavaChar(testChar, [event modifierFlags]);
 544         } else if (testDeadChar != 0) {
 545             returnValue = NsCharToJavaChar(testDeadChar, [event modifierFlags]);
 546         } else {
 547             returnValue = java_awt_event_KeyEvent_CHAR_UNDEFINED;
 548         }
 549         break;
 550 
 551     default:
 552         //[NSException raise:@"AWT error" format:@"Attempt to get character code from non-key event!"];
 553         break;
 554     }
 555 
 556     return returnValue;
 557 }
 558 
 559 /*
 560 static jchar
 561 GetDeadKeyCharacter(NSEvent *event)
 562 {
 563     // If the current event is not a dead key, return 0.
 564     // TODO: this uses SPI; it's an optimization but not strictly necessary
 565     //if (TSMGetDeadKeyState() == 0) {
 566     //    return 0;
 567     //}
 568 
 569     // AppKit does not track dead-key states directly, but TSM does. Even then,
 570     // it's not necessarily all that accurate, because the dead key can change
 571     // given some combination of modifier keys on certain layouts.
 572     // As a result, finding the unicode value for the front end of the dead
 573     // key is a bit of a heuristic.
 574 
 575     // This algorithm was suggested by Aki Inoue.
 576     // When you get a dead key, you need to simiulate what would happen in
 577     // the current dead-key and modifier state if the user hit the spacebar.
 578     // That will tell you the front end of the dead-key combination.
 579 
 580     unichar returnValue = 0;
 581     const UInt16 VIRTUAL_KEY_SPACE = 49;
 582     UInt32 deadKeyState = 0;
 583     UInt32 appkitFlags = [event modifierFlags];
 584     UniCharCount actualStringLength;
 585     UniChar unicodeInputString[16];
 586     TISInputSourceRef keyLayout;
 587     const void *chrData;
 588 
 589     keyLayout = TISCopyCurrentKeyboardLayoutInputSource();
 590     CFDataRef cfUchrData =
 591         TISGetInputSourceProperty(keyLayout, kTISPropertyUnicodeKeyLayoutData);
 592 
 593     if (cfUchrData == NULL) {
 594         return returnValue;
 595     }
 596 
 597     // The actual 'uchr' table is inside the CFDataRef.
 598     chrData = CFDataGetBytePtr(cfUchrData);
 599 
 600     UInt8 keyboardType = LMGetKbdType();
 601     UInt32 keyEventModifiers = 0;
 602     if (appkitFlags & NSShiftKeyMask)      keyEventModifiers |= shiftKey;
 603     if (appkitFlags & NSCommandKeyMask)    keyEventModifiers |= cmdKey;
 604     if (appkitFlags & NSAlphaShiftKeyMask) keyEventModifiers |= alphaLock;
 605     if (appkitFlags & NSControlKeyMask)    keyEventModifiers |= controlKey;
 606     if (appkitFlags & NSAlternateKeyMask)  keyEventModifiers |= optionKey;
 607 
 608     if (noErr == UCKeyTranslate(chrData,
 609         VIRTUAL_KEY_SPACE,
 610         ([event type] == NSKeyDown ? kUCKeyActionDown : kUCKeyActionUp),
 611         keyEventModifiers,
 612         keyboardType,
 613         kUCKeyTranslateNoDeadKeysMask,
 614         &deadKeyState,
 615         16,
 616         &actualStringLength,
 617         unicodeInputString))
 618     {
 619         if (actualStringLength > 0) {
 620             returnValue = unicodeInputString[0];
 621         }
 622     }
 623 
 624     return returnValue;
 625 }
 626 */
 627 
 628 
 629 // REMIND: The fix for MACOSX_PORT-539 introduces Java-level implementation
 630 // of the function below (see CPlatformResponder). Consider removing this code.
 631 
 632 void
 633 DeliverJavaKeyEvent(JNIEnv *env, NSEvent *event, jobject peer)
 634 {
 635     jint javaKeyType = java_awt_event_KeyEvent_KEY_PRESSED;
 636     jint javaKeyCode = java_awt_event_KeyEvent_VK_UNDEFINED;
 637     jint javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;
 638     NSString *chars = nil;
 639     BOOL postsTyped;
 640     unichar testChar = java_awt_event_KeyEvent_CHAR_UNDEFINED;
 641     unichar testDeadChar = 0;
 642     jint javaModifiers = 0;
 643 
 644     switch ([event type]) {
 645     case NSFlagsChanged:
 646         NsKeyModifiersToJavaKeyInfo([event modifierFlags],
 647                                     [event keyCode],
 648                                     &javaKeyCode,
 649                                     &javaKeyLocation,
 650                                     &javaKeyType);
 651         break;
 652 
 653     case NSKeyDown:
 654     case NSKeyUp:
 655         chars = [event charactersIgnoringModifiers];
 656         if ([chars length] > 0) {
 657             testChar = [chars characterAtIndex:0];
 658         }
 659 
 660         javaModifiers = NsKeyModifiersToJavaModifiers([event modifierFlags]);
 661         if (javaModifiers == 0) {
 662       // TODO: dead key chars
 663 //            testDeadChar = GetDeadKeyCharacter(event);
 664         }
 665 
 666         NsCharToJavaVirtualKeyCode(testChar, testDeadChar,
 667                                    [event modifierFlags], [event keyCode],
 668                                    &javaKeyCode, &javaKeyLocation, &postsTyped);
 669         if( !postsTyped ) {
 670             testChar = java_awt_event_KeyEvent_CHAR_UNDEFINED;
 671         }
 672 
 673         javaKeyType = ([event type] == NSKeyDown) ?
 674             java_awt_event_KeyEvent_KEY_PRESSED :
 675             java_awt_event_KeyEvent_KEY_RELEASED;
 676         break;
 677 
 678     default:
 679         //[NSException raise:@"AWT error" format:@"Attempt to get virtual key code from non-key event!"];
 680         break;
 681     }
 682 
 683     if (env != NULL) {
 684         static JNF_CLASS_CACHE(jc_CPlatformView, "sun/lwawt/macosx/CPlatformView");
 685         static JNF_MEMBER_CACHE(jm_deliverKeyEvent, jc_CPlatformView, "deliverKeyEvent", "(IICII)V");
 686         JNFCallVoidMethod(env, peer, jm_deliverKeyEvent,
 687                           javaKeyType, javaModifiers,
 688                           testChar, javaKeyCode, javaKeyLocation);
 689     }
 690 }
 691 
 692 jint GetJavaMouseModifiers(NSInteger button, NSUInteger modifierFlags)
 693 {
 694     // Mousing needs the key modifiers
 695     jint modifiers = NsKeyModifiersToJavaModifiers(modifierFlags);
 696 
 697 
 698     /*
 699      * Ask Quartz about mouse buttons state
 700      */
 701 
 702     if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,
 703                                  kCGMouseButtonLeft)) {
 704         modifiers |= java_awt_event_InputEvent_BUTTON1_DOWN_MASK;
 705     }
 706 
 707     if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,
 708                                  kCGMouseButtonRight)) {
 709         modifiers |= java_awt_event_InputEvent_BUTTON3_DOWN_MASK;
 710     }
 711 
 712     if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,
 713                                  kCGMouseButtonCenter)) {
 714         modifiers |= java_awt_event_InputEvent_BUTTON2_DOWN_MASK;
 715     }
 716 
 717     NSInteger extraButton = 3;
 718     for (; extraButton < gNumberOfButtons; extraButton++) {
 719         if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,
 720                                  extraButton)) {
 721             modifiers |= gButtonDownMasks[extraButton];
 722         }
 723     }
 724 
 725     return modifiers;
 726 }
 727 
 728 /*
 729  * Converts an NSEvent button number to a MouseEvent constant.
 730  */
 731 static jint
 732 NSButtonToJavaButton(NSInteger nsButtonNumber)
 733 {
 734     jint jbutton = java_awt_event_MouseEvent_NOBUTTON;
 735 
 736     if (nsButtonNumber == 0) { // left
 737         jbutton = java_awt_event_MouseEvent_BUTTON1;
 738     } else if (nsButtonNumber == 1) { // right
 739         jbutton = java_awt_event_MouseEvent_BUTTON3;
 740     } else if (nsButtonNumber == 2) { // middle
 741         jbutton = java_awt_event_MouseEvent_BUTTON2;
 742     }
 743 
 744     return jbutton;
 745 }
 746 
 747 
 748 static BOOL isDragging = NO;
 749 
 750 void
 751 DeliverMouseClickedEvent(JNIEnv *env, NSEvent *event, jobject peer)
 752 {
 753     NSPoint pt = [event locationInWindow];
 754     NSPoint pOnScreen = [NSEvent mouseLocation];
 755     jint etype = java_awt_event_MouseEvent_MOUSE_CLICKED;
 756     jint modifiers = GetJavaMouseModifiers([event buttonNumber], [event modifierFlags]);
 757     jint clickCount = [event clickCount];
 758     jint button = NSButtonToJavaButton([event buttonNumber]);
 759 
 760     if (env != NULL) {
 761         static JNF_CLASS_CACHE(jc_CPlatformView, "sun/lwawt/macosx/CPlatformView");
 762         static JNF_MEMBER_CACHE(jm_deliverMouseEvent, jc_CPlatformView,
 763                                 "deliverMouseEvent", "(IIIIFFFF)V");
 764         JNFCallVoidMethod(env, peer, jm_deliverMouseEvent,
 765                           etype, modifiers,
 766                           clickCount, button,
 767                           pt.x, pt.y,
 768                           pOnScreen.x, pOnScreen.y);
 769     }
 770 }
 771 
 772 /*
 773  * After every key down event, this is called to make the matching
 774  * KEY_TYPED (if this key posts those).  We use the same NSEvent for it,
 775  * but create a KEY_TYPED java event this time.
 776  * If this key doesn't post typed, we don't post the event.
 777  *
 778  * TODO: some duplicated effort here; could just fold it
 779  * into DeliverJavaKeyEvent...
 780  */
 781 static void
 782 DeliverKeyTypedEvents(JNIEnv *env, NSEvent *nsEvent, jobject peer)
 783 {
 784     if (peer == NULL) {
 785         return;
 786     }
 787 
 788     jint javaKeyCode, javaKeyLocation;
 789     BOOL postsTyped = NO;
 790     unichar testChar, testDeadChar = 0;
 791     jint javaModifiers = NsKeyModifiersToJavaModifiers([nsEvent modifierFlags]);
 792 
 793     if (javaModifiers == 0) {
 794         testDeadChar = [nsEvent deadKeyCharacter];
 795     }
 796 
 797     NSString *theChars = [nsEvent characters];
 798     unsigned i, stringLength = [theChars length];
 799 
 800     for (i = 0; i < stringLength; i++) {
 801         testChar = [theChars characterAtIndex:i];
 802         NsCharToJavaVirtualKeyCode(testChar, testDeadChar,
 803                                    [nsEvent modifierFlags], [nsEvent keyCode],
 804                                    &javaKeyCode, &javaKeyLocation, &postsTyped);
 805 
 806         if (postsTyped) {
 807             // Some keys may generate a KEY_TYPED, but we can't determine
 808             // what that character is. That's likely a bug, but for now we
 809             // just check for CHAR_UNDEFINED.
 810             unichar theChar = GetJavaCharacter(nsEvent, i);
 811             if (theChar != java_awt_event_KeyEvent_CHAR_UNDEFINED) {
 812                 if (env != NULL) {
 813                     static JNF_CLASS_CACHE(jc_CPlatformView,
 814                                            "sun/lwawt/macosx/CPlatformView");
 815                     static JNF_MEMBER_CACHE(jm_deliverKeyEvent, jc_CPlatformView,
 816                                             "deliverKeyEvent", "(IICII)V");
 817                     JNFCallVoidMethod(env, peer, jm_deliverKeyEvent,
 818                                       java_awt_event_KeyEvent_KEY_TYPED,
 819                                       javaModifiers,
 820                                       theChar,
 821                                       java_awt_event_KeyEvent_VK_UNDEFINED,
 822                                       java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN);
 823                 }
 824             }
 825         }
 826     }
 827 }
 828 
 829 /*
 830  * There are a couple of extra events that Java expects to get that don't
 831  * actually correspond to a direct NSEvent, KEY_TYPED and MOUSE_CLICKED are
 832  * both extra events that are sort of redundant with ordinary
 833  * key downs and mouse ups.  In this extra message, we take the original
 834  * input event and if necessary, cons up a special follow-on event which
 835  * we dispatch over to Java.
 836  *
 837  * For Java, keyDown's generate a KeyPressed (for each hardware key as it
 838  * goes down) and then a "logical KeyTyped" event for the key event. (So
 839  * a shift-a generates two presses, one keytyped of "A", and then two
 840  * releases).  The standard event utility function converts a key down to
 841  * a key pressed. When appropriate, we need to cons up another event
 842  * (KEY_TYPED) to follow a keyDown.
 843  *
 844  * Java expects you to send a clicked event if you got a down & up, with no
 845  * intervening drag. So in addition to the MOUSE_RELEASED event that a
 846  * mouseUp is translated to, we also have to cons up a MOUSE_CLICKED event
 847  * for that case. Mike Paquette, god of Window Server event handling,
 848  * confirmed this fact about how to determine if a mouse up event had an
 849  * intervening drag:
 850  * An initial mouse-down gets a click count of 1. Subsequent left or right
 851  * mouse-downs within the space/time tolerance limits increment the click
 852  * count.  A mouse-up will have the clickCount of the last mouseDown if
 853  * mouse is not outside the tolerance limits, but 0 otherwise.  Thus, a
 854  * down-up sequence without any intervening drag will have a click count
 855  * of 0 in the mouse-up event.  NOTE: The problem with this is that
 856  * clickCount goes to zero after some point in time. So a long, click &
 857  * hold without moving and then release the mouse doesn't create a
 858  * MOUSE_CLICK event as it should. Java AWT now tracks the drag state itself.
 859  *
 860  * As another add-on, we also check for the status of mouse-motion events
 861  * after a mouse-down, so we know whether to generate mouse-dragged events
 862  * during this down sequence.
 863  */
 864 void
 865 SendAdditionalJavaEvents(JNIEnv *env, NSEvent *nsEvent, jobject peer)
 866 {
 867     AWT_ASSERT_APPKIT_THREAD;
 868 
 869     NSEventType type = [nsEvent type];
 870     switch (type) {
 871     case NSKeyDown:
 872         break;
 873 
 874     case NSLeftMouseUp:
 875     case NSRightMouseUp:
 876     case NSOtherMouseUp:
 877         // TODO: we may need to pull in changedDragToMove here...
 878         //if (!isDragging && ([NSViewAWT changedDragToMove]==NO)) {
 879         if (!isDragging) {
 880             // got down/up pair with no dragged in between; ignores drag events
 881             // that have been morphed to move events
 882             DeliverMouseClickedEvent(env, nsEvent, peer);
 883         }
 884         break;
 885 
 886 // TODO: to be implemented...
 887 #if 0
 888     case NSLeftMouseDragged:
 889     case NSRightMouseDragged:
 890     case NSOtherMouseDragged:
 891         //
 892         // During a drag, the AppKit does not send mouseEnter and mouseExit
 893         // events.  It turns out that doing a hitTest causes the window's
 894         // view hierarchy to be locked from drawing and that, of course,
 895         // slows everything way down.  Synthesize mouseEnter and mouseExit
 896         // then forward.
 897         //
 898         NSView *hitView = [[source model] hitTest:[nsEvent locationInWindow]];
 899 
 900         if ((hitView != nil) &&
 901             ([hitView conformsToProtocol:@protocol(AWTPeerControl)]))
 902         {
 903             if (sLastMouseDraggedView == nil) {
 904                 sLastMouseDraggedView = hitView;
 905             }
 906             else if (hitView != sLastMouseDraggedView) {
 907                 // We know sLastMouseDraggedView is a AWTPeerControl.
 908                 jobject lastPeer =
 909                     [(id <AWTPeerControl>)sLastMouseDraggedView peer];
 910 
 911                 // Send mouseExit to sLastMouseDraggedView
 912                 jobject exitEvent =
 913                     makeMouseEvent(env, nsEvent, lastPeer,
 914                                    sLastMouseDraggedView,
 915                                    java_awt_event_MouseEvent_MOUSE_EXITED);
 916                 pushEventForward(exitEvent, env);
 917                 (*env)->DeleteLocalRef(env, exitEvent);
 918 
 919                 // Send mouseEnter to hitView
 920                 jobject enterEvent =
 921                     makeMouseEvent(env, nsEvent, peer, hitView,
 922                                    java_awt_event_MouseEvent_MOUSE_ENTERED);
 923                 pushEventForward(enterEvent, env);
 924 
 925                 (*env)->DeleteLocalRef(env, enterEvent);
 926 
 927                 // Set sLastMouseDraggedView = hitView
 928                 sLastMouseDraggedView = hitView;
 929             }
 930         }
 931         break;
 932 #endif
 933 
 934     default:
 935         break;
 936     }
 937 }
 938 
 939 jlong UTC(NSEvent *event) {
 940     struct timeval tv;
 941     if (gettimeofday(&tv, NULL) == 0) {
 942         long long sec = (long long)tv.tv_sec;
 943         return (sec*1000) + (tv.tv_usec/1000);
 944     }
 945     return 0;
 946 }
 947 
 948 JNIEXPORT void JNICALL
 949 Java_java_awt_AWTEvent_nativeSetSource
 950     (JNIEnv *env, jobject self, jobject newSource)
 951 {
 952 }
 953 
 954 /*
 955  * Class:     sun_lwawt_macosx_event_NSEvent
 956  * Method:    nsToJavaMouseModifiers
 957  * Signature: (II)I
 958  */
 959 JNIEXPORT jint JNICALL
 960 Java_sun_lwawt_macosx_event_NSEvent_nsToJavaMouseModifiers
 961 (JNIEnv *env, jclass cls, jint buttonNumber, jint modifierFlags)
 962 {
 963     jint jmodifiers = 0;
 964 
 965 JNF_COCOA_ENTER(env);
 966 
 967     jmodifiers = GetJavaMouseModifiers(buttonNumber, modifierFlags);
 968 
 969 JNF_COCOA_EXIT(env);
 970 
 971     return jmodifiers;
 972 }
 973 
 974 /*
 975  * Class:     sun_lwawt_macosx_event_NSEvent
 976  * Method:    nsToJavaKeyModifiers
 977  * Signature: (I)I
 978  */
 979 JNIEXPORT jint JNICALL
 980 Java_sun_lwawt_macosx_event_NSEvent_nsToJavaKeyModifiers
 981 (JNIEnv *env, jclass cls, jint modifierFlags)
 982 {
 983     jint jmodifiers = 0;
 984 
 985 JNF_COCOA_ENTER(env);
 986 
 987     jmodifiers = NsKeyModifiersToJavaModifiers(modifierFlags);
 988 
 989 JNF_COCOA_EXIT(env);
 990 
 991     return jmodifiers;
 992 }
 993 
 994 /*
 995  * Class:     sun_lwawt_macosx_event_NSEvent
 996  * Method:    nsToJavaKeyInfo
 997  * Signature: ([I[I)Z
 998  */
 999 JNIEXPORT jboolean JNICALL
1000 Java_sun_lwawt_macosx_event_NSEvent_nsToJavaKeyInfo
1001 (JNIEnv *env, jclass cls, jintArray inData, jintArray outData)
1002 {
1003     BOOL postsTyped = NO;
1004 
1005 JNF_COCOA_ENTER(env);
1006 
1007     jboolean copy = JNI_FALSE;
1008     jint *data = (*env)->GetIntArrayElements(env, inData, &copy);
1009 
1010     // in  = [testChar, testDeadChar, modifierFlags, keyCode]
1011     jchar testChar = (jchar)data[0];
1012     jchar testDeadChar = (jchar)data[1];
1013     jint modifierFlags = data[2];
1014     jshort keyCode = (jshort)data[3];
1015 
1016     jint jkeyCode = java_awt_event_KeyEvent_VK_UNDEFINED;
1017     jint jkeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;
1018 
1019     NsCharToJavaVirtualKeyCode((unichar)testChar, (unichar)testDeadChar,
1020                                (NSUInteger)modifierFlags, (unsigned short)keyCode,
1021                                &jkeyCode, &jkeyLocation, &postsTyped);
1022 
1023     // out = [jkeyCode, jkeyLocation];
1024     (*env)->SetIntArrayRegion(env, outData, 0, 1, &jkeyCode);
1025     (*env)->SetIntArrayRegion(env, outData, 1, 1, &jkeyLocation);
1026     
1027     (*env)->ReleaseIntArrayElements(env, inData, data, 0);
1028     
1029 JNF_COCOA_EXIT(env);
1030 
1031     return postsTyped;
1032 }
1033 
1034 /*
1035  * Class:     sun_lwawt_macosx_event_NSEvent
1036  * Method:    nsKeyModifiersToJavaKeyInfo
1037  * Signature: ([I[I)V
1038  */
1039 JNIEXPORT void JNICALL
1040 Java_sun_lwawt_macosx_event_NSEvent_nsKeyModifiersToJavaKeyInfo
1041 (JNIEnv *env, jclass cls, jintArray inData, jintArray outData)
1042 {
1043 JNF_COCOA_ENTER(env);
1044 
1045     jboolean copy = JNI_FALSE;
1046     jint *data = (*env)->GetIntArrayElements(env, inData, &copy);
1047 
1048     // in  = [modifierFlags, keyCode]
1049     jint modifierFlags = data[0];
1050     jshort keyCode = (jshort)data[1];
1051 
1052     jint jkeyCode = java_awt_event_KeyEvent_VK_UNDEFINED;
1053     jint jkeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;
1054     jint jkeyType = java_awt_event_KeyEvent_KEY_PRESSED;
1055 
1056     NsKeyModifiersToJavaKeyInfo(modifierFlags,
1057                                 keyCode,
1058                                 &jkeyCode,
1059                                 &jkeyLocation,
1060                                 &jkeyType);
1061 
1062     // out = [jkeyCode, jkeyLocation, jkeyType];
1063     (*env)->SetIntArrayRegion(env, outData, 0, 1, &jkeyCode);
1064     (*env)->SetIntArrayRegion(env, outData, 1, 1, &jkeyLocation);
1065     (*env)->SetIntArrayRegion(env, outData, 2, 1, &jkeyType);
1066 
1067     (*env)->ReleaseIntArrayElements(env, inData, data, 0);
1068     
1069 JNF_COCOA_EXIT(env);
1070 }
1071 
1072 /*
1073  * Class:     sun_lwawt_macosx_event_NSEvent
1074  * Method:    nsToJavaChar
1075  * Signature: (CI)C
1076  */
1077 JNIEXPORT jint JNICALL
1078 Java_sun_lwawt_macosx_event_NSEvent_nsToJavaChar
1079 (JNIEnv *env, jclass cls, char nsChar, jint modifierFlags)
1080 {
1081     jchar javaChar = 0;
1082     
1083 JNF_COCOA_ENTER(env);
1084     
1085     javaChar = NsCharToJavaChar(nsChar, modifierFlags);
1086 
1087 JNF_COCOA_EXIT(env);
1088     
1089     return javaChar;
1090 }