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
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 }
598 }
599
600 /*
601 * Class: sun_lwawt_macosx_event_NSEvent
602 * Method: nsToJavaKeyInfo
603 * Signature: ([I[I)Z
604 */
605 JNIEXPORT jboolean JNICALL
606 Java_sun_lwawt_macosx_event_NSEvent_nsToJavaKeyInfo
607 (JNIEnv *env, jclass cls, jintArray inData, jintArray outData)
608 {
609 BOOL postsTyped = NO;
610
611 JNF_COCOA_ENTER(env);
612
613 jboolean copy = JNI_FALSE;
614 jint *data = (*env)->GetIntArrayElements(env, inData, ©);
615
616 // in = [testChar, testDeadChar, modifierFlags, keyCode]
617 jchar testChar = (jchar)data[0];
618 jchar testDeadChar = (jchar)data[1];
619 jint modifierFlags = data[2];
620 jshort keyCode = (jshort)data[3];
621
622 jint jkeyCode = java_awt_event_KeyEvent_VK_UNDEFINED;
623 jint jkeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;
624
625 NsCharToJavaVirtualKeyCode((unichar)testChar, (unichar)testDeadChar,
626 (NSUInteger)modifierFlags, (unsigned short)keyCode,
627 &jkeyCode, &jkeyLocation, &postsTyped);
628
629 // out = [jkeyCode, jkeyLocation];
630 (*env)->SetIntArrayRegion(env, outData, 0, 1, &jkeyCode);
631 (*env)->SetIntArrayRegion(env, outData, 1, 1, &jkeyLocation);
632
633 (*env)->ReleaseIntArrayElements(env, inData, data, 0);
634
635 JNF_COCOA_EXIT(env);
636
637 return postsTyped;
638 }
639
640 /*
641 * Class: sun_lwawt_macosx_event_NSEvent
642 * Method: nsKeyModifiersToJavaKeyInfo
643 * Signature: ([I[I)V
644 */
645 JNIEXPORT void JNICALL
646 Java_sun_lwawt_macosx_event_NSEvent_nsKeyModifiersToJavaKeyInfo
647 (JNIEnv *env, jclass cls, jintArray inData, jintArray outData)
648 {
649 JNF_COCOA_ENTER(env);
650
651 jboolean copy = JNI_FALSE;
|
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 #include <Carbon/Carbon.h>
30
31 #import "LWCToolkit.h"
32 #import "ThreadUtilities.h"
33
34 #import "java_awt_event_InputEvent.h"
35 #import "java_awt_event_KeyEvent.h"
36 #import "java_awt_event_MouseEvent.h"
37
38 /*
39 * Table to map typed characters to their Java virtual key equivalent and back.
40 * We use the incoming unichar (ignoring all modifiers) and try to figure out
41 * which virtual key code is appropriate. A lot of them just have direct
42 * mappings (the function keys, arrow keys, etc.) so they aren't a problem.
43 * We had to do something a little funky to catch the keys on the numeric
44 * key pad (i.e. using event mask to distinguish between period on regular
45 * keyboard and decimal on keypad). We also have to do something incredibly
46 * hokey with regards to the shifted punctuation characters. For examples,
47 * consider '&' which is usually Shift-7. For the Java key typed events,
48 * that's no problem, we just say pass the unichar. But for the
49 * KeyPressed/Released events, we need to identify the virtual key code
355 return cur->javaChar;
356 } else if (cur->modifier != 0 &&
357 (testableFlags & cur->modifier) == testableFlags)
358 {
359 // Likewise, if the modifier field is nonzero, that means
360 // transform this character if only these modifiers are
361 // set in the testable flags.
362 return cur->javaChar;
363 }
364 }
365 }
366
367 if (nsChar >= NSUpArrowFunctionKey && nsChar <= NSModeSwitchFunctionKey) {
368 return java_awt_event_KeyEvent_CHAR_UNDEFINED;
369 }
370
371 // otherwise return character unchanged
372 return nsChar;
373 }
374
375 static unichar NsGetDeadKeyChar(unsigned short keyCode)
376 {
377 TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
378 CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
379 const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
380 // Carbon modifiers should be used instead of NSEvent modifiers
381 UInt32 modifierKeyState = (GetCurrentEventKeyModifiers() >> 8) & 0xFF;
382
383 if (keyboardLayout) {
384 UInt32 deadKeyState = 0;
385 UniCharCount maxStringLength = 255;
386 UniCharCount actualStringLength = 0;
387 UniChar unicodeString[maxStringLength];
388
389 // get the deadKeyState
390 OSStatus status = UCKeyTranslate(keyboardLayout,
391 keyCode, kUCKeyActionDown, modifierKeyState,
392 LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit,
393 &deadKeyState,
394 maxStringLength,
395 &actualStringLength, unicodeString);
396
397 if (status == noErr && deadKeyState != 0) {
398 // Press SPACE to get the dead key char
399 status = UCKeyTranslate(keyboardLayout,
400 kVK_Space, kUCKeyActionDown, 0,
401 LMGetKbdType(), 0,
402 &deadKeyState,
403 maxStringLength,
404 &actualStringLength, unicodeString);
405
406 if (status == noErr && actualStringLength > 0) {
407 return unicodeString[0];
408 }
409 }
410 }
411 return 0;
412 }
413
414 /*
415 * This is the function that uses the table above to take incoming
416 * NSEvent keyCodes and translate to the Java virtual key code.
417 */
418 static void
419 NsCharToJavaVirtualKeyCode(unichar ch, BOOL isDeadChar,
420 NSUInteger flags, unsigned short key,
421 jint *keyCode, jint *keyLocation, BOOL *postsTyped, unichar *deadChar)
422 {
423 static size_t size = sizeof(keyTable) / sizeof(struct _key);
424 NSInteger offset;
425
426 if (isDeadChar) {
427 unichar testDeadChar = NsGetDeadKeyChar(key);
428 const struct CharToVKEntry *map;
429 for (map = charToDeadVKTable; map->c != 0; ++map) {
430 if (testDeadChar == map->c) {
431 *keyCode = map->javaKey;
432 *postsTyped = NO;
433 // TODO: use UNKNOWN here?
434 *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;
435 *deadChar = testDeadChar;
436 return;
437 }
438 }
439 // If we got here, we keep looking for a normal key.
440 }
441
442 if ([[NSCharacterSet letterCharacterSet] characterIsMember:ch]) {
443 // key is an alphabetic character
444 unichar lower;
445 lower = tolower(ch);
446 offset = lower - 'a';
447 if (offset >= 0 && offset <= 25) {
448 // some chars in letter set are NOT actually A-Z characters?!
449 // skip them...
450 *postsTyped = YES;
451 // do quick conversion
452 *keyCode = java_awt_event_KeyEvent_VK_A + offset;
453 *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_STANDARD;
454 return;
455 }
640 }
641
642 /*
643 * Class: sun_lwawt_macosx_event_NSEvent
644 * Method: nsToJavaKeyInfo
645 * Signature: ([I[I)Z
646 */
647 JNIEXPORT jboolean JNICALL
648 Java_sun_lwawt_macosx_event_NSEvent_nsToJavaKeyInfo
649 (JNIEnv *env, jclass cls, jintArray inData, jintArray outData)
650 {
651 BOOL postsTyped = NO;
652
653 JNF_COCOA_ENTER(env);
654
655 jboolean copy = JNI_FALSE;
656 jint *data = (*env)->GetIntArrayElements(env, inData, ©);
657
658 // in = [testChar, testDeadChar, modifierFlags, keyCode]
659 jchar testChar = (jchar)data[0];
660 BOOL isDeadChar = (data[1] != 0);
661 jint modifierFlags = data[2];
662 jshort keyCode = (jshort)data[3];
663
664 jint jkeyCode = java_awt_event_KeyEvent_VK_UNDEFINED;
665 jint jkeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;
666 jchar testDeadChar = 0;
667
668 NsCharToJavaVirtualKeyCode((unichar)testChar, isDeadChar,
669 (NSUInteger)modifierFlags, (unsigned short)keyCode,
670 &jkeyCode, &jkeyLocation, &postsTyped, &testDeadChar);
671
672 // out = [jkeyCode, jkeyLocation];
673 (*env)->SetIntArrayRegion(env, outData, 0, 1, &jkeyCode);
674 (*env)->SetIntArrayRegion(env, outData, 1, 1, &jkeyLocation);
675 (*env)->SetIntArrayRegion(env, outData, 2, 1, (jint *)&testDeadChar);
676
677 (*env)->ReleaseIntArrayElements(env, inData, data, 0);
678
679 JNF_COCOA_EXIT(env);
680
681 return postsTyped;
682 }
683
684 /*
685 * Class: sun_lwawt_macosx_event_NSEvent
686 * Method: nsKeyModifiersToJavaKeyInfo
687 * Signature: ([I[I)V
688 */
689 JNIEXPORT void JNICALL
690 Java_sun_lwawt_macosx_event_NSEvent_nsKeyModifiersToJavaKeyInfo
691 (JNIEnv *env, jclass cls, jintArray inData, jintArray outData)
692 {
693 JNF_COCOA_ENTER(env);
694
695 jboolean copy = JNI_FALSE;
|