📄 sdl_x11events.c
字号:
/* SDL - Simple DirectMedia Layer Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Sam Lantinga slouken@libsdl.org*/#ifdef SAVE_RCSIDstatic char rcsid = "@(#) $Id: SDL_x11events.c,v 1.15 2002/09/16 07:09:04 slouken Exp $";#endif/* Handle the event stream, converting X11 events into SDL events */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <setjmp.h>#include <X11/Xlib.h>#include <X11/Xutil.h>#include <X11/keysym.h>#ifdef __SVR4#include <X11/Sunkeysym.h>#endif#include <sys/types.h>#include <sys/time.h>#include <unistd.h>#include "SDL.h"#include "SDL_syswm.h"#include "SDL_sysevents.h"#include "SDL_sysvideo.h"#include "SDL_events_c.h"#include "SDL_x11video.h"#include "SDL_x11dga_c.h"#include "SDL_x11modes_c.h"#include "SDL_x11image_c.h"#include "SDL_x11gamma_c.h"#include "SDL_x11wm_c.h"#include "SDL_x11mouse_c.h"#include "SDL_x11events_c.h"/* Define this if you want to debug X11 events *//*#define DEBUG_XEVENTS*//* The translation tables from an X11 keysym to a SDL keysym */static SDLKey ODD_keymap[256];static SDLKey MISC_keymap[256];SDL_keysym *X11_TranslateKey(Display *display, XKeyEvent *xkey, KeyCode kc, SDL_keysym *keysym);/* Check to see if this is a repeated key. (idea shamelessly lifted from GII -- thanks guys! :) */static int X11_KeyRepeat(Display *display, XEvent *event){ XEvent peekevent; int repeated; repeated = 0; if ( XPending(display) ) { XPeekEvent(display, &peekevent); if ( (peekevent.type == KeyPress) && (peekevent.xkey.keycode == event->xkey.keycode) && ((peekevent.xkey.time-event->xkey.time) < 2) ) { repeated = 1; XNextEvent(display, &peekevent); } } return(repeated);}/* Note: The X server buffers and accumulates mouse motion events, so the motion event generated by the warp may not appear exactly as we expect it to. We work around this (and improve performance) by only warping the pointer when it reaches the edge, and then wait for it.*/#define MOUSE_FUDGE_FACTOR 8static __inline__ int X11_WarpedMotion(_THIS, XEvent *xevent){ int w, h, i; int deltax, deltay; int posted; w = SDL_VideoSurface->w; h = SDL_VideoSurface->h; deltax = xevent->xmotion.x - mouse_last.x; deltay = xevent->xmotion.y - mouse_last.y;#ifdef DEBUG_MOTION printf("Warped mouse motion: %d,%d\n", deltax, deltay);#endif mouse_last.x = xevent->xmotion.x; mouse_last.y = xevent->xmotion.y; posted = SDL_PrivateMouseMotion(0, 1, deltax, deltay); if ( (xevent->xmotion.x < MOUSE_FUDGE_FACTOR) || (xevent->xmotion.x > (w-MOUSE_FUDGE_FACTOR)) || (xevent->xmotion.y < MOUSE_FUDGE_FACTOR) || (xevent->xmotion.y > (h-MOUSE_FUDGE_FACTOR)) ) { /* Get the events that have accumulated */ while ( XCheckTypedEvent(SDL_Display, MotionNotify, xevent) ) { deltax = xevent->xmotion.x - mouse_last.x; deltay = xevent->xmotion.y - mouse_last.y;#ifdef DEBUG_MOTION printf("Extra mouse motion: %d,%d\n", deltax, deltay);#endif mouse_last.x = xevent->xmotion.x; mouse_last.y = xevent->xmotion.y; posted += SDL_PrivateMouseMotion(0, 1, deltax, deltay); } mouse_last.x = w/2; mouse_last.y = h/2; XWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0, mouse_last.x, mouse_last.y); for ( i=0; i<10; ++i ) { XMaskEvent(SDL_Display, PointerMotionMask, xevent); if ( (xevent->xmotion.x > (mouse_last.x-MOUSE_FUDGE_FACTOR)) && (xevent->xmotion.x < (mouse_last.x+MOUSE_FUDGE_FACTOR)) && (xevent->xmotion.y > (mouse_last.y-MOUSE_FUDGE_FACTOR)) && (xevent->xmotion.y < (mouse_last.y+MOUSE_FUDGE_FACTOR)) ) { break; }#ifdef DEBUG_XEVENTS printf("Lost mouse motion: %d,%d\n", xevent->xmotion.x, xevent->xmotion.y);#endif }#ifdef DEBUG_XEVENTS if ( i == 10 ) { printf("Warning: didn't detect mouse warp motion\n"); }#endif } return(posted);}static int X11_DispatchEvent(_THIS){ int posted; XEvent xevent; XNextEvent(SDL_Display, &xevent); posted = 0; switch (xevent.type) { /* Gaining mouse coverage? */ case EnterNotify: {#ifdef DEBUG_XEVENTSprintf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);if ( xevent.xcrossing.mode == NotifyGrab )printf("Mode: NotifyGrab\n");if ( xevent.xcrossing.mode == NotifyUngrab )printf("Mode: NotifyUngrab\n");#endif if ( (xevent.xcrossing.mode != NotifyGrab) && (xevent.xcrossing.mode != NotifyUngrab) ) { if ( this->input_grab == SDL_GRAB_OFF ) { posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS); } else { posted = SDL_PrivateMouseMotion(0, 0, xevent.xcrossing.x, xevent.xcrossing.y); } } } break; /* Losing mouse coverage? */ case LeaveNotify: {#ifdef DEBUG_XEVENTSprintf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);if ( xevent.xcrossing.mode == NotifyGrab )printf("Mode: NotifyGrab\n");if ( xevent.xcrossing.mode == NotifyUngrab )printf("Mode: NotifyUngrab\n");#endif if ( (xevent.xcrossing.mode != NotifyGrab) && (xevent.xcrossing.mode != NotifyUngrab) && (xevent.xcrossing.detail != NotifyInferior) ) { if ( this->input_grab == SDL_GRAB_OFF ) { posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS); } else { posted = SDL_PrivateMouseMotion(0, 0, xevent.xcrossing.x, xevent.xcrossing.y); } } } break; /* Gaining input focus? */ case FocusIn: {#ifdef DEBUG_XEVENTSprintf("FocusIn!\n");#endif posted = SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS); /* Queue entry into fullscreen mode */ switch_waiting = 0x01 | SDL_FULLSCREEN; switch_time = SDL_GetTicks() + 1500; } break; /* Losing input focus? */ case FocusOut: {#ifdef DEBUG_XEVENTSprintf("FocusOut!\n");#endif posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS); /* Queue leaving fullscreen mode */ switch_waiting = 0x01; switch_time = SDL_GetTicks() + 200; } break; /* Generated upon EnterWindow and FocusIn */ case KeymapNotify: {#ifdef DEBUG_XEVENTSprintf("KeymapNotify!\n");#endif X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector); } break; /* Mouse motion? */ case MotionNotify: { if ( SDL_VideoSurface ) { if ( mouse_relative ) { if ( using_dga & DGA_MOUSE ) {#ifdef DEBUG_MOTION printf("DGA motion: %d,%d\n", xevent.xmotion.x_root, xevent.xmotion.y_root);#endif posted = SDL_PrivateMouseMotion(0, 1, xevent.xmotion.x_root, xevent.xmotion.y_root); } else { posted = X11_WarpedMotion(this,&xevent); } } else {#ifdef DEBUG_MOTION printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);#endif posted = SDL_PrivateMouseMotion(0, 0, xevent.xmotion.x, xevent.xmotion.y); } } } break; /* Mouse button press? */ case ButtonPress: { posted = SDL_PrivateMouseButton(SDL_PRESSED, xevent.xbutton.button, 0, 0); } break; /* Mouse button release? */ case ButtonRelease: { posted = SDL_PrivateMouseButton(SDL_RELEASED, xevent.xbutton.button, 0, 0); } break; /* Key press? */ case KeyPress: { SDL_keysym keysym;#ifdef DEBUG_XEVENTSprintf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);#endif posted = SDL_PrivateKeyboard(SDL_PRESSED, X11_TranslateKey(SDL_Display, &xevent.xkey, xevent.xkey.keycode, &keysym)); } break; /* Key release? */ case KeyRelease: { SDL_keysym keysym;#ifdef DEBUG_XEVENTSprintf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);#endif /* Check to see if this is a repeated key */ if ( ! X11_KeyRepeat(SDL_Display, &xevent) ) { posted = SDL_PrivateKeyboard(SDL_RELEASED, X11_TranslateKey(SDL_Display, &xevent.xkey, xevent.xkey.keycode, &keysym)); } } break; /* Have we been iconified? */ case UnmapNotify: {#ifdef DEBUG_XEVENTSprintf("UnmapNotify!\n");#endif /* If we're active, make ourselves inactive */ if ( SDL_GetAppState() & SDL_APPACTIVE ) { /* Swap out the gamma before we go inactive */ X11_SwapVidModeGamma(this); /* Send an internal deactivate event */ posted = SDL_PrivateAppActive(0, SDL_APPACTIVE|SDL_APPINPUTFOCUS); } } break; /* Have we been restored? */ case MapNotify: {#ifdef DEBUG_XEVENTSprintf("MapNotify!\n");#endif /* If we're not active, make ourselves active */ if ( !(SDL_GetAppState() & SDL_APPACTIVE) ) { /* Send an internal activate event */ posted = SDL_PrivateAppActive(1, SDL_APPACTIVE); /* Now that we're active, swap the gamma back */ X11_SwapVidModeGamma(this); } if ( SDL_VideoSurface && (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) { X11_EnterFullScreen(this); } else { X11_GrabInputNoLock(this, this->input_grab); } X11_CheckMouseModeNoLock(this); if ( SDL_VideoSurface ) { X11_RefreshDisplay(this); } } break; /* Have we been resized or moved? */ case ConfigureNotify: {#ifdef DEBUG_XEVENTSprintf("ConfigureNotify! (resize: %dx%d)\n", xevent.xconfigure.width, xevent.xconfigure.height);#endif if ( SDL_VideoSurface ) { if ((xevent.xconfigure.width != SDL_VideoSurface->w) || (xevent.xconfigure.height != SDL_VideoSurface->h)) { /* FIXME: Find a better fix for the bug with KDE 1.2 */ if ( ! ((xevent.xconfigure.width == 32) && (xevent.xconfigure.height == 32)) ) { SDL_PrivateResize(xevent.xconfigure.width, xevent.xconfigure.height); } } else { /* OpenGL windows need to know about the change */ if ( SDL_VideoSurface->flags & SDL_OPENGL ) { SDL_PrivateExpose(); } } } } break; /* Have we been requested to quit (or another client message?) */ case ClientMessage: { if ( (xevent.xclient.format == 32) && (xevent.xclient.data.l[0] == WM_DELETE_WINDOW) ) { posted = SDL_PrivateQuit(); } else if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) { SDL_SysWMmsg wmmsg; SDL_VERSION(&wmmsg.version); wmmsg.subsystem = SDL_SYSWM_X11; wmmsg.event.xevent = xevent; posted = SDL_PrivateSysWMEvent(&wmmsg); } } break; /* Do we need to refresh ourselves? */ case Expose: {#ifdef DEBUG_XEVENTSprintf("Expose (count = %d)\n", xevent.xexpose.count);#endif if ( SDL_VideoSurface && (xevent.xexpose.count == 0) ) { X11_RefreshDisplay(this); } } break; default: {#ifdef DEBUG_XEVENTSprintf("Unhandled event %d\n", xevent.type);#endif /* Only post the event if we're watching for it */ if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) { SDL_SysWMmsg wmmsg; SDL_VERSION(&wmmsg.version); wmmsg.subsystem = SDL_SYSWM_X11; wmmsg.event.xevent = xevent; posted = SDL_PrivateSysWMEvent(&wmmsg); } } break; } return(posted);}/* Ack! XPending() actually performs a blocking read if no events available */int X11_Pending(Display *display){ /* Flush the display connection and look to see if events are queued */ XFlush(display); if ( XEventsQueued(display, QueuedAlready) ) { return(1); } /* More drastic measures are required -- see if X is ready to talk */ { static struct timeval zero_time; /* static == 0 */ int x11_fd; fd_set fdset; x11_fd = ConnectionNumber(display); FD_ZERO(&fdset); FD_SET(x11_fd, &fdset); if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 ) { return(XPending(display)); } } /* Oh well, nothing is ready .. */ return(0);}void X11_PumpEvents(_THIS){ int pending; /* Keep processing pending events */ pending = 0; while ( X11_Pending(SDL_Display) ) { X11_DispatchEvent(this); ++pending; } if ( switch_waiting ) { Uint32 now; now = SDL_GetTicks();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -