Path: blob/master/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTEvent.m
41152 views
/*1* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#import "java_awt_event_InputEvent.h"26#import "java_awt_event_KeyEvent.h"27#import "LWCToolkit.h"2829#import "JNIUtilities.h"3031#import <sys/time.h>32#import <Carbon/Carbon.h>3334/*35* Table to map typed characters to their Java virtual key equivalent and back.36* We use the incoming unichar (ignoring all modifiers) and try to figure out37* which virtual key code is appropriate. A lot of them just have direct38* mappings (the function keys, arrow keys, etc.) so they aren't a problem.39* We had to do something a little funky to catch the keys on the numeric40* key pad (i.e. using event mask to distinguish between period on regular41* keyboard and decimal on keypad). We also have to do something incredibly42* hokey with regards to the shifted punctuation characters. For examples,43* consider '&' which is usually Shift-7. For the Java key typed events,44* that's no problem, we just say pass the unichar. But for the45* KeyPressed/Released events, we need to identify the virtual key code46* (which roughly correspond to hardware keys) which means we are supposed47* to say the virtual 7 key was pressed. But how are we supposed to know48* when we get a punctuation char what was the real hardware key was that49* was pressed? Although '&' often comes from Shift-7 the keyboard can be50* remapped! I don't think there really is a good answer, and hopefully51* all good applets are only interested in logical key typed events not52* press/release. Meanwhile, we are hard-coding the shifted punctuation53* to trigger the virtual keys that are the expected ones under a standard54* keymapping. Looking at Windows & Mac, they don't actually do this, the55* Mac seems to just put the ascii code in for the shifted punctuation56* (which means they actually end up with bogus key codes on the Java side),57* Windows I can't even figure out what it's doing.58*/59#define KL_STANDARD java_awt_event_KeyEvent_KEY_LOCATION_STANDARD60#define KL_NUMPAD java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD61#define KL_UNKNOWN java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN62static struct _key63{64unsigned short keyCode;65BOOL postsTyped;66jint javaKeyLocation;67jint javaKeyCode;68}69const keyTable[] =70{71{0x00, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_A},72{0x01, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_S},73{0x02, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_D},74{0x03, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_F},75{0x04, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_H},76{0x05, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_G},77{0x06, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_Z},78{0x07, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_X},79{0x08, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_C},80{0x09, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_V},81{0x0A, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_BACK_QUOTE},82{0x0B, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_B},83{0x0C, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_Q},84{0x0D, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_W},85{0x0E, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_E},86{0x0F, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_R},87{0x10, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_Y},88{0x11, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_T},89{0x12, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_1},90{0x13, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_2},91{0x14, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_3},92{0x15, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_4},93{0x16, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_6},94{0x17, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_5},95{0x18, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_EQUALS},96{0x19, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_9},97{0x1A, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_7},98{0x1B, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_MINUS},99{0x1C, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_8},100{0x1D, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_0},101{0x1E, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_CLOSE_BRACKET},102{0x1F, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_O},103{0x20, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_U},104{0x21, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_OPEN_BRACKET},105{0x22, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_I},106{0x23, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_P},107{0x24, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_ENTER},108{0x25, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_L},109{0x26, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_J},110{0x27, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_QUOTE},111{0x28, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_K},112{0x29, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_SEMICOLON},113{0x2A, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_BACK_SLASH},114{0x2B, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_COMMA},115{0x2C, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_SLASH},116{0x2D, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_N},117{0x2E, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_M},118{0x2F, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_PERIOD},119{0x30, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_TAB},120{0x31, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_SPACE},121{0x32, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_BACK_QUOTE},122{0x33, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_BACK_SPACE},123{0x34, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_ENTER},124{0x35, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_ESCAPE},125{0x36, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED},126{0x37, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_META}, // ****127{0x38, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_SHIFT}, // ****128{0x39, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_CAPS_LOCK},129{0x3A, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_ALT}, // ****130{0x3B, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_CONTROL}, // ****131{0x3C, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED},132{0x3D, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_ALT_GRAPH},133{0x3E, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED},134{0x3F, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, // the 'fn' key on PowerBooks135{0x40, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F17},136{0x41, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_DECIMAL},137{0x42, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED},138{0x43, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_MULTIPLY},139{0x44, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED},140{0x45, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_ADD},141{0x46, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED},142{0x47, NO, KL_NUMPAD, java_awt_event_KeyEvent_VK_CLEAR},143{0x48, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED},144{0x49, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED},145{0x4A, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED},146{0x4B, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_DIVIDE},147{0x4C, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_ENTER},148{0x4D, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED},149{0x4E, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_SUBTRACT},150{0x4F, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F18},151{0x50, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F19},152{0x51, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_EQUALS},153{0x52, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD0},154{0x53, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD1},155{0x54, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD2},156{0x55, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD3},157{0x56, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD4},158{0x57, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD5},159{0x58, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD6},160{0x59, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD7},161{0x5A, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F20},162{0x5B, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD8},163{0x5C, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD9},164{0x5D, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_BACK_SLASH}, // This is a combo yen/backslash on JIS keyboards.165{0x5E, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_UNDERSCORE},166{0x5F, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_COMMA},167{0x60, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F5},168{0x61, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F6},169{0x62, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F7},170{0x63, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F3},171{0x64, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F8},172{0x65, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F9},173{0x66, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_ALPHANUMERIC},174{0x67, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F11},175{0x68, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_KATAKANA},176{0x69, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F13},177{0x6A, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F16},178{0x6B, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F14},179{0x6C, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED},180{0x6D, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F10},181{0x6E, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED},182{0x6F, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F12},183{0x70, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED},184{0x71, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F15},185{0x72, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_HELP},186{0x73, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_HOME},187{0x74, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_PAGE_UP},188{0x75, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_DELETE},189{0x76, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F4},190{0x77, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_END},191{0x78, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F2},192{0x79, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_PAGE_DOWN},193{0x7A, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F1},194{0x7B, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_LEFT},195{0x7C, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_RIGHT},196{0x7D, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_DOWN},197{0x7E, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_UP},198{0x7F, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED},199};200201/*202* This table was stolen from the Windows implementation for mapping203* Unicode values to VK codes for dead keys. On Windows, some layouts204* return ASCII punctuation for dead accents, while some return spacing205* accent chars, so both should be listed. However, in all of the206* keyboard layouts I tried only the Unicode values are used.207*/208struct CharToVKEntry {209UniChar c;210jint javaKey;211};212static const struct CharToVKEntry charToDeadVKTable[] = {213{0x0060, java_awt_event_KeyEvent_VK_DEAD_GRAVE},214{0x00B4, java_awt_event_KeyEvent_VK_DEAD_ACUTE},215{0x0384, java_awt_event_KeyEvent_VK_DEAD_ACUTE}, // Unicode "GREEK TONOS" -- Greek keyboard, semicolon key216{0x005E, java_awt_event_KeyEvent_VK_DEAD_CIRCUMFLEX},217{0x007E, java_awt_event_KeyEvent_VK_DEAD_TILDE},218{0x02DC, java_awt_event_KeyEvent_VK_DEAD_TILDE}, // Unicode "SMALL TILDE"219{0x00AF, java_awt_event_KeyEvent_VK_DEAD_MACRON},220{0x02D8, java_awt_event_KeyEvent_VK_DEAD_BREVE},221{0x02D9, java_awt_event_KeyEvent_VK_DEAD_ABOVEDOT},222{0x00A8, java_awt_event_KeyEvent_VK_DEAD_DIAERESIS},223{0x02DA, java_awt_event_KeyEvent_VK_DEAD_ABOVERING},224{0x02DD, java_awt_event_KeyEvent_VK_DEAD_DOUBLEACUTE},225{0x02C7, java_awt_event_KeyEvent_VK_DEAD_CARON},226{0x00B8, java_awt_event_KeyEvent_VK_DEAD_CEDILLA},227{0x02DB, java_awt_event_KeyEvent_VK_DEAD_OGONEK},228{0x037A, java_awt_event_KeyEvent_VK_DEAD_IOTA},229{0x309B, java_awt_event_KeyEvent_VK_DEAD_VOICED_SOUND},230{0x309C, java_awt_event_KeyEvent_VK_DEAD_SEMIVOICED_SOUND},231{0,0}232};233234// TODO: some constants below are part of CGS (private interfaces)...235// for now we will look at the raw key code to determine left/right status236// but not sure this is foolproof...237static struct _nsKeyToJavaModifier238{239NSUInteger nsMask;240//NSUInteger cgsLeftMask;241//NSUInteger cgsRightMask;242unsigned short leftKeyCode;243unsigned short rightKeyCode;244jint javaExtMask;245jint javaMask;246jint javaKey;247}248const nsKeyToJavaModifierTable[] =249{250{251NSAlphaShiftKeyMask,2520,2530,2540, // no Java equivalent2550, // no Java equivalent256java_awt_event_KeyEvent_VK_CAPS_LOCK257},258{259NSShiftKeyMask,260//kCGSFlagsMaskAppleShiftKey,261//kCGSFlagsMaskAppleRightShiftKey,26256,26360,264java_awt_event_InputEvent_SHIFT_DOWN_MASK,265java_awt_event_InputEvent_SHIFT_MASK,266java_awt_event_KeyEvent_VK_SHIFT267},268{269NSControlKeyMask,270//kCGSFlagsMaskAppleControlKey,271//kCGSFlagsMaskAppleRightControlKey,27259,27362,274java_awt_event_InputEvent_CTRL_DOWN_MASK,275java_awt_event_InputEvent_CTRL_MASK,276java_awt_event_KeyEvent_VK_CONTROL277},278{279NSCommandKeyMask,280//kCGSFlagsMaskAppleLeftCommandKey,281//kCGSFlagsMaskAppleRightCommandKey,28255,28354,284java_awt_event_InputEvent_META_DOWN_MASK,285java_awt_event_InputEvent_META_MASK,286java_awt_event_KeyEvent_VK_META287},288{289NSAlternateKeyMask,290//kCGSFlagsMaskAppleLeftAlternateKey,291//kCGSFlagsMaskAppleRightAlternateKey,29258,2930,294java_awt_event_InputEvent_ALT_DOWN_MASK,295java_awt_event_InputEvent_ALT_MASK,296java_awt_event_KeyEvent_VK_ALT297},298{299NSAlternateKeyMask,3000,30161,302java_awt_event_InputEvent_ALT_DOWN_MASK | java_awt_event_InputEvent_ALT_GRAPH_DOWN_MASK,303java_awt_event_InputEvent_ALT_MASK | java_awt_event_InputEvent_ALT_GRAPH_MASK,304java_awt_event_KeyEvent_VK_ALT | java_awt_event_KeyEvent_VK_ALT_GRAPH305},306// NSNumericPadKeyMask307{308NSHelpKeyMask,3090,3100,3110, // no Java equivalent3120, // no Java equivalent313java_awt_event_KeyEvent_VK_HELP314},315// NSFunctionKeyMask316{0, 0, 0, 0, 0, 0}317};318319static BOOL leftAltKeyPressed;320321/*322* Almost all unicode characters just go from NS to Java with no translation.323* For the few exceptions, we handle it here with this small table.324*/325#define ALL_NS_KEY_MODIFIERS_MASK \326(NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask)327328static struct _char {329NSUInteger modifier;330unichar nsChar;331unichar javaChar;332}333const charTable[] = {334// map enter on keypad to same as return key335{0, NSEnterCharacter, NSNewlineCharacter},336337// [3134616] return newline instead of carriage return338{0, NSCarriageReturnCharacter, NSNewlineCharacter},339340// "delete" means backspace in Java341{ALL_NS_KEY_MODIFIERS_MASK, NSDeleteCharacter, NSBackspaceCharacter},342{ALL_NS_KEY_MODIFIERS_MASK, NSDeleteFunctionKey, NSDeleteCharacter},343344// back-tab is only differentiated from tab by Shift flag345{NSShiftKeyMask, NSBackTabCharacter, NSTabCharacter},346347{0, 0, 0}348};349350unichar NsCharToJavaChar(unichar nsChar, NSUInteger modifiers, BOOL spaceKeyTyped)351{352const struct _char *cur;353// Mask off just the keyboard modifiers from the event modifier mask.354NSUInteger testableFlags = (modifiers & ALL_NS_KEY_MODIFIERS_MASK);355356// walk through table & find the match357for (cur = charTable; cur->nsChar != 0 ; cur++) {358// <rdar://Problem/3476426> Need to determine if we are looking at359// a plain keypress or a modified keypress. Don't adjust the360// character of a keypress with a modifier.361if (cur->nsChar == nsChar) {362if (cur->modifier == 0 && testableFlags == 0) {363// If the modifier field is 0, that means to transform364// this character if no additional keyboard modifiers are set.365// This lets ctrl-C be reported as ctrl-C and not transformed366// into Newline.367return cur->javaChar;368} else if (cur->modifier != 0 &&369(testableFlags & cur->modifier) == testableFlags)370{371// Likewise, if the modifier field is nonzero, that means372// transform this character if only these modifiers are373// set in the testable flags.374return cur->javaChar;375}376}377}378379if (nsChar >= NSUpArrowFunctionKey && nsChar <= NSModeSwitchFunctionKey) {380return java_awt_event_KeyEvent_CHAR_UNDEFINED;381}382383// nsChar receives value 0 when SPACE key is typed.384if (nsChar == 0 && spaceKeyTyped == YES) {385return java_awt_event_KeyEvent_VK_SPACE;386}387388// otherwise return character unchanged389return nsChar;390}391392static unichar NsGetDeadKeyChar(unsigned short keyCode)393{394TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();395CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);396if (uchr == nil) { return 0; }397const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);398// Carbon modifiers should be used instead of NSEvent modifiers399UInt32 modifierKeyState = (GetCurrentEventKeyModifiers() >> 8) & 0xFF;400401if (keyboardLayout) {402UInt32 deadKeyState = 0;403UniCharCount maxStringLength = 255;404UniCharCount actualStringLength = 0;405UniChar unicodeString[maxStringLength];406407// get the deadKeyState408OSStatus status = UCKeyTranslate(keyboardLayout,409keyCode, kUCKeyActionDown, modifierKeyState,410LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit,411&deadKeyState,412maxStringLength,413&actualStringLength, unicodeString);414415if (status == noErr && deadKeyState != 0) {416// Press SPACE to get the dead key char417status = UCKeyTranslate(keyboardLayout,418kVK_Space, kUCKeyActionDown, 0,419LMGetKbdType(), 0,420&deadKeyState,421maxStringLength,422&actualStringLength, unicodeString);423424if (status == noErr && actualStringLength > 0) {425return unicodeString[0];426}427}428}429return 0;430}431432/*433* This is the function that uses the table above to take incoming434* NSEvent keyCodes and translate to the Java virtual key code.435*/436static void437NsCharToJavaVirtualKeyCode(unichar ch, BOOL isDeadChar,438NSUInteger flags, unsigned short key,439jint *keyCode, jint *keyLocation, BOOL *postsTyped,440unichar *deadChar)441{442static size_t size = sizeof(keyTable) / sizeof(struct _key);443NSInteger offset;444445if (isDeadChar) {446unichar testDeadChar = NsGetDeadKeyChar(key);447const struct CharToVKEntry *map;448for (map = charToDeadVKTable; map->c != 0; ++map) {449if (testDeadChar == map->c) {450*keyCode = map->javaKey;451*postsTyped = NO;452// TODO: use UNKNOWN here?453*keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;454*deadChar = testDeadChar;455return;456}457}458// If we got here, we keep looking for a normal key.459}460461if ([[NSCharacterSet letterCharacterSet] characterIsMember:ch]) {462// key is an alphabetic character463unichar lower;464lower = tolower(ch);465offset = lower - 'a';466if (offset >= 0 && offset <= 25) {467// some chars in letter set are NOT actually A-Z characters?!468// skip them...469*postsTyped = YES;470// do quick conversion471*keyCode = java_awt_event_KeyEvent_VK_A + offset;472*keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_STANDARD;473return;474}475}476477if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:ch]) {478// key is a digit479offset = ch - '0';480// make sure in range for decimal digits481if (offset >= 0 && offset <= 9) {482jboolean numpad = ((flags & NSNumericPadKeyMask) &&483(key > 81 && key < 93));484*postsTyped = YES;485if (numpad) {486*keyCode = offset + java_awt_event_KeyEvent_VK_NUMPAD0;487*keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD;488} else {489*keyCode = offset + java_awt_event_KeyEvent_VK_0;490*keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_STANDARD;491}492return;493}494}495496if (key < size) {497*postsTyped = keyTable[key].postsTyped;498*keyCode = keyTable[key].javaKeyCode;499*keyLocation = keyTable[key].javaKeyLocation;500} else {501// Should we report this? This means we've got a keyboard502// we don't know about...503*postsTyped = NO;504*keyCode = java_awt_event_KeyEvent_VK_UNDEFINED;505*keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;506}507}508509/*510* This returns the java key data for the key NSEvent modifiers511* (after NSFlagChanged).512*/513static void514NsKeyModifiersToJavaKeyInfo(NSUInteger nsFlags, unsigned short eventKeyCode,515jint *javaKeyCode,516jint *javaKeyLocation,517jint *javaKeyType)518{519static NSUInteger sPreviousNSFlags = 0;520521const struct _nsKeyToJavaModifier* cur;522NSUInteger oldNSFlags = sPreviousNSFlags;523NSUInteger changedNSFlags = oldNSFlags ^ nsFlags;524sPreviousNSFlags = nsFlags;525526*javaKeyCode = java_awt_event_KeyEvent_VK_UNDEFINED;527*javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;528*javaKeyType = java_awt_event_KeyEvent_KEY_PRESSED;529530for (cur = nsKeyToJavaModifierTable; cur->nsMask != 0; ++cur) {531if (changedNSFlags & cur->nsMask) {532*javaKeyCode = cur->javaKey;533*javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_STANDARD;534// TODO: uses SPI...535//if (changedNSFlags & cur->cgsLeftMask) {536// *javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_LEFT;537//} else if (changedNSFlags & cur->cgsRightMask) {538// *javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_RIGHT;539//}540if (eventKeyCode == cur->leftKeyCode) {541leftAltKeyPressed = YES;542*javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_LEFT;543} else if (eventKeyCode == cur->rightKeyCode) {544*javaKeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_RIGHT;545} else if (cur->nsMask == NSAlternateKeyMask) {546leftAltKeyPressed = NO;547continue;548}549*javaKeyType = (cur->nsMask & nsFlags) ?550java_awt_event_KeyEvent_KEY_PRESSED :551java_awt_event_KeyEvent_KEY_RELEASED;552break;553}554}555}556557/*558* This returns the java modifiers for a key NSEvent.559*/560jint NsKeyModifiersToJavaModifiers(NSUInteger nsFlags, BOOL isExtMods)561{562jint javaModifiers = 0;563const struct _nsKeyToJavaModifier* cur;564565for (cur = nsKeyToJavaModifierTable; cur->nsMask != 0; ++cur) {566if ((cur->nsMask & nsFlags) != 0) {567//This code will consider the mask value for left alt as well as568//right alt, but that should be ok, since right alt contains left alt569//mask value.570javaModifiers |= isExtMods ? cur->javaExtMask : cur->javaMask;571if (cur->nsMask == NSAlternateKeyMask && leftAltKeyPressed) {572break; //since right alt key struct is defined last, break out of the loop }573}574}575}576577return javaModifiers;578}579580/*581* This returns the NSEvent flags for java key modifiers.582*/583NSUInteger JavaModifiersToNsKeyModifiers(jint javaModifiers, BOOL isExtMods)584{585NSUInteger nsFlags = 0;586const struct _nsKeyToJavaModifier* cur;587588for (cur = nsKeyToJavaModifierTable; cur->nsMask != 0; ++cur) {589jint mask = isExtMods? cur->javaExtMask : cur->javaMask;590if ((mask & javaModifiers) != 0) {591nsFlags |= cur->nsMask;592}593}594595// special case596jint mask = isExtMods? java_awt_event_InputEvent_ALT_GRAPH_DOWN_MASK :597java_awt_event_InputEvent_ALT_GRAPH_MASK;598599if ((mask & javaModifiers) != 0) {600nsFlags |= NSAlternateKeyMask;601}602603return nsFlags;604}605606607jint GetJavaMouseModifiers(NSUInteger modifierFlags)608{609// Mousing needs the key modifiers610jint modifiers = NsKeyModifiersToJavaModifiers(modifierFlags, YES);611612613/*614* Ask Quartz about mouse buttons state615*/616617if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,618kCGMouseButtonLeft)) {619modifiers |= java_awt_event_InputEvent_BUTTON1_DOWN_MASK;620}621622if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,623kCGMouseButtonRight)) {624modifiers |= java_awt_event_InputEvent_BUTTON3_DOWN_MASK;625}626627if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,628kCGMouseButtonCenter)) {629modifiers |= java_awt_event_InputEvent_BUTTON2_DOWN_MASK;630}631632NSInteger extraButton = 3;633for (; extraButton < gNumberOfButtons; extraButton++) {634if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,635extraButton)) {636modifiers |= gButtonDownMasks[extraButton];637}638}639640return modifiers;641}642643jlong UTC(NSEvent *event) {644struct timeval tv;645if (gettimeofday(&tv, NULL) == 0) {646long long sec = (long long)tv.tv_sec;647return (sec*1000) + (tv.tv_usec/1000);648}649return 0;650}651652JNIEXPORT void JNICALL653Java_java_awt_AWTEvent_nativeSetSource654(JNIEnv *env, jobject self, jobject newSource)655{656}657658/*659* Class: sun_lwawt_macosx_NSEvent660* Method: nsToJavaModifiers661* Signature: (II)I662*/663JNIEXPORT jint JNICALL664Java_sun_lwawt_macosx_NSEvent_nsToJavaModifiers665(JNIEnv *env, jclass cls, jint modifierFlags)666{667jint jmodifiers = 0;668669JNI_COCOA_ENTER(env);670671jmodifiers = GetJavaMouseModifiers(modifierFlags);672673JNI_COCOA_EXIT(env);674675return jmodifiers;676}677678/*679* Class: sun_lwawt_macosx_NSEvent680* Method: nsToJavaKeyInfo681* Signature: ([I[I)Z682*/683JNIEXPORT jboolean JNICALL684Java_sun_lwawt_macosx_NSEvent_nsToJavaKeyInfo685(JNIEnv *env, jclass cls, jintArray inData, jintArray outData)686{687BOOL postsTyped = NO;688689JNI_COCOA_ENTER(env);690691jboolean copy = JNI_FALSE;692jint *data = (*env)->GetIntArrayElements(env, inData, ©);693CHECK_NULL_RETURN(data, postsTyped);694695// in = [testChar, testDeadChar, modifierFlags, keyCode]696jchar testChar = (jchar)data[0];697BOOL isDeadChar = (data[1] != 0);698jint modifierFlags = data[2];699jshort keyCode = (jshort)data[3];700701jint jkeyCode = java_awt_event_KeyEvent_VK_UNDEFINED;702jint jkeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;703jint testDeadChar = 0;704705NsCharToJavaVirtualKeyCode((unichar)testChar, isDeadChar,706(NSUInteger)modifierFlags, (unsigned short)keyCode,707&jkeyCode, &jkeyLocation, &postsTyped,708(unichar *) &testDeadChar);709710// out = [jkeyCode, jkeyLocation, deadChar];711(*env)->SetIntArrayRegion(env, outData, 0, 1, &jkeyCode);712(*env)->SetIntArrayRegion(env, outData, 1, 1, &jkeyLocation);713(*env)->SetIntArrayRegion(env, outData, 2, 1, &testDeadChar);714715(*env)->ReleaseIntArrayElements(env, inData, data, 0);716717JNI_COCOA_EXIT(env);718719return postsTyped;720}721722/*723* Class: sun_lwawt_macosx_NSEvent724* Method: nsKeyModifiersToJavaKeyInfo725* Signature: ([I[I)V726*/727JNIEXPORT void JNICALL728Java_sun_lwawt_macosx_NSEvent_nsKeyModifiersToJavaKeyInfo729(JNIEnv *env, jclass cls, jintArray inData, jintArray outData)730{731JNI_COCOA_ENTER(env);732733jboolean copy = JNI_FALSE;734jint *data = (*env)->GetIntArrayElements(env, inData, ©);735CHECK_NULL(data);736737// in = [modifierFlags, keyCode]738jint modifierFlags = data[0];739jshort keyCode = (jshort)data[1];740741jint jkeyCode = java_awt_event_KeyEvent_VK_UNDEFINED;742jint jkeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;743jint jkeyType = java_awt_event_KeyEvent_KEY_PRESSED;744745NsKeyModifiersToJavaKeyInfo(modifierFlags,746keyCode,747&jkeyCode,748&jkeyLocation,749&jkeyType);750751// out = [jkeyCode, jkeyLocation, jkeyType];752(*env)->SetIntArrayRegion(env, outData, 0, 1, &jkeyCode);753(*env)->SetIntArrayRegion(env, outData, 1, 1, &jkeyLocation);754(*env)->SetIntArrayRegion(env, outData, 2, 1, &jkeyType);755756(*env)->ReleaseIntArrayElements(env, inData, data, 0);757758JNI_COCOA_EXIT(env);759}760761/*762* Class: sun_lwawt_macosx_NSEvent763* Method: nsToJavaChar764* Signature: (CI)C765*/766JNIEXPORT jint JNICALL767Java_sun_lwawt_macosx_NSEvent_nsToJavaChar768(JNIEnv *env, jclass cls, jchar nsChar, jint modifierFlags, jboolean spaceKeyTyped)769{770jchar javaChar = 0;771772JNI_COCOA_ENTER(env);773774javaChar = NsCharToJavaChar(nsChar, modifierFlags, spaceKeyTyped);775776JNI_COCOA_EXIT(env);777778return javaChar;779}780781782