| /* |
| * Copyright 1995-2005 Sun Microsystems, Inc. All Rights Reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Sun designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Sun in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| * CA 95054 USA or visit www.sun.com if you need additional information or |
| * have any questions. |
| */ |
| |
| #ifdef HEADLESS |
| #error This file should not be included in headless library |
| #endif |
| |
| #include "awt_p.h" |
| #include <sys/time.h> /* timeval */ |
| |
| #define XK_KATAKANA |
| #include <X11/keysym.h> /* standard X keysyms */ |
| #include <X11/DECkeysym.h> /* DEC vendor-specific */ |
| #include <X11/Sunkeysym.h> /* Sun vendor-specific */ |
| #include <X11/ap_keysym.h> /* Apollo (HP) vendor-specific */ |
| /* |
| * #include <X11/HPkeysym.h> HP vendor-specific |
| * I checked HPkeysym.h into the workspace because it ships |
| * with X11R6.4.2 (and later) but not with X11R6.4.1. |
| * So, it ought to ship with Solaris 9, but not Solaris 8. |
| * Same deal for Linux - newer versions of XFree have it. |
| * |
| * Note: this is mainly done for the hp keysyms; it does NOT |
| * give us the osf keysyms that are also defined in HPkeysym.h. |
| * This is because we are already getting /Xm/VirtKeys.h |
| * from awt_p.h <- /Xm/Xm.h <- /Xm/VirtKeys.h, and VirtKeys.h |
| * #defines _OSF_Keysyms before we get here. We are |
| * missing a couple of osf keysyms because of this, |
| * so I have #defined them below. |
| */ |
| #include "HPkeysym.h" /* HP vendor-specific */ |
| |
| #include <Xm/Display.h> |
| #include <ctype.h> |
| #include "java_awt_Frame.h" |
| #include "java_awt_Component.h" |
| #include "java_awt_AWTEvent.h" |
| #include "java_awt_event_KeyEvent.h" |
| #include "java_awt_event_FocusEvent.h" |
| #include "java_awt_event_MouseEvent.h" |
| #include "java_awt_event_MouseWheelEvent.h" |
| #include "java_awt_event_InputEvent.h" |
| #include "java_awt_event_WindowEvent.h" |
| #include "sun_awt_motif_MComponentPeer.h" |
| #include "color.h" |
| #include "canvas.h" |
| #include "awt_Cursor.h" |
| #include "VDrawingArea.h" |
| #include "XDrawingArea.h" |
| #include "awt_Component.h" |
| #include "awt_AWTEvent.h" |
| #include "awt_Event.h" |
| #include "awt_KeyboardFocusManager.h" |
| #include "awt_MToolkit.h" |
| #include "awt_TopLevel.h" |
| #include "awt_util.h" |
| |
| #include <jni.h> |
| #include <jni_util.h> |
| #include <jvm.h> |
| #include <jawt.h> |
| |
| #ifdef NDEBUG /* NDEBUG overrides DEBUG */ |
| #undef DEBUG |
| #endif |
| |
| /* |
| * Two osf keys are not defined in standard keysym.h, |
| * /Xm/VirtKeys.h, or HPkeysym.h, so I added them below. |
| * I found them in /usr/openwin/lib/X11/XKeysymDB |
| */ |
| #ifndef osfXK_Prior |
| #define osfXK_Prior 0x1004FF55 |
| #endif |
| #ifndef osfXK_Next |
| #define osfXK_Next 0x1004FF56 |
| #endif |
| /* |
| * osfXK_Escape is defined in HPkeysym.h, but not in |
| * /Xm/VirtKeys.h, so I added it below. It is also in |
| * /usr/openwin/lib/X11/XKeysymDB |
| * Note: it is in /Xm/VirtKeys.h in the AWT motif workspace, |
| * but not in /usr/local/Motif/include/Xm/VirtKeys.h |
| * on the Solaris 7, 8, or 9 machines I tried. |
| */ |
| #ifndef osfXK_Escape |
| #define osfXK_Escape 0x1004FF1B |
| #endif |
| |
| extern struct MComponentPeerIDs mComponentPeerIDs; |
| extern struct AWTEventIDs awtEventIDs; |
| extern struct KeyEventIDs keyEventIDs; |
| extern struct InputEventIDs inputEventIDs; |
| extern struct ComponentIDs componentIDs; |
| extern struct KeyboardFocusManagerIDs keyboardFocusManagerIDs; |
| |
| #ifdef DEBUG |
| static Boolean debugKeys = False; |
| #endif |
| |
| jint awt_multiclick_smudge = 4; |
| |
| extern Widget drag_source; |
| |
| Widget prevWidget = NULL; /* for bug fix 4017222 */ |
| |
| FocusListElt *focusList = NULL, *focusListEnd = NULL; |
| |
| jweak forGained = NULL; |
| |
| extern Boolean scrollBugWorkAround; |
| extern jobject currentX11InputMethodInstance; |
| extern Window currentFocusWindow; |
| extern Boolean awt_x11inputmethod_lookupString(XKeyPressedEvent *, KeySym *); |
| Boolean awt_UseType4Patch = True; |
| Boolean awt_ServerDetected = False; |
| Boolean awt_IsXsun = False; |
| Boolean awt_UseXKB = False; |
| |
| void awt_post_java_key_event(XtPointer client_data, jint id, |
| XEvent *xevent, Time when, jint keycode, |
| jchar keychar, jint modifiers, |
| jint keyLocation, XEvent *anEvent); |
| void awt_post_java_focus_event(XtPointer client_data, jint id, jobject cause, |
| XEvent *event); |
| void awt_post_java_mouse_event(XtPointer client_data, jint id, |
| XEvent *event, Time when, jint modifiers, |
| jint x, jint y, |
| jint xAbs, jint yAbs, |
| jint clickcount, Boolean popuptrigger, |
| jint wheelAmt, jint button); |
| |
| typedef struct KEYMAP_ENTRY { |
| jint awtKey; |
| KeySym x11Key; |
| Boolean mapsToUnicodeChar; |
| jint keyLocation; |
| } KeymapEntry; |
| |
| /* NB: XK_R? keysyms are for Type 4 keyboards. |
| * The corresponding XK_F? keysyms are for Type 5 |
| * |
| * Note: this table must be kept in sorted order, since it is traversed |
| * according to both Java keycode and X keysym. There are a number of |
| * keycodes that map to more than one corresponding keysym, and we need |
| * to choose the right one. Unfortunately, there are some keysyms that |
| * can map to more than one keycode, depending on what kind of keyboard |
| * is in use (e.g. F11 and F12). |
| */ |
| |
| KeymapEntry keymapTable[] = |
| { |
| {java_awt_event_KeyEvent_VK_A, XK_a, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_B, XK_b, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_C, XK_c, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_D, XK_d, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_E, XK_e, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_F, XK_f, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_G, XK_g, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_H, XK_h, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_I, XK_i, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_J, XK_j, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_K, XK_k, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_L, XK_l, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_M, XK_m, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_N, XK_n, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_O, XK_o, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_P, XK_p, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_Q, XK_q, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_R, XK_r, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_S, XK_s, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_T, XK_t, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_U, XK_u, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_V, XK_v, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_W, XK_w, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_X, XK_x, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_Y, XK_y, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_Z, XK_z, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* TTY Function keys */ |
| {java_awt_event_KeyEvent_VK_BACK_SPACE, XK_BackSpace, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_TAB, XK_Tab, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_CLEAR, XK_Clear, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_ENTER, XK_Return, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_ENTER, XK_Linefeed, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PAUSE, XK_Pause, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PAUSE, XK_F21, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PAUSE, XK_R1, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_SCROLL_LOCK, XK_Scroll_Lock, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_SCROLL_LOCK, XK_F23, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_SCROLL_LOCK, XK_R3, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_ESCAPE, XK_Escape, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Other vendor-specific versions of TTY Function keys */ |
| {java_awt_event_KeyEvent_VK_BACK_SPACE, osfXK_BackSpace, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_CLEAR, osfXK_Clear, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_ESCAPE, osfXK_Escape, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Modifier keys */ |
| {java_awt_event_KeyEvent_VK_SHIFT, XK_Shift_L, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_LEFT}, |
| {java_awt_event_KeyEvent_VK_SHIFT, XK_Shift_R, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_RIGHT}, |
| {java_awt_event_KeyEvent_VK_CONTROL, XK_Control_L, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_LEFT}, |
| {java_awt_event_KeyEvent_VK_CONTROL, XK_Control_R, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_RIGHT}, |
| {java_awt_event_KeyEvent_VK_ALT, XK_Alt_L, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_LEFT}, |
| {java_awt_event_KeyEvent_VK_ALT, XK_Alt_R, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_RIGHT}, |
| {java_awt_event_KeyEvent_VK_META, XK_Meta_L, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_LEFT}, |
| {java_awt_event_KeyEvent_VK_META, XK_Meta_R, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_RIGHT}, |
| {java_awt_event_KeyEvent_VK_CAPS_LOCK, XK_Caps_Lock, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Misc Functions */ |
| {java_awt_event_KeyEvent_VK_PRINTSCREEN, XK_Print, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PRINTSCREEN, XK_F22, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PRINTSCREEN, XK_R2, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_CANCEL, XK_Cancel, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_HELP, XK_Help, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_NUM_LOCK, XK_Num_Lock, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| |
| /* Other vendor-specific versions of Misc Functions */ |
| {java_awt_event_KeyEvent_VK_CANCEL, osfXK_Cancel, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_HELP, osfXK_Help, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Rectangular Navigation Block */ |
| {java_awt_event_KeyEvent_VK_HOME, XK_Home, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_HOME, XK_R7, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PAGE_UP, XK_Page_Up, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PAGE_UP, XK_Prior, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PAGE_UP, XK_R9, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PAGE_DOWN, XK_Page_Down, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PAGE_DOWN, XK_Next, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PAGE_DOWN, XK_R15, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_END, XK_End, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_END, XK_R13, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_INSERT, XK_Insert, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DELETE, XK_Delete, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Keypad equivalents of Rectangular Navigation Block */ |
| {java_awt_event_KeyEvent_VK_HOME, XK_KP_Home, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_PAGE_UP, XK_KP_Page_Up, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_PAGE_UP, XK_KP_Prior, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_PAGE_DOWN, XK_KP_Page_Down, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_PAGE_DOWN, XK_KP_Next, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_END, XK_KP_End, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_INSERT, XK_KP_Insert, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_DELETE, XK_KP_Delete, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| |
| /* Other vendor-specific Rectangular Navigation Block */ |
| {java_awt_event_KeyEvent_VK_PAGE_UP, osfXK_PageUp, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PAGE_UP, osfXK_Prior, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PAGE_DOWN, osfXK_PageDown, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PAGE_DOWN, osfXK_Next, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_END, osfXK_EndLine, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_INSERT, osfXK_Insert, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DELETE, osfXK_Delete, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Triangular Navigation Block */ |
| {java_awt_event_KeyEvent_VK_LEFT, XK_Left, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_UP, XK_Up, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_RIGHT, XK_Right, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DOWN, XK_Down, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Keypad equivalents of Triangular Navigation Block */ |
| {java_awt_event_KeyEvent_VK_KP_LEFT, XK_KP_Left, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_KP_UP, XK_KP_Up, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_KP_RIGHT, XK_KP_Right, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_KP_DOWN, XK_KP_Down, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| |
| /* Other vendor-specific Triangular Navigation Block */ |
| {java_awt_event_KeyEvent_VK_LEFT, osfXK_Left, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_UP, osfXK_Up, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_RIGHT, osfXK_Right, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DOWN, osfXK_Down, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Remaining Cursor control & motion */ |
| {java_awt_event_KeyEvent_VK_BEGIN, XK_Begin, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_BEGIN, XK_KP_Begin, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| |
| {java_awt_event_KeyEvent_VK_0, XK_0, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_1, XK_1, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_2, XK_2, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_3, XK_3, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_4, XK_4, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_5, XK_5, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_6, XK_6, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_7, XK_7, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_8, XK_8, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_9, XK_9, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| {java_awt_event_KeyEvent_VK_SPACE, XK_space, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_EXCLAMATION_MARK, XK_exclam, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_QUOTEDBL, XK_quotedbl, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_NUMBER_SIGN, XK_numbersign, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DOLLAR, XK_dollar, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_AMPERSAND, XK_ampersand, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_QUOTE, XK_apostrophe, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_LEFT_PARENTHESIS, XK_parenleft, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_RIGHT_PARENTHESIS, XK_parenright, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_ASTERISK, XK_asterisk, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PLUS, XK_plus, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_COMMA, XK_comma, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_MINUS, XK_minus, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PERIOD, XK_period, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_SLASH, XK_slash, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| {java_awt_event_KeyEvent_VK_COLON, XK_colon, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_SEMICOLON, XK_semicolon, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_LESS, XK_less, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_EQUALS, XK_equal, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_GREATER, XK_greater, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| {java_awt_event_KeyEvent_VK_AT, XK_at, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| {java_awt_event_KeyEvent_VK_OPEN_BRACKET, XK_bracketleft, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_BACK_SLASH, XK_backslash, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_CLOSE_BRACKET, XK_bracketright, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_CIRCUMFLEX, XK_asciicircum, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_UNDERSCORE, XK_underscore, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_BACK_QUOTE, XK_grave, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| {java_awt_event_KeyEvent_VK_BRACELEFT, XK_braceleft, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_BRACERIGHT, XK_braceright, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| {java_awt_event_KeyEvent_VK_INVERTED_EXCLAMATION_MARK, XK_exclamdown, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Remaining Numeric Keypad Keys */ |
| {java_awt_event_KeyEvent_VK_NUMPAD0, XK_KP_0, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_NUMPAD1, XK_KP_1, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_NUMPAD2, XK_KP_2, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_NUMPAD3, XK_KP_3, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_NUMPAD4, XK_KP_4, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_NUMPAD5, XK_KP_5, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_NUMPAD6, XK_KP_6, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_NUMPAD7, XK_KP_7, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_NUMPAD8, XK_KP_8, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_NUMPAD9, XK_KP_9, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_SPACE, XK_KP_Space, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_TAB, XK_KP_Tab, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_ENTER, XK_KP_Enter, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_EQUALS, XK_KP_Equal, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_EQUALS, XK_R4, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_MULTIPLY, XK_KP_Multiply, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_MULTIPLY, XK_F26, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_MULTIPLY, XK_R6, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_ADD, XK_KP_Add, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_SEPARATOR, XK_KP_Separator, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_SUBTRACT, XK_KP_Subtract, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_SUBTRACT, XK_F24, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_DECIMAL, XK_KP_Decimal, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_DIVIDE, XK_KP_Divide, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_DIVIDE, XK_F25, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| {java_awt_event_KeyEvent_VK_DIVIDE, XK_R5, TRUE, java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD}, |
| |
| /* Function Keys */ |
| {java_awt_event_KeyEvent_VK_F1, XK_F1, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_F2, XK_F2, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_F3, XK_F3, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_F4, XK_F4, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_F5, XK_F5, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_F6, XK_F6, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_F7, XK_F7, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_F8, XK_F8, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_F9, XK_F9, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_F10, XK_F10, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_F11, XK_F11, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_F12, XK_F12, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Sun vendor-specific version of F11 and F12 */ |
| {java_awt_event_KeyEvent_VK_F11, SunXK_F36, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_F12, SunXK_F37, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* X11 keysym names for input method related keys don't always |
| * match keytop engravings or Java virtual key names, so here we |
| * only map constants that we've found on real keyboards. |
| */ |
| /* Type 5c Japanese keyboard: kakutei */ |
| {java_awt_event_KeyEvent_VK_ACCEPT, XK_Execute, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| /* Type 5c Japanese keyboard: henkan */ |
| {java_awt_event_KeyEvent_VK_CONVERT, XK_Kanji, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| /* Type 5c Japanese keyboard: nihongo */ |
| {java_awt_event_KeyEvent_VK_INPUT_METHOD_ON_OFF, XK_Henkan_Mode, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| /* VK_KANA_LOCK is handled separately because it generates the |
| * same keysym as ALT_GRAPH in spite of its different behavior. |
| */ |
| |
| {java_awt_event_KeyEvent_VK_COMPOSE, XK_Multi_key, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_ALT_GRAPH, XK_Mode_switch, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Editing block */ |
| {java_awt_event_KeyEvent_VK_AGAIN, XK_Redo, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_AGAIN, XK_L2, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_UNDO, XK_Undo, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_UNDO, XK_L4, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_COPY, XK_L6, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PASTE, XK_L8, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_CUT, XK_L10, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_FIND, XK_Find, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_FIND, XK_L9, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PROPS, XK_L3, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_STOP, XK_L1, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Sun vendor-specific versions for editing block */ |
| {java_awt_event_KeyEvent_VK_AGAIN, SunXK_Again, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_UNDO, SunXK_Undo, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_COPY, SunXK_Copy, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PASTE, SunXK_Paste, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_CUT, SunXK_Cut, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_FIND, SunXK_Find, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PROPS, SunXK_Props, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_STOP, SunXK_Stop, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Apollo (HP) vendor-specific versions for editing block */ |
| {java_awt_event_KeyEvent_VK_COPY, apXK_Copy, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_CUT, apXK_Cut, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PASTE, apXK_Paste, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Other vendor-specific versions for editing block */ |
| {java_awt_event_KeyEvent_VK_COPY, osfXK_Copy, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_CUT, osfXK_Cut, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_PASTE, osfXK_Paste, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_UNDO, osfXK_Undo, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Dead key mappings (for European keyboards) */ |
| {java_awt_event_KeyEvent_VK_DEAD_GRAVE, XK_dead_grave, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_ACUTE, XK_dead_acute, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_CIRCUMFLEX, XK_dead_circumflex, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_TILDE, XK_dead_tilde, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_MACRON, XK_dead_macron, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_BREVE, XK_dead_breve, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_ABOVEDOT, XK_dead_abovedot, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_DIAERESIS, XK_dead_diaeresis, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_ABOVERING, XK_dead_abovering, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_DOUBLEACUTE, XK_dead_doubleacute, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_CARON, XK_dead_caron, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_CEDILLA, XK_dead_cedilla, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_OGONEK, XK_dead_ogonek, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_IOTA, XK_dead_iota, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_VOICED_SOUND, XK_dead_voiced_sound, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_SEMIVOICED_SOUND, XK_dead_semivoiced_sound, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Sun vendor-specific dead key mappings (for European keyboards) */ |
| {java_awt_event_KeyEvent_VK_DEAD_GRAVE, SunXK_FA_Grave, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_CIRCUMFLEX, SunXK_FA_Circum, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_TILDE, SunXK_FA_Tilde, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_ACUTE, SunXK_FA_Acute, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_DIAERESIS, SunXK_FA_Diaeresis, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_CEDILLA, SunXK_FA_Cedilla, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* DEC vendor-specific dead key mappings (for European keyboards) */ |
| {java_awt_event_KeyEvent_VK_DEAD_ABOVERING, DXK_ring_accent, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_CIRCUMFLEX, DXK_circumflex_accent, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_CEDILLA, DXK_cedilla_accent, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_ACUTE, DXK_acute_accent, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_GRAVE, DXK_grave_accent, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_TILDE, DXK_tilde, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_DIAERESIS, DXK_diaeresis, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| /* Other vendor-specific dead key mappings (for European keyboards) */ |
| {java_awt_event_KeyEvent_VK_DEAD_ACUTE, hpXK_mute_acute, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_GRAVE, hpXK_mute_grave, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_CIRCUMFLEX, hpXK_mute_asciicircum, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_DIAERESIS, hpXK_mute_diaeresis, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| {java_awt_event_KeyEvent_VK_DEAD_TILDE, hpXK_mute_asciitilde, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_STANDARD}, |
| |
| {java_awt_event_KeyEvent_VK_UNDEFINED, NoSymbol, FALSE, java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN} |
| }; |
| |
| static Boolean |
| keyboardHasKanaLockKey() |
| { |
| static Boolean haveResult = FALSE; |
| static Boolean result = FALSE; |
| |
| int32_t minKeyCode, maxKeyCode, keySymsPerKeyCode; |
| KeySym *keySyms, *keySymsStart, keySym; |
| int32_t i; |
| int32_t kanaCount = 0; |
| |
| // Solaris doesn't let you swap keyboards without rebooting, |
| // so there's no need to check for the kana lock key more than once. |
| if (haveResult) { |
| return result; |
| } |
| |
| // There's no direct way to determine whether the keyboard has |
| // a kana lock key. From available keyboard mapping tables, it looks |
| // like only keyboards with the kana lock key can produce keysyms |
| // for kana characters. So, as an indirect test, we check for those. |
| |
| XDisplayKeycodes(awt_display, &minKeyCode, &maxKeyCode); |
| keySyms = XGetKeyboardMapping(awt_display, minKeyCode, maxKeyCode - minKeyCode + 1, &keySymsPerKeyCode); |
| keySymsStart = keySyms; |
| for (i = 0; i < (maxKeyCode - minKeyCode + 1) * keySymsPerKeyCode; i++) { |
| keySym = *keySyms++; |
| if ((keySym & 0xff00) == 0x0400) { |
| kanaCount++; |
| } |
| } |
| XFree(keySymsStart); |
| |
| // use a (somewhat arbitrary) minimum so we don't get confused by a stray function key |
| result = kanaCount > 10; |
| haveResult = TRUE; |
| return result; |
| } |
| |
| void |
| keysymToAWTKeyCode(KeySym x11Key, jint *keycode, Boolean *mapsToUnicodeChar, |
| jint *keyLocation) |
| { |
| int32_t i; |
| |
| // Solaris uses XK_Mode_switch for both the non-locking AltGraph |
| // and the locking Kana key, but we want to keep them separate for |
| // KeyEvent. |
| if (x11Key == XK_Mode_switch && keyboardHasKanaLockKey()) { |
| *keycode = java_awt_event_KeyEvent_VK_KANA_LOCK; |
| *mapsToUnicodeChar = FALSE; |
| *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN; |
| return; |
| } |
| |
| for (i = 0; |
| keymapTable[i].awtKey != java_awt_event_KeyEvent_VK_UNDEFINED; |
| i++) { |
| if (keymapTable[i].x11Key == x11Key) { |
| *keycode = keymapTable[i].awtKey; |
| *mapsToUnicodeChar = keymapTable[i].mapsToUnicodeChar; |
| *keyLocation = keymapTable[i].keyLocation; |
| return; |
| } |
| } |
| |
| *keycode = java_awt_event_KeyEvent_VK_UNDEFINED; |
| *mapsToUnicodeChar = FALSE; |
| *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN; |
| |
| DTRACE_PRINTLN1("keysymToAWTKeyCode: no key mapping found: keysym = %x", x11Key); |
| } |
| |
| KeySym |
| awt_getX11KeySym(jint awtKey) |
| { |
| int32_t i; |
| |
| if (awtKey == java_awt_event_KeyEvent_VK_KANA_LOCK && keyboardHasKanaLockKey()) { |
| return XK_Mode_switch; |
| } |
| |
| for (i = 0; keymapTable[i].awtKey != 0; i++) { |
| if (keymapTable[i].awtKey == awtKey) { |
| return keymapTable[i].x11Key; |
| } |
| } |
| |
| DTRACE_PRINTLN1("awt_getX11KeySym: no key mapping found: awtKey = %x", awtKey); |
| return NoSymbol; |
| } |
| |
| |
| typedef struct COLLAPSE_INFO { |
| Window win; |
| DamageRect *r; |
| } CollapseInfo; |
| |
| static void |
| expandDamageRect(DamageRect * drect, XEvent * xev, Boolean debug, char *str) |
| { |
| int32_t x1 = xev->xexpose.x; |
| int32_t y1 = xev->xexpose.y; |
| int32_t x2 = x1 + xev->xexpose.width; |
| int32_t y2 = y1 + xev->xexpose.height; |
| |
| /* |
| if (debug) { |
| printf(" %s: collapsing (%d,%d %dx%d) into (%d,%d %dx%d) ->>", |
| str, x1, y1, xev->xexpose.width, xev->xexpose.height, |
| drect->x1, drect->y1, drect->x2 - drect->x1, drect->y2 - drect->y1); |
| } |
| */ |
| |
| drect->x1 = MIN(x1, drect->x1); |
| drect->y1 = MIN(y1, drect->y1); |
| drect->x2 = MAX(x2, drect->x2); |
| drect->y2 = MAX(y2, drect->y2); |
| |
| /* |
| if (debug) { |
| printf("(%d,%d %dx%d) %s\n", |
| drect->x1, drect->y1, drect->x2 - drect->x1, drect->y2 - drect->y1); |
| } |
| */ |
| |
| } |
| |
| static Bool |
| checkForExpose(Display * dpy, XEvent * evt, XPointer client_data) |
| { |
| CollapseInfo *cinfo = (CollapseInfo *) client_data; |
| |
| if ((evt->type == Expose && evt->xexpose.window == cinfo->win && |
| INTERSECTS(cinfo->r->x1, cinfo->r->x2, cinfo->r->y1, cinfo->r->y2, |
| evt->xexpose.x, |
| evt->xexpose.x + evt->xexpose.width, |
| evt->xexpose.y, |
| evt->xexpose.y + evt->xexpose.height)) || |
| (evt->type == GraphicsExpose && evt->xgraphicsexpose.drawable == cinfo->win && |
| INTERSECTS(cinfo->r->x1, cinfo->r->x2, cinfo->r->y1, cinfo->r->y2, |
| evt->xgraphicsexpose.x, |
| evt->xgraphicsexpose.x + evt->xgraphicsexpose.width, |
| evt->xgraphicsexpose.y, |
| evt->xgraphicsexpose.y + evt->xgraphicsexpose.height))) { |
| |
| return True; |
| } |
| return False; |
| } |
| |
| /* |
| * javaObject is an MComponentPeer instance |
| */ |
| static void |
| HandleExposeEvent(Widget w, jobject javaObject, XEvent * event) |
| { |
| jobject target; |
| jint wdth, hght; |
| |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| |
| switch (event->type) { |
| case Expose: |
| case GraphicsExpose: |
| { |
| struct ComponentData *cdata; |
| Boolean debug = FALSE; |
| jint drawState; |
| |
| /* Set the draw state */ |
| drawState = (*env)->GetIntField(env, javaObject, |
| mComponentPeerIDs.drawState); |
| (*env)->SetIntField(env, javaObject, mComponentPeerIDs.drawState, |
| drawState | JAWT_LOCK_CLIP_CHANGED); |
| cdata = (struct ComponentData *) |
| JNU_GetLongFieldAsPtr(env, javaObject, mComponentPeerIDs.pData); |
| if (JNU_IsNull(env, javaObject) || (cdata == NULL)) { |
| return; |
| } |
| if (event->xexpose.send_event) { |
| if (cdata->repaintPending & RepaintPending_REPAINT) { |
| cdata->repaintPending &= ~RepaintPending_REPAINT; |
| |
| JNU_CallMethodByName(env, |
| NULL, |
| javaObject, |
| "handleRepaint", |
| "(IIII)V", |
| (jint) cdata->repaintRect.x1, |
| (jint) cdata->repaintRect.y1, |
| (jint) cdata->repaintRect.x2 |
| - cdata->repaintRect.x1, |
| (jint) cdata->repaintRect.y2 |
| - cdata->repaintRect.y1); |
| if ((*env)->ExceptionOccurred(env)) { |
| (*env)->ExceptionDescribe(env); |
| (*env)->ExceptionClear(env); |
| } |
| } |
| return; |
| } |
| if ((cdata->repaintPending & RepaintPending_EXPOSE) == 0) { |
| cdata->exposeRect.x1 = event->xexpose.x; |
| cdata->exposeRect.y1 = event->xexpose.y; |
| cdata->exposeRect.x2 = cdata->exposeRect.x1 + event->xexpose.width; |
| cdata->exposeRect.y2 = cdata->exposeRect.y1 + event->xexpose.height; |
| cdata->repaintPending |= RepaintPending_EXPOSE; |
| } else { |
| expandDamageRect(&(cdata->exposeRect), event, debug, "1"); |
| } |
| |
| /* Only post Expose/Repaint if we know others arn't following |
| * directly in the queue. |
| */ |
| if (event->xexpose.count == 0) { |
| int32_t count = 0; |
| CollapseInfo cinfo; |
| |
| cinfo.win = XtWindow(w); |
| cinfo.r = &(cdata->exposeRect); |
| |
| /* Do a little more inspecting and collapse further if there |
| * are additional expose events pending on this window where |
| * the damage rects intersect with the current exposeRect. |
| */ |
| while (TRUE) { |
| XEvent xev; |
| |
| if (XCheckIfEvent(XtDisplay(w), &xev |
| ,checkForExpose, (XtPointer) & cinfo)) { |
| count = xev.xexpose.count; |
| expandDamageRect(&(cdata->exposeRect), &xev, debug, "2"); |
| |
| } else { |
| /* XCheckIfEvent Failed. */ |
| break; |
| } |
| } |
| |
| cdata->repaintPending &= ~RepaintPending_EXPOSE; |
| |
| /* Fix for bugtraq id 4262108. Paint events should not be |
| * delivered to components that have one of their |
| * dimensions equal to zero. |
| */ |
| |
| if ((*env)->EnsureLocalCapacity(env, 1) < 0) { |
| return; |
| } |
| |
| target = (*env)->GetObjectField(env, javaObject, |
| mComponentPeerIDs.target); |
| wdth = (*env)->GetIntField(env, target, componentIDs.width); |
| hght = (*env)->GetIntField(env, target, componentIDs.height); |
| (*env)->DeleteLocalRef(env, target); |
| |
| if ( wdth != 0 && hght != 0) { |
| JNU_CallMethodByName(env, |
| NULL, |
| javaObject, |
| "handleExpose", |
| "(IIII)V", |
| (jint) cdata->exposeRect.x1, |
| (jint) cdata->exposeRect.y1, |
| (jint) cdata->exposeRect.x2 |
| - cdata->exposeRect.x1, |
| (jint) cdata->exposeRect.y2 |
| - cdata->exposeRect.y1); |
| if ((*env)->ExceptionOccurred(env)) { |
| (*env)->ExceptionDescribe(env); |
| (*env)->ExceptionClear(env); |
| } |
| } |
| } |
| } |
| break; |
| |
| default: |
| jio_fprintf(stderr, "Got event %d in HandleExposeEvent!\n", event->type); |
| } |
| } |
| |
| /* We always store and return JNI GlobalRefs. */ |
| static jweak focusOwnerPeer = NULL; |
| static jweak focusedWindowPeer = NULL; |
| |
| /* |
| * This function should only be called under the |
| * protection of AWT_LOCK(). Otherwise, multithreaded access |
| * can corrupt the value of focusOwnerPeer variable. |
| * This function returns LocalRef, result should be deleted |
| * explicitly if called on a thread that never returns to |
| * Java. |
| */ |
| jobject |
| awt_canvas_getFocusOwnerPeer() { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| jobject res; |
| AWT_LOCK(); |
| res = (*env)->NewLocalRef(env, focusOwnerPeer); |
| AWT_UNLOCK(); |
| return res; |
| } |
| |
| /* |
| * This function should only be called under the |
| * protection of AWT_LOCK(). Otherwise, multithreaded access |
| * can corrupt the value of focusedWindowPeer variable. |
| * This function returns LocalRef, result should be deleted |
| * explicitly if called on a thread that never returns to |
| * Java. |
| */ |
| jobject |
| awt_canvas_getFocusedWindowPeer() { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| jobject res; |
| AWT_LOCK(); |
| res = (*env)->NewLocalRef(env, focusedWindowPeer); |
| AWT_UNLOCK(); |
| return res; |
| } |
| |
| /* |
| * Only call this function under AWT_LOCK(). Otherwise, multithreaded |
| * access can corrupt the value of focusOwnerPeer variable. |
| */ |
| void |
| awt_canvas_setFocusOwnerPeer(jobject peer) { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| AWT_LOCK(); |
| if (focusOwnerPeer != NULL) { |
| (*env)->DeleteWeakGlobalRef(env, focusOwnerPeer); |
| } |
| focusOwnerPeer = (peer != NULL) |
| ? (*env)->NewWeakGlobalRef(env, peer) : NULL; |
| AWT_UNLOCK(); |
| } |
| |
| /* |
| * Only call this function under AWT_LOCK(). Otherwise, multithreaded |
| * access can corrupt the value of focusedWindowPeer variable. |
| */ |
| void |
| awt_canvas_setFocusedWindowPeer(jobject peer) { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| AWT_LOCK(); |
| if (focusedWindowPeer != NULL) { |
| (*env)->DeleteWeakGlobalRef(env, focusedWindowPeer); |
| } |
| focusedWindowPeer = (peer != NULL) |
| ? (*env)->NewWeakGlobalRef(env, peer) : NULL; |
| AWT_UNLOCK(); |
| } |
| |
| void callFocusCallback(jobject focusPeer, int focus_type, jobject cause) { |
| awt_post_java_focus_event(focusPeer, |
| focus_type, |
| cause, |
| NULL); |
| awt_canvas_setFocusOwnerPeer(focusPeer); |
| } |
| |
| |
| void |
| handleFocusEvent(Widget w, |
| XFocusChangeEvent * fevent, |
| XtPointer client_data, |
| Boolean * cont, |
| Boolean passEvent, |
| jobject cause) |
| { |
| if (fevent->type == FocusIn) { |
| if (fevent->mode == NotifyNormal && |
| fevent->detail != NotifyPointer && fevent->detail != NotifyVirtual) |
| { |
| #ifdef DEBUG_FOCUS |
| printf("window = %d, mode = %d, detail = %d\n", fevent->window, fevent->mode, fevent->detail); |
| printf("----posting java FOCUS GAINED on window %d, pass = %d\n", XtWindow(w), passEvent); |
| #endif |
| awt_post_java_focus_event(client_data, |
| java_awt_event_FocusEvent_FOCUS_GAINED, |
| cause, |
| NULL); |
| awt_canvas_setFocusOwnerPeer(client_data); |
| } |
| } else { |
| /* FocusOut */ |
| if (fevent->mode == NotifyNormal && |
| fevent->detail != NotifyPointer && fevent->detail != NotifyVirtual) |
| { |
| #ifdef DEBUG_FOCUS |
| printf("window = %d, mode = %d, detail = %d\n", fevent->window, fevent->mode, fevent->detail); |
| printf("----posting java FOCUS LOST on window %d, pass = %d, temp = %d\n", XtWindow(w), passEvent, temp); |
| #endif |
| awt_post_java_focus_event(client_data, |
| java_awt_event_FocusEvent_FOCUS_LOST, |
| cause, |
| NULL); |
| awt_canvas_setFocusOwnerPeer(NULL); |
| } |
| } |
| *cont = TRUE; |
| } |
| |
| void callFocusHandler(Widget w, int eventType, jobject cause) { |
| jobject peer = NULL; |
| XFocusChangeEvent event; |
| Boolean cont; |
| JNIEnv *env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| |
| if (w == NULL) { |
| return; |
| } |
| |
| peer = findPeer(&w); |
| if (peer == NULL) { |
| w = findTopLevelByShell(w); |
| if (w != NULL) { |
| peer = findPeer(&w); |
| } |
| } |
| if (peer == NULL) { |
| return; |
| } |
| memset(&event, 0, sizeof(event)); |
| event.type = eventType; |
| event.mode = NotifyNormal; |
| event.detail = NotifyAncestor; |
| event.window = XtWindow(w); |
| cont = FALSE; |
| handleFocusEvent(w, &event, (XtPointer)peer, &cont, TRUE, cause); |
| } |
| |
| /** |
| * Copy XEvent to jbyteArray and save it in AWTEvent |
| */ |
| void |
| awt_copyXEventToAWTEvent(JNIEnv *env, XEvent * xev, jobject jevent) |
| { |
| jbyteArray bdata; |
| if (xev != NULL) { |
| if ((*env)->EnsureLocalCapacity(env, 1) < 0) { |
| return; |
| } |
| bdata = (*env)->NewByteArray(env, sizeof(XEvent)); |
| if (bdata != NULL) { |
| (*env)->SetByteArrayRegion(env, bdata, 0, sizeof(XEvent), |
| (jbyte *)xev); |
| (*env)->SetObjectField(env, jevent, awtEventIDs.bdata, bdata); |
| (*env)->DeleteLocalRef(env, bdata); |
| } |
| } |
| } |
| |
| /* Returns new modifiers set like ???_DOWN_MASK for keyboard and mouse after the event. |
| * The modifiers on a Java key event reflect the state of the modifier keys |
| * immediately AFTER the key press or release. This usually doesn't require |
| * us to change the modifiers: the exception is when the key pressed or |
| * released is a modifier key. Since the state of an XEvent represents |
| * the modifiers BEFORE the event, we change the modifiers according to |
| * the button and keycode. |
| */ |
| jint |
| getModifiers(uint32_t state, jint button, jint keyCode) |
| { |
| jint modifiers = 0; |
| |
| if (((state & ShiftMask) != 0) ^ (keyCode == java_awt_event_KeyEvent_VK_SHIFT)) |
| { |
| modifiers |= java_awt_event_InputEvent_SHIFT_DOWN_MASK; |
| } |
| if (((state & ControlMask) != 0) ^ (keyCode == java_awt_event_KeyEvent_VK_CONTROL)) |
| { |
| modifiers |= java_awt_event_InputEvent_CTRL_DOWN_MASK; |
| } |
| if (((state & awt_MetaMask) != 0) ^ (keyCode == java_awt_event_KeyEvent_VK_META)) |
| { |
| modifiers |= java_awt_event_InputEvent_META_DOWN_MASK; |
| } |
| if (((state & awt_AltMask) != 0) ^ (keyCode == java_awt_event_KeyEvent_VK_ALT)) |
| { |
| modifiers |= java_awt_event_InputEvent_ALT_DOWN_MASK; |
| } |
| if (((state & awt_ModeSwitchMask) != 0) ^ (keyCode == java_awt_event_KeyEvent_VK_ALT_GRAPH)) |
| { |
| modifiers |= java_awt_event_InputEvent_ALT_GRAPH_DOWN_MASK; |
| } |
| if (((state & Button1Mask) != 0) ^ (button == java_awt_event_MouseEvent_BUTTON1)) { |
| modifiers |= java_awt_event_InputEvent_BUTTON1_DOWN_MASK; |
| } |
| if (((state & Button2Mask) != 0) ^ (button == java_awt_event_MouseEvent_BUTTON2)) { |
| modifiers |= java_awt_event_InputEvent_BUTTON2_DOWN_MASK; |
| } |
| if (((state & Button3Mask) != 0) ^ (button == java_awt_event_MouseEvent_BUTTON3)) { |
| modifiers |= java_awt_event_InputEvent_BUTTON3_DOWN_MASK; |
| } |
| return modifiers; |
| } |
| |
| /* Returns which mouse button has changed state |
| */ |
| jint |
| getButton(uint32_t button) |
| { |
| switch (button) { |
| case Button1: |
| return java_awt_event_MouseEvent_BUTTON1; |
| case Button2: |
| return java_awt_event_MouseEvent_BUTTON2; |
| case Button3: |
| return java_awt_event_MouseEvent_BUTTON3; |
| } |
| return java_awt_event_MouseEvent_NOBUTTON; |
| } |
| |
| |
| /* This function changes the state of the native XEvent AFTER |
| * the corresponding Java event has been processed. The XEvent |
| * needs to be modified before it is dispatched to the native widget. |
| */ |
| void |
| awt_modify_KeyEvent(JNIEnv *env, XEvent *xevent, jobject jevent) |
| { |
| jint keyCode; |
| jchar keyChar; |
| jint modifiers; |
| KeySym keysym = (KeySym) java_awt_event_KeyEvent_CHAR_UNDEFINED; |
| |
| if (xevent->type != KeyPress && xevent->type != KeyRelease) { |
| return; |
| } |
| |
| keyCode = (*env)->GetIntField(env, jevent, keyEventIDs.keyCode); |
| keyChar = (*env)->GetCharField(env, jevent, keyEventIDs.keyChar); |
| modifiers = (*env)->GetIntField(env, jevent, inputEventIDs.modifiers); |
| |
| switch (keyCode) { |
| case java_awt_event_KeyEvent_VK_MULTIPLY: |
| case java_awt_event_KeyEvent_VK_SUBTRACT: |
| case java_awt_event_KeyEvent_VK_DIVIDE: |
| /* Bugid 4103229: Change the X event so these three Numpad |
| * keys work with the NumLock off. For some reason, Motif |
| * widgets ignore the events produced by these three keys |
| * unless the NumLock is on. It also ignores them if some |
| * other modifiers are set. Turn off ALL modifiers, then |
| * turn NumLock mask on in the X event. |
| */ |
| xevent->xkey.state = awt_NumLockMask; |
| return; |
| case java_awt_event_KeyEvent_VK_ENTER: |
| case java_awt_event_KeyEvent_VK_BACK_SPACE: |
| case java_awt_event_KeyEvent_VK_TAB: |
| case java_awt_event_KeyEvent_VK_ESCAPE: |
| case java_awt_event_KeyEvent_VK_ADD: |
| case java_awt_event_KeyEvent_VK_DECIMAL: |
| case java_awt_event_KeyEvent_VK_NUMPAD0: |
| case java_awt_event_KeyEvent_VK_NUMPAD1: |
| case java_awt_event_KeyEvent_VK_NUMPAD2: |
| case java_awt_event_KeyEvent_VK_NUMPAD3: |
| case java_awt_event_KeyEvent_VK_NUMPAD4: |
| case java_awt_event_KeyEvent_VK_NUMPAD5: |
| case java_awt_event_KeyEvent_VK_NUMPAD6: |
| case java_awt_event_KeyEvent_VK_NUMPAD7: |
| case java_awt_event_KeyEvent_VK_NUMPAD8: |
| case java_awt_event_KeyEvent_VK_NUMPAD9: |
| keysym = awt_getX11KeySym(keyCode); |
| break; |
| case java_awt_event_KeyEvent_VK_DELETE: |
| /* For some reason XKeysymToKeycode returns incorrect value for |
| * Delete, so we don't want to modify the original event |
| */ |
| break; |
| default: |
| if (keyChar < (KeySym) 256) { |
| keysym = (KeySym) keyChar; |
| } else { |
| keysym = awt_getX11KeySym(keyCode); |
| } |
| break; |
| } |
| |
| if (keysym < (KeySym) 256) { |
| if (modifiers & java_awt_event_InputEvent_CTRL_MASK) { |
| switch (keysym + 64) { |
| case '[': |
| case ']': |
| case '\\': |
| case '_': |
| keysym += 64; |
| break; |
| default: |
| if (isalpha((int32_t)(keysym + 'a' - 1))) { |
| keysym += ('a' - 1); |
| } |
| break; |
| } |
| } |
| /* |
| * 0xff61 is Unicode value of first XK_kana_fullstop. |
| * We need X Keysym to Unicode map in post1.1 release |
| * to support more international keyboards. |
| */ |
| if (keysym >= (KeySym) 0xff61 && keysym <= (KeySym) 0xff9f) { |
| keysym = keysym - 0xff61 + XK_kana_fullstop; |
| } |
| xevent->xkey.keycode = XKeysymToKeycode(awt_display, keysym); |
| } |
| |
| if (keysym >= 'A' && keysym <= 'Z') { |
| xevent->xkey.state |= ShiftMask; |
| } |
| if (modifiers & java_awt_event_InputEvent_SHIFT_DOWN_MASK) { |
| xevent->xkey.state |= ShiftMask; |
| } |
| if (modifiers & java_awt_event_InputEvent_CTRL_DOWN_MASK) { |
| xevent->xkey.state |= ControlMask; |
| } |
| if (modifiers & java_awt_event_InputEvent_META_DOWN_MASK) { |
| xevent->xkey.state |= awt_MetaMask; |
| } |
| if (modifiers & java_awt_event_InputEvent_ALT_DOWN_MASK) { |
| xevent->xkey.state |= awt_AltMask; |
| } |
| if (modifiers & java_awt_event_InputEvent_ALT_GRAPH_DOWN_MASK) { |
| xevent->xkey.state |= awt_ModeSwitchMask; |
| } |
| if (modifiers & java_awt_event_InputEvent_BUTTON1_DOWN_MASK) { |
| xevent->xkey.state |= Button1Mask; |
| } |
| if (modifiers & java_awt_event_InputEvent_BUTTON2_DOWN_MASK) { |
| xevent->xkey.state |= Button2Mask; |
| } |
| if (modifiers & java_awt_event_InputEvent_BUTTON3_DOWN_MASK) { |
| xevent->xkey.state |= Button3Mask; |
| } |
| } |
| |
| |
| /* Called from handleKeyEvent. The purpose of this function is |
| * to check for a list of vendor-specific keysyms, most of which |
| * have values greater than 0xFFFF. Most of these keys don't map |
| * to unicode characters, but some do. |
| * |
| * For keys that don't map to unicode characters, the keysym |
| * is irrelevant at this point. We set the keysym to zero |
| * to ensure that the switch statement immediately below |
| * this function call (in adjustKeySym) won't incorrectly act |
| * on them after the high bits are stripped off. |
| * |
| * For keys that do map to unicode characters, we change the keysym |
| * to the equivalent that is < 0xFFFF |
| */ |
| static void |
| handleVendorKeySyms(XEvent *event, KeySym *keysym) |
| { |
| KeySym originalKeysym = *keysym; |
| |
| switch (*keysym) { |
| /* Apollo (HP) vendor-specific from <X11/ap_keysym.h> */ |
| case apXK_Copy: |
| case apXK_Cut: |
| case apXK_Paste: |
| /* DEC vendor-specific from <X11/DECkeysym.h> */ |
| case DXK_ring_accent: /* syn usldead_ring */ |
| case DXK_circumflex_accent: |
| case DXK_cedilla_accent: /* syn usldead_cedilla */ |
| case DXK_acute_accent: |
| case DXK_grave_accent: |
| case DXK_tilde: |
| case DXK_diaeresis: |
| /* Sun vendor-specific from <X11/Sunkeysym.h> */ |
| case SunXK_FA_Grave: |
| case SunXK_FA_Circum: |
| case SunXK_FA_Tilde: |
| case SunXK_FA_Acute: |
| case SunXK_FA_Diaeresis: |
| case SunXK_FA_Cedilla: |
| case SunXK_F36: /* Labeled F11 */ |
| case SunXK_F37: /* Labeled F12 */ |
| case SunXK_Props: |
| case SunXK_Copy: |
| case SunXK_Open: |
| case SunXK_Paste: |
| case SunXK_Cut: |
| /* Other vendor-specific from HPkeysym.h */ |
| case hpXK_mute_acute: /* syn usldead_acute */ |
| case hpXK_mute_grave: /* syn usldead_grave */ |
| case hpXK_mute_asciicircum: /* syn usldead_asciicircum */ |
| case hpXK_mute_diaeresis: /* syn usldead_diaeresis */ |
| case hpXK_mute_asciitilde: /* syn usldead_asciitilde */ |
| case osfXK_Copy: |
| case osfXK_Cut: |
| case osfXK_Paste: |
| case osfXK_PageUp: |
| case osfXK_PageDown: |
| case osfXK_EndLine: |
| case osfXK_Clear: |
| case osfXK_Left: |
| case osfXK_Up: |
| case osfXK_Right: |
| case osfXK_Down: |
| case osfXK_Prior: |
| case osfXK_Next: |
| case osfXK_Insert: |
| case osfXK_Undo: |
| case osfXK_Help: |
| *keysym = 0; |
| break; |
| /* |
| * The rest DO map to unicode characters, so translate them |
| */ |
| case osfXK_BackSpace: |
| *keysym = XK_BackSpace; |
| break; |
| case osfXK_Escape: |
| *keysym = XK_Escape; |
| break; |
| case osfXK_Cancel: |
| *keysym = XK_Cancel; |
| break; |
| case osfXK_Delete: |
| *keysym = XK_Delete; |
| break; |
| default: |
| break; |
| } |
| |
| if (originalKeysym != *keysym) { |
| DTRACE_PRINTLN2("In handleVendorKeySyms: originalKeysym=%x, keysym=%x", |
| originalKeysym, *keysym); |
| } |
| } |
| |
| /* Called from handleKeyEvent. |
| * The purpose of this function is to adjust the keysym and XEvent |
| * keycode for a key event. This is basically a conglomeration of |
| * bugfixes that require these adjustments. |
| */ |
| static void |
| adjustKeySym(XEvent *event, KeySym *keysym) |
| { |
| KeySym originalKeysym = *keysym; |
| |
| /* We have seen bits set in the high two bytes on Linux, |
| * which prevents this switch statement from executing |
| * correctly. Strip off the high order bits. |
| */ |
| *keysym &= 0x0000FFFF; |
| |
| switch (*keysym) { |
| case XK_Return: |
| *keysym = XK_Linefeed; /* fall thru */ |
| case XK_BackSpace: |
| case XK_Tab: |
| case XK_Linefeed: |
| case XK_Escape: |
| case XK_Delete: |
| /* strip off highorder bits defined in keysymdef.h |
| * I think doing this converts them to values that |
| * we can cast to jchars and use as java keychars. |
| * If so, it's really a hack. |
| */ |
| *keysym &= 0x007F; |
| break; |
| case XK_Cancel: |
| *keysym = 0x0018; /* the unicode char for Cancel */ |
| break; |
| case XK_KP_Decimal: |
| *keysym = '.'; |
| break; |
| case XK_KP_Add: |
| *keysym = '+'; |
| break; |
| case XK_F24: /* NumLock off */ |
| case XK_KP_Subtract: /* NumLock on */ |
| *keysym = '-'; |
| break; |
| case XK_F25: /* NumLock off */ |
| case XK_KP_Divide: /* NumLock on */ |
| *keysym = '/'; |
| break; |
| case XK_F26: /* NumLock off */ |
| case XK_KP_Multiply: /* NumLock on */ |
| *keysym = '*'; |
| break; |
| case XK_KP_Equal: |
| *keysym = '='; |
| break; |
| case XK_KP_0: |
| *keysym = '0'; |
| break; |
| case XK_KP_1: |
| *keysym = '1'; |
| break; |
| case XK_KP_2: |
| *keysym = '2'; |
| break; |
| case XK_KP_3: |
| *keysym = '3'; |
| break; |
| case XK_KP_4: |
| *keysym = '4'; |
| break; |
| case XK_KP_5: |
| *keysym = '5'; |
| break; |
| case XK_KP_6: |
| *keysym = '6'; |
| break; |
| case XK_KP_7: |
| *keysym = '7'; |
| break; |
| case XK_KP_8: |
| *keysym = '8'; |
| break; |
| case XK_KP_9: |
| *keysym = '9'; |
| break; |
| case XK_KP_Left: /* Bug 4350175 */ |
| *keysym = XK_Left; |
| event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); |
| break; |
| case XK_KP_Up: |
| *keysym = XK_Up; |
| event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); |
| break; |
| case XK_KP_Right: |
| *keysym = XK_Right; |
| event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); |
| break; |
| case XK_KP_Down: |
| *keysym = XK_Down; |
| event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); |
| break; |
| case XK_KP_Home: |
| *keysym = XK_Home; |
| event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); |
| break; |
| case XK_KP_End: |
| *keysym = XK_End; |
| event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); |
| break; |
| case XK_KP_Page_Up: |
| *keysym = XK_Page_Up; |
| event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); |
| break; |
| case XK_KP_Page_Down: |
| *keysym = XK_Page_Down; |
| event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); |
| break; |
| case XK_KP_Begin: |
| *keysym = XK_Begin; |
| event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); |
| break; |
| case XK_KP_Insert: |
| *keysym = XK_Insert; |
| event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); |
| break; |
| case XK_KP_Delete: |
| *keysym = XK_Delete; |
| event->xkey.keycode = XKeysymToKeycode(awt_display, *keysym); |
| *keysym &= 0x007F; |
| break; |
| case XK_KP_Enter: |
| *keysym = XK_Linefeed; |
| event->xkey.keycode = XKeysymToKeycode(awt_display, XK_Return); |
| *keysym &= 0x007F; |
| break; |
| default: |
| break; |
| } |
| |
| if (originalKeysym != *keysym) { |
| DTRACE_PRINTLN2("In adjustKeySym: originalKeysym=%x, keysym=%x", |
| originalKeysym, *keysym); |
| } |
| } |
| |
| /* |
| * What a sniffer sez? |
| * Xsun and Xorg if NumLock is on do two thing different: |
| * keep Keypad key in different places of keysyms array and |
| * ignore/obey "ModLock is ShiftLock", so we should choose. |
| * People say, it's right to use behavior and not Vendor tags to decide. |
| * Maybe. But why these tags were invented, then? |
| * TODO: use behavior, not tags. Maybe. |
| */ |
| static Boolean |
| isXsunServer(XEvent *event) { |
| if( awt_ServerDetected ) return awt_IsXsun; |
| if( strncmp( ServerVendor( event->xkey.display ), "Sun Microsystems, Inc.", 32) ) { |
| awt_ServerDetected = True; |
| awt_IsXsun = False; |
| return False; |
| } |
| // Now, it's Sun. It still may be Xorg though, eg on Solaris 10, x86. |
| // Today (2005), VendorRelease of Xorg is a Big Number unlike Xsun. |
| if( VendorRelease( event->xkey.display ) > 10000 ) { |
| awt_ServerDetected = True; |
| awt_IsXsun = False; |
| return False; |
| } |
| awt_ServerDetected = True; |
| awt_IsXsun = True; |
| return True; |
| } |
| static Boolean |
| isKPevent(XEvent *event) |
| { |
| /* |
| Xlib manual, ch 12.7 says, as a first rule for choice of keysym: |
| The numlock modifier is on and the second KeySym is a keypad KeySym. In this case, |
| if the Shift modifier is on, or if the Lock modifier is on and is interpreted as ShiftLock, |
| then the first KeySym is used, otherwise the second KeySym is used. |
| |
| However, Xsun server does ignore ShiftLock and always takes 3-rd element from an array. |
| |
| So, is it a keypad keysym? |
| */ |
| jint mods = getModifiers(event->xkey.state, 0, event->xkey.keycode); |
| Boolean bsun = isXsunServer( event ); |
| |
| return IsKeypadKey( XKeycodeToKeysym(event->xkey.display, event->xkey.keycode,(bsun && !awt_UseXKB ? 2 : 1) ) ); |
| } |
| /* |
| * In a next redesign, get rid of this code altogether. |
| * |
| */ |
| static void |
| handleKeyEventWithNumLockMask_New(XEvent *event, KeySym *keysym) |
| { |
| KeySym originalKeysym = *keysym; |
| if( !isKPevent( event ) ) { |
| return; |
| } |
| if( isXsunServer( event ) && !awt_UseXKB ) { |
| if( (event->xkey.state & ShiftMask) ) { // shift modifier is on |
| *keysym = XKeycodeToKeysym(event->xkey.display, |
| event->xkey.keycode, 3); |
| }else { |
| *keysym = XKeycodeToKeysym(event->xkey.display, |
| event->xkey.keycode, 2); |
| } |
| } else { |
| if( (event->xkey.state & ShiftMask) || // shift modifier is on |
| ((event->xkey.state & LockMask) && // lock modifier is on |
| (awt_ModLockIsShiftLock)) ) { // it is interpreted as ShiftLock |
| *keysym = XKeycodeToKeysym(event->xkey.display, |
| event->xkey.keycode, 0); |
| }else{ |
| *keysym = XKeycodeToKeysym(event->xkey.display, |
| event->xkey.keycode, 1); |
| } |
| } |
| } |
| |
| /* Called from handleKeyEvent. |
| * The purpose of this function is to make some adjustments to keysyms |
| * that have been found to be necessary when the NumLock mask is set. |
| * They come from various bug fixes and rearchitectures. |
| * This function is meant to be called when |
| * (event->xkey.state & awt_NumLockMask) is TRUE. |
| */ |
| static void |
| handleKeyEventWithNumLockMask(XEvent *event, KeySym *keysym) |
| { |
| KeySym originalKeysym = *keysym; |
| |
| #ifndef __linux__ |
| /* The following code on Linux will cause the keypad keys |
| * not to echo on JTextField when the NumLock is on. The |
| * keysyms will be 0, because the last parameter 2 is not defined. |
| * See Xlib Programming Manual, O'Reilly & Associates, Section |
| * 9.1.5 "Other Keyboard-handling Routines", "The meaning of |
| * the keysym list beyond the first two (unmodified, Shift or |
| * Shift Lock) is not defined." |
| */ |
| |
| /* Translate again with NumLock as modifier. */ |
| /* ECH - I wonder why we think that NumLock corresponds to 2? |
| * On Linux, we've seen xmodmap -pm yield mod2 as NumLock, |
| * but I don't know that it will be for every configuration. |
| * Perhaps using the index (modn in awt_MToolkit.c:setup_modifier_map) |
| * would be more correct. |
| */ |
| *keysym = XKeycodeToKeysym(event->xkey.display, |
| event->xkey.keycode, 2); |
| if (originalKeysym != *keysym) { |
| DTRACE_PRINTLN3("%s=%x, keysym=%x", |
| "In handleKeyEventWithNumLockMask ifndef linux: originalKeysym", |
| originalKeysym, *keysym); |
| } |
| #endif |
| |
| /* Note: the XK_R? key assignments are for Type 4 kbds */ |
| switch (*keysym) { |
| case XK_R13: |
| *keysym = XK_KP_1; |
| break; |
| case XK_R14: |
| *keysym = XK_KP_2; |
| break; |
| case XK_R15: |
| *keysym = XK_KP_3; |
| break; |
| case XK_R10: |
| *keysym = XK_KP_4; |
| break; |
| case XK_R11: |
| *keysym = XK_KP_5; |
| break; |
| case XK_R12: |
| *keysym = XK_KP_6; |
| break; |
| case XK_R7: |
| *keysym = XK_KP_7; |
| break; |
| case XK_R8: |
| *keysym = XK_KP_8; |
| break; |
| case XK_R9: |
| *keysym = XK_KP_9; |
| break; |
| case XK_KP_Insert: |
| *keysym = XK_KP_0; |
| break; |
| case XK_KP_Delete: |
| *keysym = XK_KP_Decimal; |
| break; |
| case XK_R4: |
| *keysym = XK_KP_Equal; /* Type 4 kbd */ |
| break; |
| case XK_R5: |
| *keysym = XK_KP_Divide; |
| break; |
| case XK_R6: |
| *keysym = XK_KP_Multiply; |
| break; |
| /* |
| * Need the following keysym changes for Linux key releases. |
| * Sometimes the modifier state gets messed up, so we get a |
| * KP_Left when we should get a KP_4, for example. |
| * XK_KP_Insert and XK_KP_Delete were already handled above. |
| */ |
| case XK_KP_Left: |
| *keysym = XK_KP_4; |
| break; |
| case XK_KP_Up: |
| *keysym = XK_KP_8; |
| break; |
| case XK_KP_Right: |
| *keysym = XK_KP_6; |
| break; |
| case XK_KP_Down: |
| *keysym = XK_KP_2; |
| break; |
| case XK_KP_Home: |
| *keysym = XK_KP_7; |
| break; |
| case XK_KP_End: |
| *keysym = XK_KP_1; |
| break; |
| case XK_KP_Page_Up: |
| *keysym = XK_KP_9; |
| break; |
| case XK_KP_Page_Down: |
| *keysym = XK_KP_3; |
| break; |
| case XK_KP_Begin: |
| *keysym = XK_KP_5; |
| break; |
| default: |
| break; |
| } |
| |
| if (originalKeysym != *keysym) { |
| DTRACE_PRINTLN2("In handleKeyEventWithNumLockMask: originalKeysym=%x, keysym=%x", |
| originalKeysym, *keysym); |
| } |
| } |
| |
| static void |
| handleKeyEvent(jint keyEventId, |
| XEvent *event, |
| XtPointer *client_data, |
| Boolean *cont, |
| Boolean passEvent) |
| { |
| KeySym keysym = NoSymbol; |
| jint keycode = java_awt_event_KeyEvent_VK_UNDEFINED; |
| Modifiers mods = 0; |
| Boolean mapsToUnicodeChar = FALSE; |
| jint keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN; |
| jint modifiers = 0; |
| |
| DTRACE_PRINTLN4("\nEntered handleKeyEvent: type=%d, xkeycode=%x, xstate=%x, keysym=%x", |
| event->type, event->xkey.keycode, event->xkey.state, keysym); |
| |
| if (currentX11InputMethodInstance != NULL |
| && keyEventId == java_awt_event_KeyEvent_KEY_PRESSED |
| && event->xkey.window == currentFocusWindow) |
| { |
| /* invokes XmbLookupString to get a committed string or keysym if any. */ |
| if (awt_x11inputmethod_lookupString((XKeyPressedEvent*)event, &keysym)) { |
| *cont = FALSE; |
| return; |
| } |
| } |
| |
| /* Ignore the keysym found immediately above in |
| * awt_x11inputmethod_lookupString; the methodology in that function |
| * sometimes returns incorrect results. |
| * |
| * Get keysym without taking modifiers into account first. |
| * This keysym is not necessarily for the character that was typed: |
| * it is for the primary layer. So, if $ were typed by pressing |
| * shift-4, this call should give us 4, not $ |
| * |
| * We only want this keysym so we can use it to index into the |
| * keymapTable to get the Java keycode associated with the |
| * primary layer key that was pressed. |
| */ |
| keysym = XKeycodeToKeysym(event->xkey.display, event->xkey.keycode, 0); |
| |
| /* Linux: Sometimes the keysym returned is uppercase when CapsLock is |
| * on and LockMask is not set in event->xkey.state. |
| */ |
| if (keysym >= (KeySym) 'A' && keysym <= (KeySym) 'Z') { |
| event->xkey.state |= LockMask; |
| keysym = (KeySym) tolower((int32_t) keysym); |
| } |
| |
| DTRACE_PRINTLN4("In handleKeyEvent: type=%d, xkeycode=%x, xstate=%x, keysym=%x", |
| event->type, event->xkey.keycode, event->xkey.state, keysym); |
| |
| if (keysym == NoSymbol) { |
| *cont = TRUE; |
| return; |
| } |
| |
| if (keysym < (KeySym) 256) { |
| keysymToAWTKeyCode(keysym, &keycode, &mapsToUnicodeChar, &keyLocation); |
| |
| /* Now get real keysym which looks at modifiers |
| * XtGetActionKeySym() returns wrong value with Kana Lock, |
| * so use XtTranslateKeycode(). |
| */ |
| XtTranslateKeycode(event->xkey.display, (KeyCode) event->xkey.keycode, |
| event->xkey.state, &mods, &keysym); |
| DTRACE_PRINTLN6("%s: type=%d, xkeycode=%x, xstate=%x, keysym=%x, xmods=%d", |
| "In handleKeyEvent keysym<256 ", event->type, event->xkey.keycode, |
| event->xkey.state, keysym, mods); |
| |
| /* Linux: With caps lock on, chars echo lowercase. */ |
| if ((event->xkey.state & LockMask) && |
| (keysym >= (KeySym) 'a' && keysym <= (KeySym) 'z')) |
| { |
| keysym = (KeySym) toupper((int32_t) keysym); |
| } |
| |
| if ((event->xkey.state & ControlMask)) { |
| switch (keysym) { |
| case '[': |
| case ']': |
| case '\\': |
| case '_': |
| keysym -= 64; |
| break; |
| default: |
| if (isalpha((int32_t) keysym)) { |
| keysym = (KeySym) tolower((int32_t) keysym) - 'a' + 1; |
| } |
| break; |
| } |
| } |
| |
| if (keysym >= (KeySym) XK_kana_fullstop && |
| keysym <= (KeySym) XK_semivoicedsound) { |
| /* |
| * 0xff61 is Unicode value of first XK_kana_fullstop. |
| * We need X Keysym to Unicode map in post1.1 release |
| * to support more intenational keyboard. |
| */ |
| keysym = keysym - XK_kana_fullstop + 0xff61; |
| } |
| |
| modifiers = getModifiers(event->xkey.state, 0, keycode); |
| DTRACE_PRINTLN6("%s: type=%d, xkeycode=%x, xstate=%x, keysym=%x, AWTmodifiers=%d", |
| "In handleKeyEvent keysym<256 ", event->type, event->xkey.keycode, |
| event->xkey.state, keysym, modifiers); |
| |
| awt_post_java_key_event(client_data, |
| keyEventId, |
| (passEvent == TRUE) ? event : NULL, |
| event->xkey.time, |
| keycode, |
| (jchar) keysym, |
| modifiers, |
| keyLocation, |
| event); |
| |
| if (keyEventId == java_awt_event_KeyEvent_KEY_PRESSED) { |
| awt_post_java_key_event(client_data, |
| java_awt_event_KeyEvent_KEY_TYPED, |
| NULL, |
| event->xkey.time, |
| java_awt_event_KeyEvent_VK_UNDEFINED, |
| (jchar) keysym, |
| modifiers, |
| java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN, |
| event); |
| |
| } |
| } else { |
| if (event->xkey.state & awt_NumLockMask) { |
| if( awt_UseType4Patch ) { |
| handleKeyEventWithNumLockMask(event, &keysym); |
| }else{ |
| handleKeyEventWithNumLockMask_New(event, &keysym); |
| } |
| } |
| |
| if (keysym == XK_ISO_Left_Tab) { |
| keysym = XK_Tab; |
| } |
| |
| /* The keysym here does not consider modifiers, so these results |
| * are relevant to the KEY_PRESSED event only, not the KEY_TYPED |
| */ |
| keysymToAWTKeyCode(keysym, &keycode, &mapsToUnicodeChar, &keyLocation); |
| DTRACE_PRINTLN3("In handleKeyEvent: keysym=%x, AWTkeycode=%x, mapsToUnicodeChar=%d", |
| keysym, keycode, mapsToUnicodeChar); |
| |
| if (keycode == java_awt_event_KeyEvent_VK_UNDEFINED) { |
| *cont = TRUE; |
| return; |
| } |
| |
| /* Need to take care of keysyms > 0xFFFF here |
| * Most of these keys don't map to unicode characters, but some do. |
| * |
| * For keys that don't map to unicode characters, the keysym |
| * is irrelevant at this point. We set the keysym to zero |
| * to ensure that the switch statement immediately below |
| * this function call (in adjustKeySym) won't incorrectly act |
| * on them after the high bits are stripped off. |
| * |
| * For keys that do map to unicode characters, we change the keysym |
| * to the equivalent that is < 0xFFFF |
| */ |
| handleVendorKeySyms(event, &keysym); |
| |
| /* This function is a conglomeration of bug fixes that adjust |
| * the keysym and XEvent keycode for this key event. |
| */ |
| adjustKeySym(event, &keysym); |
| |
| modifiers = getModifiers(event->xkey.state, 0, keycode); |
| |
| DTRACE_PRINTLN6("%s: type=%d, xkeycode=%x, xstate=%x, keysym=%x, xmods=%d", |
| "In handleKeyEvent keysym>=256 ", event->type, event->xkey.keycode, |
| event->xkey.state, keysym, mods); |
| DTRACE_PRINTLN2(" AWTkeycode=%x, AWTmodifiers=%d", |
| keycode, modifiers); |
| |
| awt_post_java_key_event(client_data, |
| keyEventId, |
| (passEvent == TRUE) ? event : NULL, |
| event->xkey.time, |
| keycode, |
| (jchar) (mapsToUnicodeChar ? keysym : |
| java_awt_event_KeyEvent_CHAR_UNDEFINED), |
| modifiers, |
| keyLocation, |
| event); |
| |
| /* If this was a keyPressed event, we may need to post a |
| * keyTyped event, too. Otherwise, return. |
| */ |
| if (keyEventId == java_awt_event_KeyEvent_KEY_RELEASED) { |
| return; |
| } |
| DTRACE_PRINTLN("This is a keyPressed event"); |
| |
| /* XtTranslateKeycode seems to return slightly bogus values for the |
| * Escape key (keysym==1004ff69==osfXK_Cancel, xmods=2) on Solaris, |
| * so we just create the KEY_TYPED as a special case for Escape here. |
| * (Linux works fine, and this was also okay running under VNC.) |
| */ |
| if (keycode == java_awt_event_KeyEvent_VK_ESCAPE) { |
| awt_post_java_key_event(client_data, |
| java_awt_event_KeyEvent_KEY_TYPED, |
| NULL, |
| event->xkey.time, |
| java_awt_event_KeyEvent_VK_UNDEFINED, |
| (jchar) keysym, |
| modifiers, |
| java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN, |
| event); |
| |
| DTRACE_PRINTLN("Posted a keyTyped event for VK_ESCAPE"); |
| return; |
| } |
| |
| /* Now get real keysym which looks at modifiers for keyTyped event. |
| * XtGetActionKeySym() returns wrong value with Kana Lock, |
| * so use XtTranslateKeycode(). |
| */ |
| XtTranslateKeycode(event->xkey.display, (KeyCode) event->xkey.keycode, |
| event->xkey.state, &mods, &keysym); |
| DTRACE_PRINTLN6("%s: type=%d, xkeycode=%x, xstate=%x, keysym=%x, xmods=%d", |
| "In handleKeyEvent keysym>=256 ", event->type, event->xkey.keycode, |
| event->xkey.state, keysym, mods); |
| |
| if (keysym == NoSymbol) { |
| return; |
| } |
| |
| if (event->xkey.state & awt_NumLockMask) { |
| if( awt_UseType4Patch ) { |
| handleKeyEventWithNumLockMask(event, &keysym); |
| }else{ |
| handleKeyEventWithNumLockMask_New(event, &keysym); |
| } |
| } |
| |
| if (keysym == XK_ISO_Left_Tab) { |
| keysym = XK_Tab; |
| } |
| |
| /* Map the real keysym to a Java keycode */ |
| keysymToAWTKeyCode(keysym, &keycode, &mapsToUnicodeChar, &keyLocation); |
| DTRACE_PRINTLN3("In handleKeyEvent: keysym=%x, AWTkeycode=%x, mapsToUnicodeChar=%d", |
| keysym, keycode, mapsToUnicodeChar); |
| |
| /* If it doesn't map to a Unicode character, don't post a keyTyped event */ |
| if (!mapsToUnicodeChar) { |
| return; |
| } |
| |
| handleVendorKeySyms(event, &keysym); |
| adjustKeySym(event, &keysym); |
| DTRACE_PRINT4("In handleKeyEvent: type=%d, xkeycode=%x, xstate=%x, keysym=%x", |
| event->type, event->xkey.keycode, event->xkey.state, keysym); |
| DTRACE_PRINTLN2(", AWTkeycode=%x, AWTmodifiers=%d", keycode, modifiers); |
| |
| awt_post_java_key_event(client_data, |
| java_awt_event_KeyEvent_KEY_TYPED, |
| NULL, |
| event->xkey.time, |
| java_awt_event_KeyEvent_VK_UNDEFINED, |
| (jchar) keysym, |
| modifiers, |
| java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN, |
| event); |
| } |
| } |
| |
| |
| static void |
| translateXY(Widget w, jint *xp, jint *yp) |
| { |
| Position wx, wy; |
| |
| XtVaGetValues(w, XmNx, &wx, XmNy, &wy, NULL); |
| *xp += wx; |
| *yp += wy; |
| } |
| |
| |
| /* |
| * Part fix for bug id 4017222. Return the root widget of the Widget parameter. |
| */ |
| Widget |
| getRootWidget(Widget w) { |
| if(!w) return NULL; |
| |
| if(XtParent(w)) |
| return getRootWidget(XtParent(w)); |
| else |
| return w; |
| } |
| |
| #define ABS(x) ((x) < 0 ? -(x) : (x)) |
| |
| /* This proc is the major AWT engine for processing X events |
| * for Java components and is the proc responsible for taking |
| * X events and posting their corresponding Java event to the |
| * AWT EventQueue. It is set up to be called both from an Xt |
| * event handler and directly from MToolkit.c:shouldDispatchToWidget(). |
| * For the latter case, the "passEvent" parameter will be true, |
| * which means that the event is being posted on the Java queue |
| * BEFORE it is being passed to Xt and so a copy of the X event |
| * must be stored within the Java event structure so it can be |
| * dispatched to Xt later on. |
| */ |
| void |
| awt_canvas_handleEvent(Widget w, XtPointer client_data, |
| XEvent * event, struct WidgetInfo *winfo, |
| Boolean * cont, Boolean passEvent) |
| { |
| static jint clickCount = 1; |
| static XtPointer lastPeer = NULL; |
| static Time lastTime = 0; |
| static jint lastx = 0; |
| static jint lasty = 0; |
| static int32_t rbutton = 0; |
| static int32_t lastButton = 0; |
| Boolean popupTrigger; |
| jint x, y; |
| jint modifiers = 0; |
| jint button = java_awt_event_MouseEvent_NOBUTTON; |
| uint32_t fullRelease = 0; |
| WidgetClass wclass = NULL; |
| |
| /* Any event handlers which take peer instance pointers as |
| * client_data should check to ensure the widget has not been |
| * marked as destroyed as a result of a dispose() call on the peer |
| * (which can result in the peer instance pointer already haven |
| * been gc'd by the time this event is processed) |
| */ |
| if (w->core.being_destroyed) { |
| return; |
| } |
| *cont = FALSE; |
| |
| switch (event->type) { |
| case SelectionClear: |
| case SelectionNotify: |
| case SelectionRequest: |
| *cont = TRUE; |
| break; |
| case GraphicsExpose: |
| case Expose: |
| HandleExposeEvent(w, (jobject) client_data, event); |
| break; |
| case FocusIn: |
| case FocusOut: |
| *cont = TRUE; |
| updateCursor(client_data, CACHE_UPDATE); // 4840883 |
| // We no longer listen to the Motif focus notifications. |
| // Instead we call focus callbacks in the times we think |
| // appropriate trying to simulate correct Motif widget system |
| // behavior. |
| break; |
| case ButtonPress: |
| x = (jint) event->xbutton.x; |
| y = (jint) event->xbutton.y; |
| |
| if (lastPeer == client_data && |
| lastButton == event->xbutton.button && |
| (event->xbutton.time - lastTime) <= (Time) awt_multiclick_time) { |
| clickCount++; |
| } else { |
| clickCount = 1; |
| lastPeer = client_data; |
| lastButton = event->xbutton.button; |
| lastx = x; |
| lasty = y; |
| } |
| lastTime = event->xbutton.time; |
| |
| /* On MouseEvent.MOUSE_PRESSED, RELEASED and CLICKED only new modifiers and |
| * modifier for changed mouse button are set. |
| */ |
| button = getButton(event->xbutton.button); |
| modifiers = getModifiers(event->xbutton.state, button, 0); |
| |
| |
| /* If the widget is a subwidget on a component we need to |
| * translate the x,y into the coordinate space of the component. |
| */ |
| if (winfo != NULL && winfo->widget != winfo->origin) { |
| translateXY(winfo->widget, &x, &y); |
| } |
| |
| if (XtIsSubclass(w, xmScrollBarWidgetClass) && findWidgetInfo(w) != NULL) { |
| passEvent = FALSE; |
| *cont = TRUE; |
| } |
| |
| /* Mouse wheel events come in as button 4 (wheel up) and |
| * button 5 (wheel down). |
| */ |
| if (lastButton == 4 || lastButton == 5) { |
| *cont = FALSE; |
| awt_post_java_mouse_event(client_data, |
| java_awt_event_MouseEvent_MOUSE_WHEEL, |
| (passEvent == TRUE) ? event : NULL, |
| event->xbutton.time, |
| modifiers, |
| x, y, |
| (jint) (event->xbutton.x_root), |
| (jint) (event->xbutton.y_root), |
| clickCount, |
| False, |
| lastButton == 4 ? -1 : 1, |
| java_awt_event_MouseEvent_NOBUTTON); |
| /* we're done with this event */ |
| break; |
| } |
| |
| /* (4168006) Find out out how many buttons we have |
| * If this is a two button system Right == 2 |
| * If this is a three button system Right == 3 |
| */ |
| if ( rbutton == 0 ) { |
| unsigned char map[5]; |
| rbutton = XGetPointerMapping ( awt_display, map, 3 ); |
| } |
| |
| if (event->xbutton.button == rbutton || event->xbutton.button > 2) { |
| popupTrigger = True; |
| } else { |
| popupTrigger = False; |
| } |
| |
| awt_post_java_mouse_event(client_data, |
| java_awt_event_MouseEvent_MOUSE_PRESSED, |
| (passEvent == TRUE) ? event : NULL, |
| event->xbutton.time, |
| modifiers, |
| x, y, |
| (jint) (event->xbutton.x_root), |
| (jint) (event->xbutton.y_root), |
| clickCount, |
| popupTrigger, 0, |
| button); |
| |
| drag_source = w; |
| |
| break; |
| case ButtonRelease: |
| if (XtIsSubclass(w, xmScrollBarWidgetClass) && findWidgetInfo(w) != NULL) { |
| passEvent = FALSE; |
| *cont = TRUE; |
| } |
| |
| /* |
| * For button 4 & 5 (mouse wheel) we can simply ignore this event. |
| * We dispatch the wheel on the ButtonPress. |
| */ |
| if (event->xbutton.button == 4 || |
| event->xbutton.button == 5) { |
| break; |
| } |
| |
| prevWidget = NULL; |
| x = (jint) event->xbutton.x; |
| y = (jint) event->xbutton.y; |
| /* On MouseEvent.MOUSE_PRESSED, RELEASED and CLICKED only new modifiers and |
| * modifier for changed mouse button are set. |
| */ |
| button = getButton(event->xbutton.button); |
| modifiers = getModifiers(event->xbutton.state, button, 0); |
| |
| fullRelease = |
| ((event->xbutton.state & Button1Mask) && |
| !(event->xbutton.state & Button2Mask) && |
| !(event->xbutton.state & Button3Mask) && |
| (event->xbutton.button == Button1)) || |
| (!(event->xbutton.state & Button1Mask) && |
| (event->xbutton.state & Button2Mask) && |
| !(event->xbutton.state & Button3Mask) && |
| (event->xbutton.button == Button2)) || |
| (!(event->xbutton.state & Button1Mask) && |
| !(event->xbutton.state & Button2Mask) && |
| (event->xbutton.state & Button3Mask) && |
| (event->xbutton.button == Button3)); |
| |
| /* If the widget is a subwidget on a component we need to |
| * translate the x,y into the coordinate space of the component. |
| */ |
| if (winfo != NULL && winfo->widget != winfo->origin) { |
| translateXY(winfo->widget, &x, &y); |
| } |
| drag_source = NULL; |
| awt_post_java_mouse_event(client_data, |
| java_awt_event_MouseEvent_MOUSE_RELEASED, |
| (passEvent == TRUE) ? event : NULL, |
| event->xbutton.time, |
| modifiers, |
| x, y, |
| (jint) (event->xbutton.x_root), |
| (jint) (event->xbutton.y_root), |
| clickCount, |
| FALSE, 0, |
| button); |
| |
| if (lastPeer == client_data) { |
| awt_post_java_mouse_event(client_data, |
| java_awt_event_MouseEvent_MOUSE_CLICKED, |
| NULL, |
| event->xbutton.time, |
| modifiers, |
| x, y, |
| (jint) (event->xbutton.x_root), |
| (jint) (event->xbutton.y_root), |
| clickCount, |
| FALSE, 0, |
| button); |
| } |
| |
| if (fullRelease) { |
| updateCursor(client_data, UPDATE_ONLY); |
| } |
| |
| break; |
| case MotionNotify: |
| if (XtIsSubclass(w, xmScrollBarWidgetClass) && findWidgetInfo(w) != NULL) { |
| passEvent = FALSE; |
| *cont = TRUE; |
| } |
| |
| x = (jint) event->xmotion.x; |
| y = (jint) event->xmotion.y; |
| |
| /* If a motion comes in while a multi-click is pending, |
| * allow a smudge factor so that moving the mouse by a small |
| * amount does not wipe out the multi-click state variables. |
| */ |
| if (!(lastPeer == client_data && |
| ((event->xmotion.time - lastTime) <= (Time) awt_multiclick_time) && |
| (ABS(lastx - x) < awt_multiclick_smudge && |
| ABS(lasty - y) < awt_multiclick_smudge))) { |
| clickCount = (jint) 0; |
| lastTime = (Time) 0; |
| lastPeer = NULL; |
| lastx = (jint) 0; |
| lasty = (jint) 0; |
| } |
| /* On other MouseEvent only new modifiers and |
| * old mouse modifiers are set. |
| */ |
| modifiers = getModifiers(event->xmotion.state, 0, 0); |
| |
| /* If the widget is a subwidget on a component we need to |
| * translate the x,y into the coordinate space of the component. |
| */ |
| if (winfo != NULL && winfo->widget != winfo->origin) { |
| translateXY(winfo->widget, &x, &y); |
| } |
| if (event->xmotion.state & (Button1Mask | Button2Mask | Button3Mask)) { |
| if (!clickCount) { |
| |
| /* |
| Fix for bug id 4017222. A button is down, so EnterNotify and |
| LeaveNotify events are only being sent to this widget. If |
| the pointer has moved over a new widget, manually generate |
| MouseEnter and MouseExit and send them to the right widgets. |
| */ |
| |
| extern Widget awt_WidgetAtXY(Widget root, Position x, Position y); |
| extern Widget awt_GetWidgetAtPointer(); |
| Widget currentWidget=NULL, topLevelW; |
| Position wx=0, wy=0; |
| |
| XtTranslateCoords(w, (int32_t) x, (int32_t) y, &wx, &wy); |
| /* Get the top level widget underneath the mouse pointer */ |
| currentWidget = awt_GetWidgetAtPointer(); |
| /* Get the exact widget at the current XY from the top level */ |
| currentWidget = awt_WidgetAtXY(currentWidget, wx, wy); |
| if ((prevWidget != NULL) && (prevWidget != w) && |
| (currentWidget != prevWidget) && awt_isAwtWidget(prevWidget) && |
| !prevWidget->core.being_destroyed) { |
| XtPointer userData=NULL; |
| XtVaGetValues(prevWidget, XmNuserData, &userData, NULL); |
| if (userData) { |
| awt_post_java_mouse_event(userData, |
| java_awt_event_MouseEvent_MOUSE_EXITED, |
| (passEvent==TRUE) ? event : NULL, |
| event->xmotion.time, |
| modifiers, |
| x, y, |
| (jint) (event->xmotion.x_root), |
| (jint) (event->xmotion.y_root), |
| clickCount, |
| FALSE, 0, |
| java_awt_event_MouseEvent_NOBUTTON); |
| } |
| } |
| |
| if ((currentWidget != NULL) && (currentWidget != w) && |
| (currentWidget != prevWidget) && awt_isAwtWidget(currentWidget)) { |
| XtPointer userData=NULL; |
| XtVaGetValues(currentWidget, XmNuserData, &userData, NULL); |
| if (userData) { |
| awt_post_java_mouse_event(userData, |
| java_awt_event_MouseEvent_MOUSE_ENTERED, |
| (passEvent==TRUE) ? event : NULL, |
| event->xmotion.time, |
| modifiers, |
| x, y, |
| (jint) (event->xmotion.x_root), |
| (jint) (event->xmotion.y_root), |
| clickCount, |
| FALSE, 0, |
| java_awt_event_MouseEvent_NOBUTTON); |
| } |
| |
| updateCursor(userData, CACHE_ONLY); |
| awt_util_setCursor(currentWidget, None); |
| } |
| |
| prevWidget = currentWidget; |
| /* end 4017222 */ |
| |
| |
| awt_post_java_mouse_event(client_data, |
| java_awt_event_MouseEvent_MOUSE_DRAGGED, |
| (passEvent == TRUE) ? event : NULL, |
| event->xmotion.time, |
| modifiers, |
| x, y, |
| (jint) (event->xmotion.x_root), |
| (jint) (event->xmotion.y_root), |
| clickCount, |
| FALSE, 0, |
| java_awt_event_MouseEvent_NOBUTTON); |
| |
| } |
| } else { |
| |
| awt_post_java_mouse_event(client_data, |
| java_awt_event_MouseEvent_MOUSE_MOVED, |
| (passEvent == TRUE) ? event : NULL, |
| event->xmotion.time, |
| modifiers, |
| x, y, |
| (jint) (event->xmotion.x_root), |
| (jint) (event->xmotion.y_root), |
| clickCount, |
| FALSE, 0, |
| java_awt_event_MouseEvent_NOBUTTON); |
| } |
| break; |
| case KeyPress: |
| handleKeyEvent(java_awt_event_KeyEvent_KEY_PRESSED, |
| event, client_data, cont, TRUE); |
| break; |
| case KeyRelease: |
| handleKeyEvent(java_awt_event_KeyEvent_KEY_RELEASED, |
| event, client_data, cont, TRUE); |
| break; |
| case EnterNotify: |
| case LeaveNotify: |
| /* |
| printf("----->%s on %s(%x):mode=%d detail = %d\n", |
| event->type == EnterNotify?"EnterNotify":"LeaveNotify", |
| XtName(w), w, |
| ((XCrossingEvent*)event)->mode, ((XCrossingEvent*)event)->detail); |
| */ |
| if (event->xcrossing.mode != NotifyNormal || |
| ((event->xcrossing.detail == NotifyVirtual || |
| event->xcrossing.detail == NotifyNonlinearVirtual) && |
| !XtIsSubclass(w, xmScrolledWindowWidgetClass))) { |
| *cont = TRUE; |
| return; |
| } |
| |
| /* fix for 4454304. |
| * We should not post MOUSE_ENTERED and MOUSE_EXITED events |
| * if the mouse pointer is in the place between component |
| * and its scrollbars. |
| * kdm@sparc.spb.su |
| */ |
| if (winfo != NULL && winfo->widget != NULL) { |
| wclass = XtClass(winfo->widget); |
| if (event->xcrossing.subwindow == NULL |
| && event->xcrossing.detail == NotifyInferior |
| && (wclass == xmTextWidgetClass |
| || wclass == xmListWidgetClass)) { |
| *cont = TRUE; |
| return; |
| } |
| } |
| |
| clickCount = (jint) 0; |
| lastTime = (Time) 0; |
| lastPeer = NULL; |
| |
| /* On other MouseEvent only new modifiers and |
| * old mouse modifiers are set. |
| */ |
| modifiers = getModifiers(event->xcrossing.state, 0, 0); |
| |
| switch (event->type) { |
| case EnterNotify: |
| awt_post_java_mouse_event(client_data, |
| java_awt_event_MouseEvent_MOUSE_ENTERED, |
| (passEvent == TRUE) ? event : NULL, |
| event->xcrossing.time, |
| modifiers, |
| (jint) (event->xcrossing.x), |
| (jint) (event->xcrossing.y), |
| (jint) (event->xcrossing.x_root), |
| (jint) (event->xcrossing.y_root), |
| clickCount, |
| FALSE, 0, |
| java_awt_event_MouseEvent_NOBUTTON); |
| if (!(event->xcrossing.state |
| & (Button1Mask | Button2Mask | Button3Mask))) { |
| updateCursor(client_data, CACHE_UPDATE); |
| } |
| |
| break; |
| case LeaveNotify: |
| awt_post_java_mouse_event(client_data, |
| java_awt_event_MouseEvent_MOUSE_EXITED, |
| (passEvent == TRUE) ? event : NULL, |
| event->xcrossing.time, |
| modifiers, |
| (jint) (event->xcrossing.x), |
| (jint) (event->xcrossing.y), |
| (jint) (event->xcrossing.x_root), |
| (jint) (event->xcrossing.y_root), |
| clickCount, |
| FALSE, 0, |
| java_awt_event_MouseEvent_NOBUTTON); |
| break; |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| /* |
| * client_data is MComponentPeer subclass |
| */ |
| void |
| awt_canvas_event_handler(Widget w, XtPointer client_data, |
| XEvent * event, Boolean * cont) |
| { |
| awt_canvas_handleEvent(w, client_data, event, NULL, cont, FALSE); |
| } |
| |
| void |
| awt_canvas_reconfigure(struct FrameData *wdata) |
| { |
| Dimension w, h; |
| |
| if (wdata->winData.comp.widget == NULL || |
| XtParent(wdata->winData.comp.widget) == NULL) { |
| return; |
| } |
| XtVaGetValues(XtParent(wdata->winData.comp.widget), XmNwidth, &w, XmNheight, &h, NULL); |
| XtConfigureWidget(wdata->winData.comp.widget, |
| -(wdata->left), |
| -(wdata->top), |
| w + (wdata->left + wdata->right), |
| h + (wdata->top + wdata->bottom), |
| 0); |
| } |
| |
| static void |
| Wrap_event_handler(Widget widget, |
| XtPointer client_data, |
| XmDrawingAreaCallbackStruct * call_data) |
| { |
| awt_canvas_reconfigure((struct FrameData *) client_data); |
| } |
| |
| |
| Widget |
| awt_canvas_create(XtPointer this, |
| Widget parent, |
| char *base, |
| int32_t width, |
| int32_t height, |
| Boolean parentIsFrame, |
| struct FrameData *wdata, |
| AwtGraphicsConfigDataPtr awtData) |
| { |
| Widget newCanvas; |
| Widget wrap; |
| #define MAX_ARGC 20 |
| Arg args[MAX_ARGC]; |
| int32_t argc; |
| char name[128]; |
| static XtTranslations translationKeyDown = NULL; |
| |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| |
| |
| if (parent == NULL) { |
| JNU_ThrowNullPointerException(env, "NullPointerException"); |
| return NULL; |
| } |
| if (width == 0) { |
| width = 1; |
| } |
| if (height == 0) { |
| height = 1; |
| } |
| |
| if (wdata != NULL) { |
| argc = 0; |
| if (!parentIsFrame) |
| { |
| XtSetArg(args[argc], XmNwidth, width); |
| argc++; |
| XtSetArg(args[argc], XmNheight, height); |
| argc++; |
| } |
| XtSetArg(args[argc], XmNmarginWidth, 0); |
| argc++; |
| XtSetArg(args[argc], XmNmarginHeight, 0); |
| argc++; |
| XtSetArg(args[argc], XmNspacing, 0); |
| argc++; |
| XtSetArg(args[argc], XmNresizePolicy, XmRESIZE_NONE); |
| argc++; |
| /* check for overflowing name? */ |
| strcpy(name, base); |
| strcat(name, "wrap"); |
| |
| DASSERT(!(argc > MAX_ARGC)); |
| wrap = XmCreateDrawingArea(parent, name, args, argc); |
| if (!parentIsFrame) |
| { |
| /* Fixing bugs in frame module (awt_Frame.c). It will now |
| provide the resize handling for this inner/parent canvas.*/ |
| XtAddCallback(wrap, XmNresizeCallback, |
| (XtCallbackProc) Wrap_event_handler, wdata); |
| } |
| XtManageChild(wrap); |
| } else { |
| wrap = parent; |
| } |
| |
| /* check for overflowing name? */ |
| strcpy(name, base); |
| strcat(name, "canvas"); |
| |
| argc = 0; |
| XtSetArg(args[argc], XmNspacing, 0); |
| argc++; |
| if (!parentIsFrame) |
| { |
| XtSetArg(args[argc], XmNwidth, width); |
| argc++; |
| XtSetArg(args[argc], XmNheight, height); |
| argc++; |
| } |
| XtSetArg(args[argc], XmNmarginHeight, 0); |
| argc++; |
| XtSetArg(args[argc], XmNmarginWidth, 0); |
| argc++; |
| XtSetArg(args[argc], XmNresizePolicy, XmRESIZE_NONE); |
| argc++; |
| XtSetArg(args[argc], XmNuserData, this); |
| argc++; |
| /* Fixed 4059430, 3/11/98, robi.khan@eng |
| * install insert proc callback so components are ordered correctly |
| * when added directly to frame/dialogs/windows |
| */ |
| XtSetArg(args[argc], XmNinsertPosition, (XtPointer) awt_util_insertCallback); |
| argc++; |
| |
| if (awtData != getDefaultConfig(awtData->awt_visInfo.screen)) { |
| XtSetArg (args[argc], XtNvisual, awtData->awt_visInfo.visual); argc++; |
| XtSetArg (args[argc], XmNdepth, awtData->awt_depth); argc++; |
| XtSetArg (args[argc], XmNscreen, |
| ScreenOfDisplay(awt_display, |
| awtData->awt_visInfo.screen)); argc++; |
| |
| if (awtData->awt_cmap == None) { |
| awtJNI_CreateColorData (env, awtData, 1); |
| } |
| |
| XtSetArg (args[argc], XmNcolormap, awtData->awt_cmap); argc++; |
| |
| DASSERT(!(argc > MAX_ARGC)); |
| newCanvas = XtCreateWidget(name, vDrawingAreaClass, wrap, |
| args, argc); |
| |
| } else { |
| newCanvas = XtCreateWidget(name, xDrawingAreaClass, |
| wrap, args, argc); |
| } |
| |
| XtSetMappedWhenManaged(newCanvas, False); |
| XtManageChild(newCanvas); |
| /* |
| XXX: causes problems on 2.5 |
| if (!scrollBugWorkAround) { |
| awt_setWidgetGravity(newCanvas, StaticGravity); |
| } |
| */ |
| /* Fixed 4250354 7/28/99 ssi@sparc.spb.su |
| * XtParseTranslationTable leaks in old ver of Xtoolkit |
| * and result should be deletetd in any case |
| * |
| * XtOverrideTranslations(newCanvas, |
| * XtParseTranslationTable("<KeyDown>:DrawingAreaInput()")); |
| */ |
| if (NULL==translationKeyDown) |
| translationKeyDown=XtParseTranslationTable("<KeyDown>:DrawingAreaInput()"); |
| XtOverrideTranslations(newCanvas,translationKeyDown); |
| |
| XtSetSensitive(newCanvas, True); |
| |
| return newCanvas; |
| } |
| |
| static void |
| messWithGravity(Widget w, int32_t gravity) |
| { |
| extern void awt_changeAttributes(Display * dpy, Widget w, |
| unsigned long mask, |
| XSetWindowAttributes * xattr); |
| XSetWindowAttributes xattr; |
| |
| xattr.bit_gravity = gravity; |
| xattr.win_gravity = gravity; |
| |
| awt_changeAttributes(XtDisplay(w), w, (CWBitGravity | CWWinGravity), &xattr); |
| |
| } |
| |
| struct MoveRecord { |
| long dx; |
| long dy; |
| }; |
| |
| void |
| moveWidget(Widget w, void *data) |
| { |
| struct MoveRecord *rec = (struct MoveRecord *) data; |
| |
| if (XtIsRealized(w) && XmIsRowColumn(w)) { |
| w->core.x -= rec->dx; |
| w->core.y -= rec->dy; |
| } |
| } |
| |
| #if 0 |
| /* Scroll entire contents of window by dx and dy. Currently only |
| dy is supported. A negative dy means scroll backwards, i.e., |
| contents in window move down. */ |
| void |
| awt_canvas_scroll(XtPointer this, |
| struct CanvasData *wdata, |
| long dx, |
| long dy) |
| { |
| |
| Window win; |
| XWindowChanges xchgs; |
| Window root; |
| int x, y; |
| unsigned int width, height, junk; |
| Display *dpy; |
| struct MoveRecord mrec; |
| |
| mrec.dx = dx; |
| mrec.dy = dy; |
| |
| dpy = XtDisplay(wdata->comp.widget); |
| win = XtWindow(wdata->comp.widget); |
| |
| /* REMIND: consider getting rid of this! */ |
| XGetGeometry(awt_display, |
| win, |
| &root, |
| &x, |
| &y, |
| &width, |
| &height, |
| &junk, |
| &junk); |
| |
| /* we need to actually update the coordinates for manager widgets, */ |
| /* otherwise the parent won't pass down events to them properly */ |
| /* after scrolling... */ |
| awt_util_mapChildren(wdata->comp.widget, moveWidget, 0, &mrec); |
| |
| if (dx < 0) { |
| /* scrolling backward */ |
| |
| if (scrollBugWorkAround) { |
| messWithGravity(wdata->comp.widget, NorthWestGravity); |
| } |
| xchgs.x = x + dx; |
| xchgs.y = y; |
| xchgs.width = width - dx; |
| xchgs.height = height; |
| XConfigureWindow(awt_display, |
| win, |
| CWX | CWY | CWWidth | CWHeight, |
| &xchgs); |
| |
| if (scrollBugWorkAround) { |
| messWithGravity(wdata->comp.widget, NorthWestGravity); |
| } |
| xchgs.x = x; |
| xchgs.y = y; |
| XConfigureWindow(awt_display, |
| win, |
| CWX | CWY, |
| &xchgs); |
| |
| xchgs.width = width; |
| xchgs.height = height; |
| XConfigureWindow(awt_display, |
| win, |
| CWWidth | CWHeight, |
| &xchgs); |
| } else { |
| /* forward scrolling */ |
| |
| /* make window a little taller */ |
| xchgs.width = width + dx; |
| xchgs.height = height; |
| XConfigureWindow(awt_display, |
| win, |
| CWWidth | CWHeight, |
| &xchgs); |
| |
| if (scrollBugWorkAround) { |
| messWithGravity(wdata->comp.widget, NorthEastGravity); |
| } |
| /* move window by amount we're scrolling */ |
| xchgs.x = x - dx; |
| xchgs.y = y; |
| XConfigureWindow(awt_display, |
| win, |
| CWX | CWY, |
| &xchgs); |
| |
| if (scrollBugWorkAround) { |
| messWithGravity(wdata->comp.widget, NorthWestGravity); |
| } |
| /* resize to original size */ |
| xchgs.x = x; |
| xchgs.y = y; |
| xchgs.width = width; |
| xchgs.height = height; |
| XConfigureWindow(awt_display, |
| win, |
| CWX | CWY | CWWidth | CWHeight, |
| &xchgs); |
| } |
| /* Because of the weird way we're scrolling this window, |
| we have to eat all the exposure events that result from |
| scrolling forward, and translate them up by the amount we're |
| scrolling by. |
| |
| Rather than just eating all the exposures and having the |
| java code fill in what it knows is exposed, we do it this |
| way. The reason is that there might be some other exposure |
| events caused by overlapping windows on top of us that we |
| also need to deal with. */ |
| { |
| XRectangle rect; |
| |
| rect.x = -1; |
| eatAllExposures(dpy, win, &rect); |
| if (rect.x != -1) { /* we got at least one expose event */ |
| if (dx > 0) { |
| rect.x -= dx; |
| rect.width += dx; |
| } |
| /* |
| printf("EXPOSE (%d): %d, %d, %d, %d\n", |
| dy, rect.x, rect.y, rect.width, rect.height); |
| */ |
| callJavaExpose(this, &rect); |
| XSync(awt_display, False); |
| } |
| } |
| if (dy < 0) { |
| /* scrolling backward */ |
| |
| if (scrollBugWorkAround) { |
| messWithGravity(wdata->comp.widget, SouthGravity); |
| } |
| xchgs.x = x; |
| xchgs.y = y + dy; |
| xchgs.width = width; |
| xchgs.height = height - dy; |
| XConfigureWindow(awt_display, |
| win, |
| CWX | CWY | CWWidth | CWHeight, |
| &xchgs); |
| |
| if (scrollBugWorkAround) { |
| messWithGravity(wdata->comp.widget, NorthWestGravity); |
| } |
| xchgs.x = x; |
| xchgs.y = y; |
| XConfigureWindow(awt_display, |
| win, |
| CWX | CWY, |
| &xchgs); |
| |
| xchgs.width = width; |
| xchgs.height = height; |
| XConfigureWindow(awt_display, |
| win, |
| CWWidth | CWHeight, |
| &xchgs); |
| } else { |
| /* forward scrolling */ |
| |
| /* make window a little taller */ |
| xchgs.width = width; |
| xchgs.height = height + dy; |
| XConfigureWindow(awt_display, |
| win, |
| CWWidth | CWHeight, |
| &xchgs); |
| |
| /* move window by amount we're scrolling */ |
| xchgs.x = x; |
| xchgs.y = y - dy; |
| XConfigureWindow(awt_display, |
| win, |
| CWX | CWY, |
| &xchgs); |
| |
| if (scrollBugWorkAround) { |
| messWithGravity(wdata->comp.widget, SouthGravity); |
| } |
| /* resize to original size */ |
| xchgs.x = x; |
| xchgs.y = y; |
| xchgs.width = width; |
| xchgs.height = height; |
| XConfigureWindow(awt_display, |
| win, |
| CWX | CWY | CWWidth | CWHeight, |
| &xchgs); |
| if (scrollBugWorkAround) { |
| messWithGravity(wdata->comp.widget, NorthWestGravity); |
| } |
| } |
| /* Because of the weird way we're scrolling this window, |
| we have to eat all the exposure events that result from |
| scrolling forward, and translate them up by the amount we're |
| scrolling by. |
| |
| Rather than just eating all the exposures and having the |
| java code fill in what it knows is exposed, we do it this |
| way. The reason is that there might be some other exposure |
| events caused by overlapping windows on top of us that we |
| also need to deal with. */ |
| { |
| XRectangle rect; |
| |
| rect.x = -1; |
| eatAllExposures(dpy, win, &rect); |
| if (rect.x != -1) { /* we got at least one expose event */ |
| if (dy > 0) { |
| rect.y -= dy; |
| rect.height += dy; |
| } |
| if (dx > 0) { |
| rect.x -= dx; |
| rect.width += dx; |
| } |
| /* |
| printf("EXPOSE (%d): %d, %d, %d, %d\n", |
| dy, rect.x, rect.y, rect.width, rect.height); |
| */ |
| callJavaExpose(this, &rect); |
| XSync(awt_display, False); |
| } |
| } |
| } |
| #endif |
| |
| extern Window focusProxyWindow; |
| /* |
| * client_data is MComponentPeer instance |
| */ |
| void |
| awt_post_java_key_event(XtPointer client_data, jint id, XEvent *event, |
| Time when, jint keycode, jchar keychar, jint modifiers, jint keyLocation, XEvent *anEvent) |
| { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| jobject peer = (jobject) client_data; |
| jobject target; |
| static jclass classKeyEvent = NULL; |
| static jmethodID mid = NULL; |
| char *clsName = "java/awt/event/KeyEvent"; |
| jobject hEvent; |
| jlong jWhen; |
| Boolean isProxyActive = (focusProxyWindow != None); |
| |
| if (anEvent != NULL && anEvent->xany.send_event == 2){ |
| isProxyActive = False; |
| if (event != NULL) { |
| event->xany.send_event = 0; |
| } |
| } |
| if ((*env)->PushLocalFrame(env, 16) < 0) |
| return; |
| |
| target = (*env)->GetObjectField(env, peer, mComponentPeerIDs.target); |
| |
| if (classKeyEvent == NULL) { |
| jobject sysClass; |
| |
| sysClass = (*env)->FindClass(env, clsName); |
| if (sysClass != NULL) { |
| /* Make this class 'sticky', we don't want it GC'd */ |
| classKeyEvent = (*env)->NewGlobalRef(env, sysClass); |
| mid = (*env)->GetMethodID(env, classKeyEvent, "<init>", |
| "(Ljava/awt/Component;IJIICIZ)V"); |
| } |
| if (JNU_IsNull(env, classKeyEvent) || mid == NULL) { |
| JNU_ThrowClassNotFoundException(env, clsName); |
| (*env)->PopLocalFrame(env, 0); |
| return; |
| } |
| } |
| |
| jWhen = awt_util_nowMillisUTC_offset(when); /* convert Time to UTC */ |
| |
| hEvent = (*env)->NewObject(env, classKeyEvent, mid, |
| target, id, jWhen, modifiers, |
| keycode, keychar, keyLocation, |
| isProxyActive?JNI_TRUE:JNI_FALSE); |
| |
| if ((*env)->ExceptionOccurred(env)) { |
| (*env)->ExceptionDescribe(env); |
| (*env)->ExceptionClear(env); |
| } |
| if (JNU_IsNull(env, hEvent)) { |
| JNU_ThrowNullPointerException(env, "NullPointerException: constructor failed."); |
| (*env)->PopLocalFrame(env, 0); |
| return; |
| } |
| awt_copyXEventToAWTEvent(env, event, hEvent); |
| #ifdef DEBUG |
| if (debugKeys) { |
| jio_fprintf(stderr, "native posting event id:%d keychar:%c\n", (int)id, (char)keychar); |
| } |
| #endif |
| JNU_CallMethodByName(env, NULL, peer, |
| "postEvent", "(Ljava/awt/AWTEvent;)V", hEvent); |
| if ((*env)->ExceptionOccurred(env)) { |
| (*env)->ExceptionDescribe(env); |
| (*env)->ExceptionClear(env); |
| } |
| (*env)->PopLocalFrame(env, 0); |
| } /* awt_post_java_key_event() */ |
| |
| /* |
| * Note: this routine returns a global reference which should be deleted |
| * after use. |
| */ |
| jobject |
| awt_canvas_wrapInSequenced(jobject awtevent) { |
| static jclass classSequencedEvent = NULL; |
| static jmethodID mid = NULL; |
| jobject wrapperEventLocal = NULL; |
| jobject wrapperEvent = NULL; |
| |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| |
| if ((*env)->PushLocalFrame(env, 5) < 0) |
| return NULL; |
| |
| if (classSequencedEvent == NULL) { |
| jobject sysClass = (*env)->FindClass(env, "java/awt/SequencedEvent"); |
| if (sysClass != NULL) { |
| /* Make this class 'sticky', we don't want it GC'd */ |
| classSequencedEvent = (*env)->NewGlobalRef(env, sysClass); |
| if (mid == NULL) { |
| mid = (*env)->GetMethodID(env, classSequencedEvent |
| ,"<init>" |
| ,"(Ljava/awt/AWTEvent;)V"); |
| } |
| } |
| if (JNU_IsNull(env, classSequencedEvent) || mid == NULL) { |
| JNU_ThrowClassNotFoundException(env, "java/awt/SequencedEvent"); |
| (*env)->PopLocalFrame(env, 0); |
| return NULL; |
| } |
| } |
| wrapperEventLocal = (*env)->NewObject(env, classSequencedEvent, mid, awtevent); |
| |
| if ((*env)->ExceptionOccurred(env)) { |
| (*env)->ExceptionDescribe(env); |
| (*env)->ExceptionClear(env); |
| } |
| if (JNU_IsNull(env, wrapperEventLocal)) { |
| JNU_ThrowNullPointerException(env, "constructor failed."); |
| (*env)->PopLocalFrame(env, 0); |
| return NULL; |
| } |
| wrapperEvent = (*env)->NewGlobalRef(env, wrapperEventLocal); |
| if (!JNU_IsNull(env, ((*env)->ExceptionOccurred(env)))) { |
| (*env)->ExceptionDescribe(env); |
| (*env)->ExceptionClear(env); |
| (*env)->PopLocalFrame(env, 0); |
| return NULL; |
| } |
| if (JNU_IsNull(env, wrapperEvent)) { |
| JNU_ThrowNullPointerException(env, "NewGlobalRef failed."); |
| (*env)->PopLocalFrame(env, 0); |
| return NULL; |
| } |
| |
| (*env)->PopLocalFrame(env, 0); |
| return wrapperEvent; |
| } |
| |
| jobject |
| findTopLevelOpposite(JNIEnv *env, jint eventType) |
| { |
| jobject target, peer, opposite; |
| |
| if ((*env)->EnsureLocalCapacity(env, 2) < 0) { |
| return NULL; |
| } |
| |
| /* 4462056: Get a usable handle for a weakly referenced object */ |
| target = (*env)->NewLocalRef(env, |
| (eventType == java_awt_event_WindowEvent_WINDOW_GAINED_FOCUS) |
| ? forGained |
| : focusList->requestor); |
| if (target == NULL) { |
| return NULL; |
| } |
| |
| peer = (*env)->GetObjectField(env, target, componentIDs.peer); |
| (*env)->DeleteLocalRef(env, target); |
| if (peer == NULL) { |
| return NULL; |
| } |
| |
| opposite = findTopLevel(peer, env); |
| (*env)->DeleteLocalRef(env, peer); |
| |
| return opposite; |
| } |
| |
| void |
| cleanFocusList(JNIEnv *env){ |
| |
| while(focusList) { |
| FocusListElt *tmp = focusList->next; |
| (*env)->DeleteWeakGlobalRef(env, focusList->requestor); |
| free(focusList); |
| focusList = tmp; |
| } |
| focusListEnd = NULL; |
| } |
| |
| static jweak |
| computeOpposite(jint id, jobject target) |
| { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| jobject top; |
| jboolean isSameObject; |
| |
| if (focusList == NULL) { |
| return NULL; |
| } |
| |
| /* 4462056: Get a usable handle for a weakly referenced object */ |
| top = (*env)->NewLocalRef(env, focusList->requestor); |
| if (top == NULL) { |
| /* weakly referenced component was deleted -- clean up focus list */ |
| cleanFocusList(env); |
| return NULL; |
| } |
| |
| isSameObject = (*env)->IsSameObject(env, target, top); |
| (*env)->DeleteLocalRef(env, top); |
| |
| if (isSameObject) { |
| if (id == java_awt_event_FocusEvent_FOCUS_GAINED) { |
| return forGained; |
| } else { /* focus lost */ |
| FocusListElt *tmp = focusList->next; |
| (*env)->DeleteWeakGlobalRef(env, forGained); |
| forGained = focusList->requestor; |
| free(focusList); |
| focusList = tmp; |
| |
| if (focusList == NULL) { |
| focusListEnd = NULL; |
| return NULL; |
| } |
| return focusList->requestor; |
| } |
| } else { /* target does not match top of list */ |
| /* be gentle with focus lost for now... */ |
| if (id == java_awt_event_FocusEvent_FOCUS_LOST) { |
| (*env)->DeleteWeakGlobalRef(env, forGained); |
| forGained = (*env)->NewWeakGlobalRef(env, target); |
| return NULL; |
| } |
| |
| cleanFocusList(env); |
| return NULL; |
| } |
| } |
| |
| |
| /* |
| * client_data is MComponentPeer instance |
| */ |
| void |
| awt_post_java_focus_event(XtPointer client_data, |
| jint id, jobject cause, |
| XEvent* event) |
| { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| jobject peer = (jobject) client_data; |
| jobject target; |
| jobject opposite; |
| static jclass classFocusEvent = NULL; |
| static jmethodID mid = NULL; |
| char *clsName = "sun/awt/CausedFocusEvent"; |
| jobject hEvent; |
| |
| if ((*env)->PushLocalFrame(env, 16) < 0) |
| return; |
| |
| target = (*env)->GetObjectField(env, peer, mComponentPeerIDs.target); |
| |
| opposite = (*env)->NewLocalRef(env, computeOpposite(id, target)); |
| |
| if (classFocusEvent == NULL) { |
| jobject sysClass; |
| |
| sysClass = (*env)->FindClass(env, clsName); |
| if (sysClass != NULL) { |
| /* Make this class 'sticky', we don't want it GC'd */ |
| classFocusEvent = (*env)->NewGlobalRef(env, sysClass); |
| mid = (*env)->GetMethodID(env, classFocusEvent |
| ,"<init>" |
| ,"(Ljava/awt/Component;IZLjava/awt/Component;Lsun/awt/CausedFocusEvent$Cause;)V"); |
| } |
| if (JNU_IsNull(env, classFocusEvent) || mid == 0) { |
| JNU_ThrowClassNotFoundException(env, clsName); |
| (*env)->PopLocalFrame(env, 0); |
| return; |
| } |
| } |
| hEvent = (*env)->NewObject(env, classFocusEvent, mid, |
| target, id, JNI_FALSE, opposite, cause); |
| (*env)->DeleteLocalRef(env, opposite); |
| |
| if ((*env)->ExceptionOccurred(env)) { |
| (*env)->ExceptionDescribe(env); |
| (*env)->ExceptionClear(env); |
| } |
| if (JNU_IsNull(env, hEvent)) { |
| JNU_ThrowNullPointerException(env, "NullPointerException: constructor failed."); |
| (*env)->PopLocalFrame(env, 0); |
| return; |
| } |
| awt_copyXEventToAWTEvent(env, event, hEvent); |
| { |
| jobject awtEvent = awt_canvas_wrapInSequenced(hEvent); |
| JNU_CallMethodByName(env, NULL, peer, |
| "postEvent", "(Ljava/awt/AWTEvent;)V", |
| awtEvent); |
| (*env)->DeleteGlobalRef(env, awtEvent); |
| } |
| if ((*env)->ExceptionOccurred(env)) { |
| (*env)->ExceptionDescribe(env); |
| (*env)->ExceptionClear(env); |
| } |
| (*env)->PopLocalFrame(env, 0); |
| } |
| |
| |
| void |
| awt_canvas_addToFocusListDefault(jobject target) { |
| awt_canvas_addToFocusListWithDuplicates(target, JNI_FALSE); |
| } |
| |
| void |
| awt_canvas_addToFocusListWithDuplicates(jobject target, jboolean acceptDuplicates) |
| { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| jboolean isSameObject; |
| |
| if (focusListEnd) { |
| jobject localRef = (*env)->NewLocalRef(env, focusListEnd->requestor); |
| |
| if (localRef == NULL) { |
| isSameObject = JNI_FALSE; |
| } else { |
| isSameObject = (*env)->IsSameObject(env, target, localRef); |
| (*env)->DeleteLocalRef(env, localRef); |
| } |
| |
| if (isSameObject && !acceptDuplicates) { |
| return; |
| } |
| |
| focusListEnd->next = malloc(sizeof(FocusListElt)); |
| focusListEnd = focusListEnd->next; |
| } else { |
| jobject l_focusOwnerPeer = awt_canvas_getFocusOwnerPeer(); |
| if (l_focusOwnerPeer == NULL) { |
| isSameObject = JNI_FALSE; |
| } else { |
| jobject l_focusOwner = |
| (*env)->GetObjectField(env, l_focusOwnerPeer, |
| mComponentPeerIDs.target); |
| isSameObject = |
| (*env)->IsSameObject(env, target, l_focusOwner); |
| (*env)->DeleteLocalRef(env, l_focusOwner); |
| (*env)->DeleteLocalRef(env, l_focusOwnerPeer); |
| } |
| |
| if (isSameObject && !acceptDuplicates) { |
| return; |
| } |
| |
| focusList = focusListEnd = malloc(sizeof(FocusListElt)); |
| } |
| |
| focusListEnd->requestor = (*env)->NewWeakGlobalRef(env, target); |
| focusListEnd->next = NULL; |
| } |
| |
| /* |
| * client_data is MComponentPeer instance |
| */ |
| void |
| awt_post_java_mouse_event(XtPointer client_data, jint id, XEvent* event, |
| Time when, jint modifiers, jint x, jint y, |
| jint xAbs, jint yAbs, |
| jint clickcount, |
| Boolean popuptrigger, |
| jint wheelAmt, jint button) |
| { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| jobject peer = (jobject) client_data; |
| jobject target; |
| |
| static jclass classMouseEvent = NULL; |
| static jclass classMouseWheelEvent = NULL; |
| |
| static jmethodID mid = NULL; |
| static jmethodID wheelmid = NULL; |
| |
| char *clsName = "java/awt/event/MouseEvent"; |
| char *wheelClsName = "java/awt/event/MouseWheelEvent"; |
| |
| jobject hEvent; |
| jobject sysClass; |
| jlong jWhen; |
| |
| if ((*env)->PushLocalFrame(env, 16) < 0) |
| return; |
| |
| target = (*env)->GetObjectField(env, peer, mComponentPeerIDs.target); |
| |
| if (classMouseEvent == NULL) { |
| sysClass = (*env)->FindClass(env, clsName); |
| if (sysClass != NULL) { |
| /* Make this class 'sticky', we don't want it GC'd */ |
| classMouseEvent = (*env)->NewGlobalRef(env, sysClass); |
| mid = (*env)->GetMethodID(env, classMouseEvent |
| ,"<init>" |
| ,"(Ljava/awt/Component;IJIIIIIIZI)V"); |
| } |
| if (JNU_IsNull(env, classMouseEvent) || mid == 0) { |
| JNU_ThrowClassNotFoundException(env, clsName); |
| (*env)->PopLocalFrame(env, 0); |
| return; |
| } |
| } |
| |
| if (id == java_awt_event_MouseEvent_MOUSE_WHEEL && |
| classMouseWheelEvent == NULL) { |
| sysClass = (*env)->FindClass(env, wheelClsName); |
| if (sysClass != NULL) { |
| /* Make this class 'sticky', we don't want it GC'd */ |
| classMouseWheelEvent = (*env)->NewGlobalRef(env, sysClass); |
| wheelmid = (*env)->GetMethodID(env, classMouseWheelEvent, |
| "<init>", |
| "(Ljava/awt/Component;IJIIIIIIZIII)V"); |
| } |
| if (JNU_IsNull(env, classMouseWheelEvent) || wheelmid == 0) { |
| JNU_ThrowClassNotFoundException(env, wheelClsName); |
| (*env)->PopLocalFrame(env, 0); |
| return; |
| } |
| } |
| |
| jWhen = awt_util_nowMillisUTC_offset(when); /* convert Time to UTC */ |
| |
| if (id == java_awt_event_MouseEvent_MOUSE_WHEEL) { |
| hEvent = (*env)->NewObject(env, classMouseWheelEvent, wheelmid, |
| target, id, jWhen, modifiers, |
| x, y, |
| xAbs, yAbs, |
| clickcount, popuptrigger, |
| /* Linux has no API for setting how a Component |
| * should scroll in response to the mouse wheel, |
| * so we have to make up our own. |
| * The default behavior on Windows is 3 lines of |
| * text, so we use that to match. |
| */ |
| java_awt_event_MouseWheelEvent_WHEEL_UNIT_SCROLL, |
| 3, |
| wheelAmt); |
| } |
| else { |
| hEvent = (*env)->NewObject(env, classMouseEvent, mid, |
| target, id, jWhen, modifiers, |
| x, y, |
| xAbs, yAbs, |
| clickcount, popuptrigger, button); |
| } |
| |
| |
| if ((*env)->ExceptionOccurred(env)) { |
| (*env)->ExceptionDescribe(env); |
| (*env)->ExceptionClear(env); |
| } |
| if (JNU_IsNull(env, hEvent)) { |
| JNU_ThrowNullPointerException(env, "NullPointerException: constructor failed."); |
| (*env)->PopLocalFrame(env, 0); |
| return; |
| } |
| awt_copyXEventToAWTEvent(env, event, hEvent); |
| JNU_CallMethodByName(env, NULL, peer, |
| "postEvent", "(Ljava/awt/AWTEvent;)V", hEvent); |
| if ((*env)->ExceptionOccurred(env)) { |
| (*env)->ExceptionDescribe(env); |
| (*env)->ExceptionClear(env); |
| } |
| (*env)->PopLocalFrame(env, 0); |
| } |