440 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			440 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Darwin event queue and event handling
 | |
|  */
 | |
| /*
 | |
| Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved.
 | |
| 
 | |
| This file is based on mieq.c by Keith Packard,
 | |
| which contains the following copyright:
 | |
| Copyright 1990, 1998  The Open Group
 | |
| 
 | |
| Permission to use, copy, modify, distribute, and sell this software and its
 | |
| documentation for any purpose is hereby granted without fee, provided that
 | |
| the above copyright notice appear in all copies and that both that
 | |
| copyright notice and this permission notice appear in supporting
 | |
| documentation.
 | |
| 
 | |
| The above copyright notice and this permission notice shall be included in
 | |
| all copies or substantial portions of the Software.
 | |
| 
 | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 | |
| OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 | |
| AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | |
| 
 | |
| Except as contained in this notice, the name of The Open Group shall not be
 | |
| used in advertising or otherwise to promote the sale, use or other dealings
 | |
| in this Software without prior written authorization from The Open Group.
 | |
|  */
 | |
| /* $XFree86: xc/programs/Xserver/hw/darwin/darwinEvents.c,v 1.5 2003/11/03 05:36:30 tsi Exp $ */
 | |
| 
 | |
| #define NEED_EVENTS
 | |
| #include   "X.h"
 | |
| #include   "Xmd.h"
 | |
| #include   "Xproto.h"
 | |
| #include   "misc.h"
 | |
| #include   "windowstr.h"
 | |
| #include   "pixmapstr.h"
 | |
| #include   "inputstr.h"
 | |
| #include   "mi.h"
 | |
| #include   "scrnintstr.h"
 | |
| #include   "mipointer.h"
 | |
| 
 | |
| #include "darwin.h"
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/uio.h>
 | |
| #include <unistd.h>
 | |
| #include <IOKit/hidsystem/IOLLEvent.h>
 | |
| 
 | |
| /* Fake button press/release for scroll wheel move. */
 | |
| #define SCROLLWHEELUPFAKE	4
 | |
| #define SCROLLWHEELDOWNFAKE	5
 | |
| 
 | |
| #define QUEUE_SIZE 256
 | |
| 
 | |
| typedef struct _Event {
 | |
|     xEvent	event;
 | |
|     ScreenPtr	pScreen;
 | |
| } EventRec, *EventPtr;
 | |
| 
 | |
| typedef struct _EventQueue {
 | |
|     HWEventQueueType	head, tail; /* long for SetInputCheck */
 | |
|     CARD32	lastEventTime;      /* to avoid time running backwards */
 | |
|     Bool	lastMotion;
 | |
|     EventRec	events[QUEUE_SIZE]; /* static allocation for signals */
 | |
|     DevicePtr	pKbd, pPtr;         /* device pointer, to get funcs */
 | |
|     ScreenPtr	pEnqueueScreen;     /* screen events are being delivered to */
 | |
|     ScreenPtr	pDequeueScreen;     /* screen events are being dispatched to */
 | |
| } EventQueueRec, *EventQueuePtr;
 | |
| 
 | |
| static EventQueueRec darwinEventQueue;
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * DarwinPressModifierMask
 | |
|  *  Press or release the given modifier key, specified by its mask.
 | |
|  */
 | |
| static void DarwinPressModifierMask(
 | |
|     xEvent *xe,      // must already have type, time and mouse location
 | |
|     int mask)       // one of NX_*MASK constants
 | |
| {
 | |
|     int key = DarwinModifierNXMaskToNXKey(mask);
 | |
| 
 | |
|     if (key != -1) {
 | |
|         int keycode = DarwinModifierNXKeyToNXKeycode(key, 0);
 | |
|         if (keycode != 0) {
 | |
|             xe->u.u.detail = keycode + MIN_KEYCODE;
 | |
|             (*darwinEventQueue.pKbd->processInputProc)(xe,
 | |
|                             (DeviceIntPtr)darwinEventQueue.pKbd, 1);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * DarwinUpdateModifiers
 | |
|  *  Send events to update the modifier state.
 | |
|  */
 | |
| static void DarwinUpdateModifiers(
 | |
|     xEvent *xe,         // event template with time and mouse position set
 | |
|     int pressed,        // KeyPress or KeyRelease
 | |
|     int flags )         // modifier flags that have changed
 | |
| {
 | |
|     xe->u.u.type = pressed;
 | |
|     if (flags & NX_ALPHASHIFTMASK) {
 | |
|         DarwinPressModifierMask(xe, NX_ALPHASHIFTMASK);
 | |
|     }
 | |
|     if (flags & NX_COMMANDMASK) {
 | |
|         DarwinPressModifierMask(xe, NX_COMMANDMASK);
 | |
|     }
 | |
|     if (flags & NX_CONTROLMASK) {
 | |
|         DarwinPressModifierMask(xe, NX_CONTROLMASK);
 | |
|     }
 | |
|     if (flags & NX_ALTERNATEMASK) {
 | |
|         DarwinPressModifierMask(xe, NX_ALTERNATEMASK);
 | |
|     }
 | |
|     if (flags & NX_SHIFTMASK) {
 | |
|         DarwinPressModifierMask(xe, NX_SHIFTMASK);
 | |
|     }
 | |
|     if (flags & NX_SECONDARYFNMASK) {
 | |
|         DarwinPressModifierMask(xe, NX_SECONDARYFNMASK);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * DarwinSimulateMouseClick
 | |
|  *  Send a mouse click to X when multiple mouse buttons are simulated
 | |
|  *  with modifier-clicks, such as command-click for button 2. The dix
 | |
|  *  layer is told that the previously pressed modifier key(s) are
 | |
|  *  released, the simulated click event is sent. After the mouse button
 | |
|  *  is released, the modifier keys are reverted to their actual state,
 | |
|  *  which may or may not be pressed at that point. This is usually
 | |
|  *  closest to what the user wants. Ie. the user typically wants to
 | |
|  *  simulate a button 2 press instead of Command-button 2.
 | |
|  */
 | |
| static void DarwinSimulateMouseClick(
 | |
|     xEvent *xe,         // event template with time and
 | |
|                         // mouse position filled in
 | |
|     int whichButton,    // mouse button to be pressed
 | |
|     int modifierMask)   // modifiers used for the fake click
 | |
| {
 | |
|     // first fool X into forgetting about the keys
 | |
|     DarwinUpdateModifiers(xe, KeyRelease, modifierMask);
 | |
| 
 | |
|     // push the mouse button
 | |
|     xe->u.u.type = ButtonPress;
 | |
|     xe->u.u.detail = whichButton;
 | |
|     (*darwinEventQueue.pPtr->processInputProc)
 | |
|             (xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 | |
| }
 | |
| 
 | |
| 
 | |
| Bool
 | |
| DarwinEQInit(
 | |
|     DevicePtr pKbd,
 | |
|     DevicePtr pPtr)
 | |
| {
 | |
|     darwinEventQueue.head = darwinEventQueue.tail = 0;
 | |
|     darwinEventQueue.lastEventTime = GetTimeInMillis ();
 | |
|     darwinEventQueue.pKbd = pKbd;
 | |
|     darwinEventQueue.pPtr = pPtr;
 | |
|     darwinEventQueue.pEnqueueScreen = screenInfo.screens[0];
 | |
|     darwinEventQueue.pDequeueScreen = darwinEventQueue.pEnqueueScreen;
 | |
|     SetInputCheck (&darwinEventQueue.head, &darwinEventQueue.tail);
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * DarwinEQEnqueue
 | |
|  *  Must be thread safe with ProcessInputEvents.
 | |
|  *    DarwinEQEnqueue    - called from event gathering thread
 | |
|  *    ProcessInputEvents - called from X server thread
 | |
|  *  DarwinEQEnqueue should never be called from more than one thread.
 | |
|  */
 | |
| void
 | |
| DarwinEQEnqueue(
 | |
|     const xEvent *e)
 | |
| {
 | |
|     HWEventQueueType oldtail, newtail;
 | |
|     char byte = 0;
 | |
| 
 | |
|     oldtail = darwinEventQueue.tail;
 | |
| 
 | |
|     // mieqEnqueue() collapses successive motion events into one event.
 | |
|     // This is difficult to do in a thread-safe way and rarely useful.
 | |
| 
 | |
|     newtail = oldtail + 1;
 | |
|     if (newtail == QUEUE_SIZE)
 | |
|         newtail = 0;
 | |
|     /* Toss events which come in late */
 | |
|     if (newtail == darwinEventQueue.head)
 | |
|         return;
 | |
| 
 | |
|     darwinEventQueue.events[oldtail].event = *e;
 | |
|     /*
 | |
|      * Make sure that event times don't go backwards - this
 | |
|      * is "unnecessary", but very useful
 | |
|      */
 | |
|     if (e->u.keyButtonPointer.time < darwinEventQueue.lastEventTime &&
 | |
| 	darwinEventQueue.lastEventTime - e->u.keyButtonPointer.time < 10000)
 | |
|     {
 | |
| 	darwinEventQueue.events[oldtail].event.u.keyButtonPointer.time =
 | |
| 	    darwinEventQueue.lastEventTime;
 | |
|     }
 | |
|     darwinEventQueue.events[oldtail].pScreen = darwinEventQueue.pEnqueueScreen;
 | |
| 
 | |
|     // Update the tail after the event is prepared
 | |
|     darwinEventQueue.tail = newtail;
 | |
| 
 | |
|     // Signal there is an event ready to handle
 | |
|     write(darwinEventWriteFD, &byte, 1);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * DarwinEQPointerPost
 | |
|  *  Post a pointer event. Used by the mipointer.c routines.
 | |
|  */
 | |
| void
 | |
| DarwinEQPointerPost(
 | |
|     xEvent *e)
 | |
| {
 | |
|     (*darwinEventQueue.pPtr->processInputProc)
 | |
|             (e, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| DarwinEQSwitchScreen(
 | |
|     ScreenPtr   pScreen,
 | |
|     Bool        fromDIX)
 | |
| {
 | |
|     darwinEventQueue.pEnqueueScreen = pScreen;
 | |
|     if (fromDIX)
 | |
| 	darwinEventQueue.pDequeueScreen = pScreen;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * ProcessInputEvents
 | |
|  *  Read and process events from the event queue until it is empty.
 | |
|  */
 | |
| void ProcessInputEvents(void)
 | |
| {
 | |
|     EventRec	*e;
 | |
|     int		x, y;
 | |
|     xEvent	xe;
 | |
|     static int  old_flags = 0;	// last known modifier state
 | |
|     // button number and modifier mask of currently pressed fake button
 | |
|     static int darwinFakeMouseButtonDown = 0;
 | |
|     static int darwinFakeMouseButtonMask = 0;
 | |
| 
 | |
|     // Empty the signaling pipe
 | |
|     x = sizeof(xe);
 | |
|     while (x == sizeof(xe)) {
 | |
|         x = read(darwinEventReadFD, &xe, sizeof(xe));
 | |
|     }
 | |
| 
 | |
|     while (darwinEventQueue.head != darwinEventQueue.tail)
 | |
|     {
 | |
| 	if (screenIsSaved == SCREEN_SAVER_ON)
 | |
| 	    SaveScreens (SCREEN_SAVER_OFF, ScreenSaverReset);
 | |
| 
 | |
| 	e = &darwinEventQueue.events[darwinEventQueue.head];
 | |
|         xe = e->event;
 | |
| 
 | |
|         // Shift from global screen coordinates to coordinates relative to
 | |
|         // the origin of the current screen.
 | |
|         xe.u.keyButtonPointer.rootX -= darwinMainScreenX +
 | |
|                 dixScreenOrigins[miPointerCurrentScreen()->myNum].x;
 | |
|         xe.u.keyButtonPointer.rootY -= darwinMainScreenY +
 | |
|                 dixScreenOrigins[miPointerCurrentScreen()->myNum].y;
 | |
| 
 | |
| 	/*
 | |
| 	 * Assumption - screen switching can only occur on motion events
 | |
| 	 */
 | |
| 	if (e->pScreen != darwinEventQueue.pDequeueScreen)
 | |
| 	{
 | |
| 	    darwinEventQueue.pDequeueScreen = e->pScreen;
 | |
| 	    x = xe.u.keyButtonPointer.rootX;
 | |
| 	    y = xe.u.keyButtonPointer.rootY;
 | |
| 	    if (darwinEventQueue.head == QUEUE_SIZE - 1)
 | |
| 	    	darwinEventQueue.head = 0;
 | |
| 	    else
 | |
| 	    	++darwinEventQueue.head;
 | |
| 	    NewCurrentScreen (darwinEventQueue.pDequeueScreen, x, y);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 	    if (darwinEventQueue.head == QUEUE_SIZE - 1)
 | |
| 	    	darwinEventQueue.head = 0;
 | |
| 	    else
 | |
| 	    	++darwinEventQueue.head;
 | |
| 	    switch (xe.u.u.type) 
 | |
| 	    {
 | |
| 	    case KeyPress:
 | |
| 	    case KeyRelease:
 | |
|                 xe.u.u.detail += MIN_KEYCODE;
 | |
| 	    	(*darwinEventQueue.pKbd->processInputProc)
 | |
| 				(&xe, (DeviceIntPtr)darwinEventQueue.pKbd, 1);
 | |
| 	    	break;
 | |
| 
 | |
| 	    case ButtonPress:
 | |
|                 miPointerAbsoluteCursor(xe.u.keyButtonPointer.rootX,
 | |
|                                         xe.u.keyButtonPointer.rootY,
 | |
|                                         xe.u.keyButtonPointer.time);
 | |
|                 if (darwinFakeButtons && xe.u.u.detail == 1) {
 | |
|                     // Mimic multi-button mouse with modifier-clicks
 | |
|                     // If both sets of modifiers are pressed,
 | |
|                     // button 2 is clicked.
 | |
|                     if ((old_flags & darwinFakeMouse2Mask) ==
 | |
|                         darwinFakeMouse2Mask)
 | |
|                     {
 | |
|                         DarwinSimulateMouseClick(&xe, 2, darwinFakeMouse2Mask);
 | |
|                         darwinFakeMouseButtonDown = 2;
 | |
|                         darwinFakeMouseButtonMask = darwinFakeMouse2Mask;
 | |
|                         break;
 | |
|                     }
 | |
|                     else if ((old_flags & darwinFakeMouse3Mask) ==
 | |
|                              darwinFakeMouse3Mask)
 | |
|                     {
 | |
|                         DarwinSimulateMouseClick(&xe, 3, darwinFakeMouse3Mask);
 | |
|                         darwinFakeMouseButtonDown = 3;
 | |
|                         darwinFakeMouseButtonMask = darwinFakeMouse3Mask;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|                 (*darwinEventQueue.pPtr->processInputProc)
 | |
|                         (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 | |
|                 break;
 | |
| 
 | |
|             case ButtonRelease:
 | |
|                 miPointerAbsoluteCursor(xe.u.keyButtonPointer.rootX,
 | |
|                                         xe.u.keyButtonPointer.rootY,
 | |
|                                         xe.u.keyButtonPointer.time);
 | |
|                 if (darwinFakeButtons && xe.u.u.detail == 1 &&
 | |
|                     darwinFakeMouseButtonDown)
 | |
|                 {
 | |
|                     // If last mousedown was a fake click, don't check for
 | |
|                     // mouse modifiers here. The user may have released the
 | |
|                     // modifiers before the mouse button.
 | |
|                     xe.u.u.detail = darwinFakeMouseButtonDown;
 | |
|                     darwinFakeMouseButtonDown = 0;
 | |
|                     (*darwinEventQueue.pPtr->processInputProc)
 | |
|                             (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 | |
| 
 | |
|                     // Bring modifiers back up to date
 | |
|                     DarwinUpdateModifiers(&xe, KeyPress,
 | |
|                             darwinFakeMouseButtonMask & old_flags);
 | |
|                     darwinFakeMouseButtonMask = 0;
 | |
|                 } else {
 | |
|                     (*darwinEventQueue.pPtr->processInputProc)
 | |
|                             (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 | |
|                 }
 | |
|                 break;
 | |
| 
 | |
|             case MotionNotify:
 | |
|                 miPointerAbsoluteCursor(xe.u.keyButtonPointer.rootX,
 | |
|                                         xe.u.keyButtonPointer.rootY,
 | |
|                                         xe.u.keyButtonPointer.time);
 | |
| 	    	break;
 | |
| 
 | |
|             case kXDarwinUpdateModifiers:
 | |
|             {
 | |
|                 // Update modifier state.
 | |
|                 // Any amount of modifiers may have changed.
 | |
|                 int flags = xe.u.clientMessage.u.l.longs0;
 | |
|                 DarwinUpdateModifiers(&xe, KeyRelease,
 | |
|                                       old_flags & ~flags);
 | |
|                 DarwinUpdateModifiers(&xe, KeyPress,
 | |
|                                       ~old_flags & flags);
 | |
|                 old_flags = flags;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case kXDarwinUpdateButtons:
 | |
|             {
 | |
|                 long hwDelta = xe.u.clientMessage.u.l.longs0;
 | |
|                 long hwButtons = xe.u.clientMessage.u.l.longs1;
 | |
|                 int i;
 | |
| 
 | |
|                 for (i = 1; i < 5; i++) {
 | |
|                     if (hwDelta & (1 << i)) {
 | |
|                         // IOKit and X have different numbering for the
 | |
|                         // middle and right mouse buttons.
 | |
|                         if (i == 1) {
 | |
|                             xe.u.u.detail = 3;
 | |
|                         } else if (i == 2) {
 | |
|                             xe.u.u.detail = 2;
 | |
|                         } else {
 | |
|                             xe.u.u.detail = i + 1;
 | |
|                         }
 | |
|                         if (hwButtons & (1 << i)) {
 | |
|                             xe.u.u.type = ButtonPress;
 | |
|                         } else {
 | |
|                             xe.u.u.type = ButtonRelease;
 | |
|                         }
 | |
|                         (*darwinEventQueue.pPtr->processInputProc)
 | |
| 				(&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 | |
|                     }
 | |
|                 }
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case kXDarwinScrollWheel:
 | |
|             {
 | |
|                 short count = xe.u.clientMessage.u.s.shorts0;
 | |
| 
 | |
|                 if (count > 0) {
 | |
|                     xe.u.u.detail = SCROLLWHEELUPFAKE;
 | |
|                 } else {
 | |
|                     xe.u.u.detail = SCROLLWHEELDOWNFAKE;
 | |
|                     count = -count;
 | |
|                 }
 | |
| 
 | |
|                 for (; count; --count) {
 | |
|                     xe.u.u.type = ButtonPress;
 | |
|                     (*darwinEventQueue.pPtr->processInputProc)
 | |
|                             (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 | |
|                     xe.u.u.type = ButtonRelease;
 | |
|                     (*darwinEventQueue.pPtr->processInputProc)
 | |
|                             (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1);
 | |
|                 }
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             default:
 | |
|                 // Check for mode specific event
 | |
|                 DarwinModeProcessEvent(&xe);
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     miPointerUpdate();
 | |
| }
 |