| /* |
| * X events handling functions |
| * |
| * Copyright 1993 Alexandre Julliard |
| */ |
| |
| static char Copyright[] = "Copyright Alexandre Julliard, 1993"; |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <X11/Xlib.h> |
| #include <X11/Xresource.h> |
| #include <X11/Xutil.h> |
| |
| #include "windows.h" |
| #include "win.h" |
| #include "class.h" |
| #include "message.h" |
| |
| #ifdef ndef |
| #ifndef FamilyAmoeba |
| typedef char *XPointer; |
| #endif |
| #endif |
| |
| #define NB_BUTTONS 3 /* Windows can handle 3 buttons */ |
| |
| extern int desktopX, desktopY; /* misc/main.c */ |
| |
| extern void WINPOS_ChangeActiveWindow( HWND hwnd, BOOL mouseMsg ); /*winpos.c*/ |
| |
| /* X context to associate a hwnd to an X window */ |
| static XContext winContext = 0; |
| |
| /* State variables */ |
| BOOL MouseButtonsStates[NB_BUTTONS] = { FALSE, FALSE, FALSE }; |
| static WORD ALTKeyState; |
| static HWND captureWnd = 0; |
| Window winHasCursor = 0; |
| |
| /* Keyboard translation tables */ |
| static int special_key[] = |
| { |
| VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */ |
| 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */ |
| 0, 0, 0, VK_ESCAPE /* FF18 */ |
| }; |
| |
| static cursor_key[] = |
| { |
| VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR, |
| VK_NEXT, VK_END /* FF50 */ |
| }; |
| |
| static misc_key[] = |
| { |
| VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */ |
| VK_CANCEL, VK_HELP, VK_CANCEL, VK_MENU /* FF68 */ |
| }; |
| |
| static keypad_key[] = |
| { |
| VK_MENU, VK_NUMLOCK, /* FF7E */ |
| 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */ |
| 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */ |
| 0, 0, 0, 0, 0, 0, 0, 0, /* FF90 */ |
| 0, 0, 0, 0, 0, 0, 0, 0, /* FF98 */ |
| 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */ |
| 0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT, |
| VK_DECIMAL, VK_DIVIDE, /* FFA8 */ |
| VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, |
| VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */ |
| VK_NUMPAD8, VK_NUMPAD9 /* FFB8 */ |
| }; |
| |
| static function_key[] = |
| { |
| VK_F1, VK_F2, /* FFBE */ |
| VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */ |
| VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16 /* FFC8 */ |
| }; |
| |
| static modifier_key[] = |
| { |
| VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL, |
| 0, 0, /* FFE1 */ |
| 0, VK_MENU, VK_MENU /* FFE8 */ |
| }; |
| |
| typedef union |
| { |
| struct |
| { |
| unsigned long count : 16; |
| unsigned long code : 8; |
| unsigned long extended : 1; |
| unsigned long : 4; |
| unsigned long context : 1; |
| unsigned long previous : 1; |
| unsigned long transition : 1; |
| } lp1; |
| unsigned long lp2; |
| } KEYLP; |
| |
| static BOOL KeyDown = FALSE; |
| |
| |
| #ifdef DEBUG_EVENT |
| static char *event_names[] = |
| { |
| "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease", |
| "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut", |
| "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify", |
| "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest", |
| "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", |
| "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify", |
| "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify", |
| "ClientMessage", "MappingNotify" |
| }; |
| #endif |
| |
| /* Event handlers */ |
| static void EVENT_key( HWND hwnd, XKeyEvent *event ); |
| static void EVENT_ButtonPress( XButtonEvent *event ); |
| static void EVENT_ButtonRelease( XButtonEvent *event ); |
| static void EVENT_MotionNotify( XMotionEvent *event ); |
| static void EVENT_EnterNotify( XCrossingEvent *event ); |
| static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event ); |
| static void EVENT_Expose( HWND hwnd, XExposeEvent *event ); |
| static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event ); |
| |
| |
| /*********************************************************************** |
| * EVENT_ProcessEvent |
| * |
| * Process an X event. |
| */ |
| void EVENT_ProcessEvent( XEvent *event ) |
| { |
| HWND hwnd; |
| XPointer ptr; |
| |
| XFindContext( display, ((XAnyEvent *)event)->window, winContext, &ptr ); |
| hwnd = (HWND) (int)ptr; |
| |
| #ifdef DEBUG_EVENT |
| printf( "Got event %s for hwnd %d\n", event_names[event->type], hwnd ); |
| #endif |
| |
| switch(event->type) |
| { |
| case KeyPress: |
| case KeyRelease: |
| EVENT_key( hwnd, (XKeyEvent*)event ); |
| break; |
| |
| case ButtonPress: |
| EVENT_ButtonPress( (XButtonEvent*)event ); |
| break; |
| |
| case ButtonRelease: |
| EVENT_ButtonRelease( (XButtonEvent*)event ); |
| break; |
| |
| case MotionNotify: |
| EVENT_MotionNotify( (XMotionEvent*)event ); |
| break; |
| |
| case EnterNotify: |
| EVENT_EnterNotify( (XCrossingEvent*)event ); |
| break; |
| |
| case FocusOut: |
| EVENT_FocusOut( hwnd, (XFocusChangeEvent*)event ); |
| break; |
| |
| case Expose: |
| EVENT_Expose( hwnd, (XExposeEvent*)event ); |
| break; |
| |
| case ConfigureNotify: |
| EVENT_ConfigureNotify( hwnd, (XConfigureEvent*)event ); |
| break; |
| |
| #ifdef DEBUG_EVENT |
| default: |
| printf( "Unprocessed event %s for hwnd %d\n", |
| event_names[event->type], hwnd ); |
| break; |
| #endif |
| } |
| } |
| |
| |
| /*********************************************************************** |
| * EVENT_RegisterWindow |
| * |
| * Associate an X window to a HWND. |
| */ |
| void EVENT_RegisterWindow( Window w, HWND hwnd ) |
| { |
| if (!winContext) winContext = XUniqueContext(); |
| XSaveContext( display, w, winContext, (XPointer)(int)hwnd ); |
| } |
| |
| |
| /*********************************************************************** |
| * EVENT_XStateToKeyState |
| * |
| * Translate a X event state (Button1Mask, ShiftMask, etc...) to |
| * a Windows key state (MK_SHIFT, MK_CONTROL, etc...) |
| */ |
| static WORD EVENT_XStateToKeyState( int state ) |
| { |
| int kstate = 0; |
| |
| if (state & Button1Mask) kstate |= MK_LBUTTON; |
| if (state & Button2Mask) kstate |= MK_MBUTTON; |
| if (state & Button3Mask) kstate |= MK_RBUTTON; |
| if (state & ShiftMask) kstate |= MK_SHIFT; |
| if (state & ControlMask) kstate |= MK_CONTROL; |
| return kstate; |
| } |
| |
| |
| /*********************************************************************** |
| * EVENT_Expose |
| */ |
| static void EVENT_Expose( HWND hwnd, XExposeEvent *event ) |
| { |
| RECT rect; |
| UINT flags; |
| WND * wndPtr = WIN_FindWndPtr( hwnd ); |
| if (!wndPtr) return; |
| |
| /* Make position relative to client area instead of window */ |
| rect.left = event->x - (wndPtr->rectClient.left - wndPtr->rectWindow.left); |
| rect.top = event->y - (wndPtr->rectClient.top - wndPtr->rectWindow.top); |
| rect.right = rect.left + event->width; |
| rect.bottom = rect.top + event->height; |
| winHasCursor = event->window; |
| |
| flags = RDW_INVALIDATE | RDW_ERASE | RDW_FRAME; |
| /* Erase desktop background synchronously */ |
| if (event->window == rootWindow) flags |= RDW_ERASENOW | RDW_NOCHILDREN; |
| RedrawWindow( hwnd, &rect, 0, flags ); |
| } |
| |
| |
| /*********************************************************************** |
| * EVENT_key |
| * |
| * Handle a X key event |
| */ |
| static void EVENT_key( HWND hwnd, XKeyEvent *event ) |
| { |
| char Str[24]; |
| XComposeStatus cs; |
| KeySym keysym; |
| WORD xkey, vkey, key_type, key; |
| KEYLP keylp; |
| BOOL extended = FALSE; |
| |
| int count = XLookupString(event, Str, 1, &keysym, &cs); |
| Str[count] = '\0'; |
| #ifdef DEBUG_KEY |
| printf("WM_KEY??? : keysym=%lX, count=%u / %X / '%s'\n", |
| keysym, count, Str[0], Str); |
| #endif |
| |
| xkey = LOWORD(keysym); |
| key_type = HIBYTE(xkey); |
| key = LOBYTE(xkey); |
| #ifdef DEBUG_KEY |
| printf(" key_type=%X, key=%X\n", key_type, key); |
| #endif |
| |
| if (key_type == 0xFF) /* non-character key */ |
| { |
| if (key >= 0x08 && key <= 0x1B) /* special key */ |
| vkey = special_key[key - 0x08]; |
| else if (key >= 0x50 && key <= 0x57) /* cursor key */ |
| vkey = cursor_key[key - 0x50]; |
| else if (key >= 0x60 && key <= 0x6B) /* miscellaneous key */ |
| vkey = misc_key[key - 0x60]; |
| else if (key >= 0x7E && key <= 0xB9) /* keypad key */ |
| { |
| vkey = keypad_key[key - 0x7E]; |
| extended = TRUE; |
| } |
| else if (key >= 0xBE && key <= 0xCD) /* function key */ |
| { |
| vkey = function_key[key - 0xBE]; |
| extended = TRUE; |
| } |
| else if (key >= 0xE1 && key <= 0xEA) /* modifier key */ |
| vkey = modifier_key[key - 0xE1]; |
| else if (key == 0xFF) /* DEL key */ |
| vkey = VK_DELETE; |
| } |
| else if (key_type == 0) /* character key */ |
| { |
| if (key >= 0x61 && key <= 0x7A) |
| vkey = key - 0x20; /* convert lower to uppercase */ |
| else |
| vkey = key; |
| } |
| |
| if (event->type == KeyPress) |
| { |
| if (vkey == VK_MENU) ALTKeyState = TRUE; |
| keylp.lp1.count = 1; |
| keylp.lp1.code = LOBYTE(event->keycode); |
| keylp.lp1.extended = (extended ? 1 : 0); |
| keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0); |
| keylp.lp1.previous = (KeyDown ? 0 : 1); |
| keylp.lp1.transition = 0; |
| #ifdef DEBUG_KEY |
| printf(" wParam=%X, lParam=%lX\n", vkey, keylp.lp2 ); |
| #endif |
| hardware_event( ALTKeyState ? WM_SYSKEYDOWN : WM_KEYDOWN, |
| vkey, keylp.lp2, |
| event->x_root - desktopX, event->y_root - desktopY, |
| event->time, 0 ); |
| KeyDown = TRUE; |
| |
| /* The key translation ought to take place in TranslateMessage(). |
| * However, there is no way of passing the required information |
| * in a Windows message, so TranslateMessage does not currently |
| * do anything and the translation is done here. |
| */ |
| if (count == 1) /* key has an ASCII representation */ |
| { |
| #ifdef DEBUG_KEY |
| printf("WM_CHAR : wParam=%X\n", (WORD)Str[0] ); |
| #endif |
| PostMessage( GetFocus(), WM_CHAR, (WORD)Str[0], keylp.lp2 ); |
| } |
| } |
| else |
| { |
| if (vkey == VK_MENU) ALTKeyState = FALSE; |
| keylp.lp1.count = 1; |
| keylp.lp1.code = LOBYTE(event->keycode); |
| keylp.lp1.extended = (extended ? 1 : 0); |
| keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0); |
| keylp.lp1.previous = 1; |
| keylp.lp1.transition = 1; |
| #ifdef DEBUG_KEY |
| printf(" wParam=%X, lParam=%lX\n", vkey, keylp.lp2 ); |
| #endif |
| hardware_event( ((ALTKeyState || vkey == VK_MENU) ? |
| WM_SYSKEYUP : WM_KEYUP), |
| vkey, keylp.lp2, |
| event->x_root - desktopX, event->y_root - desktopY, |
| event->time, 0 ); |
| KeyDown = FALSE; |
| } |
| } |
| |
| |
| /*********************************************************************** |
| * EVENT_MotionNotify |
| */ |
| static void EVENT_MotionNotify( XMotionEvent *event ) |
| { |
| hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L, |
| event->x_root - desktopX, event->y_root - desktopY, |
| event->time, 0 ); |
| } |
| |
| |
| /*********************************************************************** |
| * EVENT_ButtonPress |
| */ |
| static void EVENT_ButtonPress( XButtonEvent *event ) |
| { |
| static WORD messages[NB_BUTTONS] = |
| { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN }; |
| int buttonNum = event->button - 1; |
| |
| if (buttonNum >= NB_BUTTONS) return; |
| MouseButtonsStates[buttonNum] = TRUE; |
| winHasCursor = event->window; |
| hardware_event( messages[buttonNum], |
| EVENT_XStateToKeyState( event->state ), 0L, |
| event->x_root - desktopX, event->y_root - desktopY, |
| event->time, 0 ); |
| } |
| |
| |
| /*********************************************************************** |
| * EVENT_ButtonRelease |
| */ |
| static void EVENT_ButtonRelease( XButtonEvent *event ) |
| { |
| static const WORD messages[NB_BUTTONS] = |
| { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP }; |
| int buttonNum = event->button - 1; |
| |
| if (buttonNum >= NB_BUTTONS) return; |
| MouseButtonsStates[buttonNum] = FALSE; |
| winHasCursor = event->window; |
| hardware_event( messages[buttonNum], |
| EVENT_XStateToKeyState( event->state ), 0L, |
| event->x_root - desktopX, event->y_root - desktopY, |
| event->time, 0 ); |
| } |
| |
| |
| /********************************************************************** |
| * EVENT_FocusOut |
| * |
| * Note: only top-level override-redirect windows get FocusOut events. |
| */ |
| static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event ) |
| { |
| if (event->detail == NotifyPointer) return; |
| if (hwnd == GetActiveWindow()) WINPOS_ChangeActiveWindow( 0, FALSE ); |
| if ((hwnd == GetFocus()) || IsChild( hwnd, GetFocus())) SetFocus( 0 ); |
| } |
| |
| |
| /********************************************************************** |
| * EVENT_EnterNotify |
| */ |
| static void EVENT_EnterNotify( XCrossingEvent *event ) |
| { |
| if (captureWnd != 0) return; |
| winHasCursor = event->window; |
| } |
| |
| |
| /********************************************************************** |
| * EVENT_ConfigureNotify |
| * |
| * The ConfigureNotify event is only selected on the desktop window. |
| */ |
| static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event ) |
| { |
| desktopX = event->x; |
| desktopY = event->y; |
| } |
| |
| |
| /********************************************************************** |
| * SetCapture (USER.18) |
| */ |
| HWND SetCapture(HWND wnd) |
| { |
| int rv; |
| HWND old_capture_wnd = captureWnd; |
| WND *wnd_p = WIN_FindWndPtr(wnd); |
| if (wnd_p == NULL) |
| return 0; |
| |
| rv = XGrabPointer(display, wnd_p->window, False, |
| ButtonPressMask | ButtonReleaseMask | PointerMotionMask, |
| GrabModeAsync, GrabModeAsync, None, None, CurrentTime); |
| |
| if (rv == GrabSuccess) |
| { |
| captureWnd = wnd; |
| return old_capture_wnd; |
| } |
| else |
| return 0; |
| } |
| |
| /********************************************************************** |
| * ReleaseCapture (USER.19) |
| */ |
| void ReleaseCapture() |
| { |
| if (captureWnd == 0) return; |
| XUngrabPointer( display, CurrentTime ); |
| captureWnd = 0; |
| } |
| |
| /********************************************************************** |
| * GetCapture (USER.236) |
| */ |
| HWND GetCapture() |
| { |
| return captureWnd; |
| } |