Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

macosx_input.m (31009B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 #import <AppKit/AppKit.h>
     23 #import <Foundation/Foundation.h>
     24 #include <ApplicationServices/ApplicationServices.h>
     25 
     26 #import "../client/client.h"
     27 #import "macosx_local.h"
     28 #import "../renderer/tr_local.h"
     29 
     30 #import "Q3Controller.h"
     31 //#import "CGMouseDeltaFix.h"
     32 #import "macosx_timers.h"
     33 #import "macosx_display.h" // For Sys_SetScreenFade
     34 
     35 #import <drivers/event_status_driver.h>
     36 #import <sys/types.h>
     37 #import <sys/time.h>
     38 #import <unistd.h>
     39 
     40 
     41 static qboolean inputActive;
     42 
     43 static NSDate *distantPast;
     44 
     45 static cvar_t *in_nomouse;
     46 static cvar_t *in_showevents;
     47 static cvar_t *in_mouseLowEndSlope;
     48 static cvar_t *in_mouseHighEndCutoff;
     49 static cvar_t *in_disableOSMouseScaling;
     50 
     51 static void Sys_StartMouseInput();
     52 static void Sys_StopMouseInput();
     53 static qboolean mouseactive = qfalse;
     54 static BOOL inputRectValid = NO;
     55 static CGRect inputRect;
     56 static NXMouseScaling originalScaling;
     57 
     58 static unsigned int currentModifierFlags;
     59 
     60 
     61 
     62 static void Sys_PreventMouseMovement(CGPoint point)
     63 {
     64     CGEventErr err;
     65 
     66     //Com_Printf("**** Calling CGAssociateMouseAndMouseCursorPosition(false)\n");
     67     err = CGAssociateMouseAndMouseCursorPosition(false);
     68     if (err != CGEventNoErr) {
     69         Sys_Error("Could not disable mouse movement, CGAssociateMouseAndMouseCursorPosition returned %d\n", err);
     70     }
     71 
     72     // Put the mouse in the position we want to leave it at
     73     err = CGWarpMouseCursorPosition(point);
     74     if (err != CGEventNoErr) {
     75         Sys_Error("Could not disable mouse movement, CGWarpMouseCursorPosition returned %d\n", err);
     76     }
     77 }
     78 
     79 static void Sys_ReenableMouseMovement()
     80 {
     81     CGEventErr err;
     82     
     83     //Com_Printf("**** Calling CGAssociateMouseAndMouseCursorPosition(true)\n");
     84     
     85     err = CGAssociateMouseAndMouseCursorPosition(true);
     86     if (err != CGEventNoErr) {
     87         Sys_Error("Could not reenable mouse movement, CGAssociateMouseAndMouseCursorPosition returned %d\n", err);
     88     }
     89     
     90     // Leave the mouse where it was -- don't warp here.
     91 }
     92 
     93 
     94 void Sys_InitInput(void)
     95 {
     96     // no input with dedicated servers
     97     if ( com_dedicated->integer ) {
     98             return;
     99     }
    100 	
    101     // The Cvars don't seem to work really early.
    102     [(Q3Controller *)[NSApp delegate] showBanner];
    103 
    104     Com_Printf( "------- Input Initialization -------\n" );
    105 
    106     if (!distantPast)
    107         distantPast = [[NSDate distantPast] retain];
    108 
    109     // For hide support.  If we don't do this, then the command key will get stuck on when we hide (since we won't get the flags changed event when it goes up).
    110     currentModifierFlags = 0;
    111     
    112     r_fullscreen = Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE | CVAR_LATCH );
    113     in_nomouse = Cvar_Get( "in_nomouse", "0", 0 );
    114     in_showevents = Cvar_Get( "in_showevents", "0", 0 );
    115 
    116     // these defaults were arrived at via emprical testing between a Windows box and a Mac OS X box
    117 #define ACT_LIKE_WINDOWS
    118 #ifdef ACT_LIKE_WINDOWS
    119     in_mouseLowEndSlope = Cvar_Get("in_mouseLowEndSlope", "3.5", CVAR_ARCHIVE);
    120     if (in_mouseLowEndSlope->value < 1) {
    121         Cvar_Set("in_mouseLowEndSlope", "1");
    122     }
    123 #else
    124     in_mouseLowEndSlope = Cvar_Get("in_mouseLowEndSlope", "1", CVAR_ARCHIVE);
    125     if (in_mouseLowEndSlope->value < 1) {
    126         Cvar_Set("in_mouseLowEndSlope", "1");
    127     }
    128 #endif
    129 
    130     in_mouseHighEndCutoff = Cvar_Get("in_mouseHighEndCutoff", "20", CVAR_ARCHIVE);
    131     if (in_mouseLowEndSlope->value < 1) {
    132         Cvar_Set("in_mouseHighEndCutoff", "1");
    133     }
    134     in_disableOSMouseScaling = Cvar_Get("in_disableOSMouseScaling", "1", CVAR_ARCHIVE );
    135     
    136     glw_state.display = Sys_DisplayToUse();
    137 
    138     inputActive = qtrue;
    139 
    140     if ( in_nomouse->integer == 0 )
    141         Sys_StartMouseInput();
    142     else
    143         Com_Printf( "  in_nomouse is set, skipping.\n" );
    144 
    145     Com_Printf( "------------------------------------\n" );
    146 }
    147 
    148 void Sys_ShutdownInput(void)
    149 {
    150     // no input with dedicated servers
    151     if ( !com_dedicated || com_dedicated->integer ) {
    152             return;
    153     }
    154 
    155     Com_Printf( "------- Input Shutdown -------\n" );
    156     if ( !inputActive ) {
    157         return;
    158     }
    159     inputActive = qfalse;
    160 
    161     if (mouseactive)
    162         Sys_StopMouseInput();
    163 
    164     Com_Printf( "------------------------------\n" );
    165 }
    166 
    167 static void Sys_LockMouseInInputRect(CGRect rect)
    168 {
    169     CGPoint center;
    170     
    171     center.x = rect.origin.x + rect.size.width / 2.0;
    172     center.y = rect.origin.y + rect.size.height / 2.0;
    173 
    174     // Now, put the mouse in the middle of the input rect (anywhere over it would do)
    175     // and don't allow it to move.  This means that the user won't be able to accidentally
    176     // select another application.
    177     Sys_PreventMouseMovement(center);
    178 }
    179 
    180 extern void Sys_UpdateWindowMouseInputRect(void);
    181 
    182 static void Sys_StartMouseInput()
    183 {
    184     NXEventHandle eventStatus;
    185     CGMouseDelta dx, dy;
    186 
    187     if (mouseactive) {
    188         //Com_Printf("**** Attempted to start mouse input while already started\n");
    189         return;
    190     }
    191 
    192     Com_Printf("Starting mouse input\n");
    193 
    194     mouseactive = qtrue;
    195     if (inputRectValid && !glConfig.isFullscreen)
    196         // Make sure that if window moved we don't hose the user...
    197         Sys_UpdateWindowMouseInputRect();
    198 
    199     Sys_LockMouseInInputRect(inputRect);
    200 
    201     // Grab any mouse delta information to reset the last delta buffer
    202     CGGetLastMouseDelta(&dx, &dy);
    203     
    204     // Turn off mouse scaling
    205     if (in_disableOSMouseScaling->integer==0 && (eventStatus = NXOpenEventStatus())) {
    206         NXMouseScaling newScaling;
    207 
    208         NXGetMouseScaling(eventStatus, &originalScaling);
    209         newScaling.numScaleLevels = 1;
    210         newScaling.scaleThresholds[0] = 1;
    211         newScaling.scaleFactors[0] = -1;
    212         NXSetMouseScaling(eventStatus, &newScaling);
    213         NXCloseEventStatus(eventStatus);
    214     }
    215     
    216     [NSCursor hide];
    217 }
    218 
    219 static void Sys_StopMouseInput()
    220 {
    221     NXEventHandle eventStatus;
    222     if (!mouseactive) {
    223         //Com_Printf("**** Attempted to stop mouse input while already stopped\n");
    224         return;
    225     }
    226     
    227     Com_Printf("Stopping mouse input\n");
    228     
    229     // Restore mouse scaling
    230     if (in_disableOSMouseScaling->integer == 0 && (eventStatus = NXOpenEventStatus())) {
    231         NXSetMouseScaling(eventStatus, &originalScaling);
    232         NXCloseEventStatus(eventStatus);
    233     }
    234 
    235     mouseactive = qfalse;
    236     Sys_ReenableMouseMovement();
    237 
    238     [NSCursor unhide];
    239 }
    240 
    241 //===========================================================================
    242 
    243 #include <sys/types.h>
    244 #include <sys/time.h>
    245 #include <unistd.h>
    246 
    247 static char *Sys_ConsoleInput(void)
    248 {
    249     extern qboolean stdin_active;
    250     static char text[256];
    251     int     len;
    252     fd_set	fdset;
    253     struct timeval timeout;
    254 
    255     if (!com_dedicated || !com_dedicated->integer)
    256         return NULL;
    257     
    258     if (!stdin_active)
    259         return NULL;
    260     
    261     FD_ZERO(&fdset);
    262     FD_SET(fileno(stdin), &fdset);
    263     timeout.tv_sec = 0;
    264     timeout.tv_usec = 0;
    265     if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(fileno(stdin), &fdset))
    266         return NULL;
    267 
    268     len = read (fileno(stdin), text, sizeof(text));
    269     if (len == 0) { // eof!
    270         stdin_active = qfalse;
    271         return NULL;
    272     }
    273 
    274     if (len < 1)
    275         return NULL;
    276     text[len-1] = 0;    // rip off the /n and terminate
    277 
    278     return text;
    279 }
    280 
    281 //===========================================================================
    282 // Mouse input
    283 //===========================================================================
    284 
    285 #define MAX_DISPLAYS 128
    286 
    287 CGDirectDisplayID Sys_DisplayToUse(void)
    288 {
    289     static BOOL gotDisplay =  NO;
    290     static CGDirectDisplayID displayToUse;
    291     
    292     cvar_t   *vid_screen;
    293     CGDisplayErr err;
    294     CGDirectDisplayID displays[MAX_DISPLAYS];
    295     CGDisplayCount displayCount;
    296     int displayIndex;
    297     
    298     if (gotDisplay)
    299         return displayToUse;
    300     gotDisplay = YES;    
    301     
    302     err = CGGetActiveDisplayList(MAX_DISPLAYS, displays, &displayCount);
    303     if (err != CGDisplayNoErr)
    304         Sys_Error("Cannot get display list -- CGGetActiveDisplayList returned %d.\n", err);
    305 
    306     // -1, the default, means to use the main screen
    307     if ((vid_screen = Cvar_Get("vid_screen", "-1", CVAR_ARCHIVE)))
    308         displayIndex = vid_screen->integer;
    309     else
    310         displayIndex = -1;
    311         
    312     if (displayIndex < 0 || displayIndex >= displayCount)
    313         // This is documented (in CGDirectDisplay.h) to be the main display.  We want to
    314         // return this instead of kCGDirectMainDisplay since this will allow us to compare
    315         // display IDs.
    316         displayToUse = displays[0];
    317     else
    318         displayToUse = displays[displayIndex];
    319 
    320     return displayToUse;
    321 }
    322 
    323 void Sys_SetMouseInputRect(CGRect newRect)
    324 {
    325     inputRectValid = YES;
    326     inputRect = newRect;
    327     //Com_Printf("**** inputRect = (%f, %f, %f, %f)\n", newRect.origin.x, newRect.origin.y, newRect.size.width, newRect.size.height);
    328     
    329     if (mouseactive)
    330         Sys_LockMouseInInputRect(inputRect);
    331 }
    332 
    333 
    334 static void Sys_ProcessMouseMovedEvent(NSEvent *mouseMovedEvent, int currentTime)
    335 {
    336     float dx, dy;
    337     
    338     if (!mouseactive)
    339         return;
    340         
    341     dx = [mouseMovedEvent deltaX];
    342     dy = [mouseMovedEvent deltaY];
    343     
    344     if (in_showevents->integer)
    345         Com_Printf("MOUSE MOVED: %d, %d\n", dx, dy);
    346 
    347     Sys_QueEvent(currentTime, SE_MOUSE, dx, dy, 0, NULL );
    348 }
    349 
    350 // If we are 'paused' (i.e., in any state that our normal key bindings aren't in effect), then interpret cmd-h and cmd-tab as hiding the application.
    351 static qboolean maybeHide()
    352 {
    353     if ((currentModifierFlags & NSCommandKeyMask) == 0)
    354         return qfalse;
    355 
    356     return Sys_Hide();
    357 }
    358 
    359 static inline void sendEventForCharacter(NSEvent *event, unichar character, qboolean keyDownFlag, int currentTime)
    360 {
    361     if (in_showevents->integer)
    362         Com_Printf("CHARACTER: 0x%02x down=%d\n", character, keyDownFlag);
    363         
    364 #ifdef OMNI_TIMER
    365     if (character == NSF9FunctionKey && !keyDownFlag) {
    366         // Log and reset the root timer.  We should currently only have the root on the stack.
    367         OTStackPopRoot();
    368         OTStackReportResults(NULL);
    369         OTStackReset();
    370         OTStackPushRoot(rootNode);
    371     }
    372 #endif
    373 
    374     switch (character) {
    375         case 0x03:
    376             Sys_QueEvent(currentTime, SE_KEY, K_KP_ENTER, keyDownFlag, 0, NULL);
    377             break;
    378         case '\b':
    379         case '\177':
    380             Sys_QueEvent(currentTime, SE_KEY, K_BACKSPACE, keyDownFlag, 0, NULL);
    381             if (keyDownFlag) {
    382                Sys_QueEvent(currentTime, SE_CHAR, '\b', 0, 0, NULL);
    383             }
    384             break;
    385         case '\t':
    386             if (maybeHide())
    387                 return;
    388             Sys_QueEvent(currentTime, SE_KEY, K_TAB, keyDownFlag, 0, NULL);
    389             if (keyDownFlag) {
    390                 Sys_QueEvent(currentTime, SE_CHAR, '\t', 0, 0, NULL);
    391             }
    392             break;
    393         case '\r':
    394         case '\n':
    395             Sys_QueEvent(currentTime, SE_KEY, K_ENTER, keyDownFlag, 0, NULL);
    396             if (keyDownFlag) {
    397                 Sys_QueEvent(currentTime, SE_CHAR, '\r', 0, 0, NULL);
    398             }
    399             break;
    400         case '\033':
    401             Sys_QueEvent(currentTime, SE_KEY, K_ESCAPE, keyDownFlag, 0, NULL);
    402             break;
    403         case ' ':
    404             Sys_QueEvent(currentTime, SE_KEY, K_SPACE, keyDownFlag, 0, NULL);
    405             if (keyDownFlag) {
    406                 Sys_QueEvent(currentTime, SE_CHAR, ' ', 0, 0, NULL);
    407             }
    408             break;
    409         case NSUpArrowFunctionKey:
    410             Sys_QueEvent(currentTime, SE_KEY, K_UPARROW, keyDownFlag, 0, NULL);
    411             break;
    412         case NSDownArrowFunctionKey:
    413             Sys_QueEvent(currentTime, SE_KEY, K_DOWNARROW, keyDownFlag, 0, NULL);
    414             break;
    415         case NSLeftArrowFunctionKey:
    416             Sys_QueEvent(currentTime, SE_KEY, K_LEFTARROW, keyDownFlag, 0, NULL);
    417             break;
    418         case NSRightArrowFunctionKey:
    419             Sys_QueEvent(currentTime, SE_KEY, K_RIGHTARROW, keyDownFlag, 0, NULL);
    420             break;
    421         case NSF1FunctionKey:
    422             Sys_QueEvent(currentTime, SE_KEY, K_F1, keyDownFlag, 0, NULL);
    423             break;
    424         case NSF2FunctionKey:
    425             Sys_QueEvent(currentTime, SE_KEY, K_F2, keyDownFlag, 0, NULL);
    426             break;
    427         case NSF3FunctionKey:
    428             Sys_QueEvent(currentTime, SE_KEY, K_F3, keyDownFlag, 0, NULL);
    429             break;
    430         case NSF4FunctionKey:
    431             Sys_QueEvent(currentTime, SE_KEY, K_F4, keyDownFlag, 0, NULL);
    432             break;
    433         case NSF5FunctionKey:
    434             Sys_QueEvent(currentTime, SE_KEY, K_F5, keyDownFlag, 0, NULL);
    435             break;
    436         case NSF6FunctionKey:
    437             Sys_QueEvent(currentTime, SE_KEY, K_F6, keyDownFlag, 0, NULL);
    438             break;
    439         case NSF7FunctionKey:
    440             Sys_QueEvent(currentTime, SE_KEY, K_F7, keyDownFlag, 0, NULL);
    441             break;
    442         case NSF8FunctionKey:
    443             Sys_QueEvent(currentTime, SE_KEY, K_F8, keyDownFlag, 0, NULL);
    444             break;
    445         case NSF9FunctionKey:
    446             Sys_QueEvent(currentTime, SE_KEY, K_F9, keyDownFlag, 0, NULL);
    447             break;
    448         case NSF10FunctionKey:
    449             Sys_QueEvent(currentTime, SE_KEY, K_F10, keyDownFlag, 0, NULL);
    450             break;
    451         case NSF11FunctionKey:
    452             Sys_QueEvent(currentTime, SE_KEY, K_F11, keyDownFlag, 0, NULL);
    453             break;
    454         case NSF12FunctionKey:
    455             Sys_QueEvent(currentTime, SE_KEY, K_F12, keyDownFlag, 0, NULL);
    456             break;
    457         case NSF13FunctionKey:
    458             Sys_QueEvent(currentTime, SE_KEY, '`', keyDownFlag, 0, NULL);
    459             if (keyDownFlag) {
    460                 Sys_QueEvent(currentTime, SE_CHAR, '`', 0, 0, NULL);
    461             }
    462             break;
    463         case NSInsertFunctionKey:
    464             Sys_QueEvent(currentTime, SE_KEY, K_INS, keyDownFlag, 0, NULL);
    465             break;
    466         case NSDeleteFunctionKey:
    467             Sys_QueEvent(currentTime, SE_KEY, K_DEL, keyDownFlag, 0, NULL);
    468             break;
    469         case NSPageDownFunctionKey:
    470             Sys_QueEvent(currentTime, SE_KEY, K_PGDN, keyDownFlag, 0, NULL);
    471             break;
    472         case NSPageUpFunctionKey:
    473             Sys_QueEvent(currentTime, SE_KEY, K_PGUP, keyDownFlag, 0, NULL);
    474             break;
    475         case NSHomeFunctionKey:
    476             Sys_QueEvent(currentTime, SE_KEY, K_HOME, keyDownFlag, 0, NULL);
    477             break;
    478         case NSEndFunctionKey:
    479             Sys_QueEvent(currentTime, SE_KEY, K_END, keyDownFlag, 0, NULL);
    480             break;
    481         case NSPauseFunctionKey:
    482             Sys_QueEvent(currentTime, SE_KEY, K_PAUSE, keyDownFlag, 0, NULL);
    483             break;
    484         default:
    485             if ([event modifierFlags] & NSNumericPadKeyMask) {
    486                 switch (character) {
    487                     case '0':
    488                         Sys_QueEvent(currentTime, SE_KEY, K_KP_INS, keyDownFlag, 0, NULL);
    489                         break;
    490                     case '1':
    491                         Sys_QueEvent(currentTime, SE_KEY, K_KP_END, keyDownFlag, 0, NULL);
    492                         break;
    493                     case '2':
    494                         Sys_QueEvent(currentTime, SE_KEY, K_KP_DOWNARROW, keyDownFlag, 0, NULL);
    495                         break;
    496                     case '3':
    497                         Sys_QueEvent(currentTime, SE_KEY, K_KP_PGDN, keyDownFlag, 0, NULL);
    498                         break;
    499                     case '4':
    500                         Sys_QueEvent(currentTime, SE_KEY, K_KP_LEFTARROW, keyDownFlag, 0, NULL);
    501                         break;
    502                     case '5':
    503                         Sys_QueEvent(currentTime, SE_KEY, K_KP_5, keyDownFlag, 0, NULL);
    504                         break;
    505                     case '6':
    506                         Sys_QueEvent(currentTime, SE_KEY, K_KP_RIGHTARROW, keyDownFlag, 0, NULL);
    507                         break;
    508                     case '7':
    509                         Sys_QueEvent(currentTime, SE_KEY, K_KP_HOME, keyDownFlag, 0, NULL);
    510                         break;
    511                     case '8':
    512                         Sys_QueEvent(currentTime, SE_KEY, K_KP_UPARROW, keyDownFlag, 0, NULL);
    513                         break;
    514                     case '9':
    515                         Sys_QueEvent(currentTime, SE_KEY, K_KP_PGUP, keyDownFlag, 0, NULL);
    516                         break;
    517                     case '.':
    518                     case ',':
    519                         Sys_QueEvent(currentTime, SE_KEY, K_KP_DEL, keyDownFlag, 0, NULL);
    520                         break;
    521                     case '+':
    522                         Sys_QueEvent(currentTime, SE_KEY, K_KP_PLUS, keyDownFlag, 0, NULL);
    523                         break;
    524                     case '-':
    525                         Sys_QueEvent(currentTime, SE_KEY, K_KP_MINUS, keyDownFlag, 0, NULL);
    526                         break;
    527                     case '*':
    528                         Sys_QueEvent(currentTime, SE_KEY, K_KP_STAR, keyDownFlag, 0, NULL);
    529                         break;
    530                     case '/':
    531                         Sys_QueEvent(currentTime, SE_KEY, K_KP_SLASH, keyDownFlag, 0, NULL);
    532                         break;
    533                     case '=':
    534                         Sys_QueEvent(currentTime, SE_KEY, K_KP_EQUALS, keyDownFlag, 0, NULL);
    535                         break;
    536                     default:
    537                         //NSLog(@"TODO: Implement character %d", (int)character);
    538                         break;
    539                  }       
    540             } else if (character >= 'a' && character <= 'z') {
    541                 if (character == 'h') {
    542                     if (maybeHide())
    543                         return;
    544                 }
    545                 Sys_QueEvent(currentTime, SE_KEY, character, keyDownFlag, 0, NULL);
    546                 if (keyDownFlag) {
    547                     Sys_QueEvent(currentTime, SE_CHAR, (char)character, 0, 0, NULL);
    548                 }
    549             } else if (character >= 'A' && character <= 'Z') {
    550                 Sys_QueEvent(currentTime, SE_KEY, 'a' + (character - 'A'), keyDownFlag, 0, NULL);
    551                 if (keyDownFlag) {
    552                     Sys_QueEvent(currentTime, SE_CHAR, character, 0, 0, NULL);
    553                 }
    554             } else if (character >= 32 && character < 127) {
    555                 Sys_QueEvent(currentTime, SE_KEY, character, keyDownFlag, 0, NULL);
    556                 if (keyDownFlag) {
    557                     Sys_QueEvent(currentTime, SE_CHAR, (char)character, 0, 0, NULL);
    558                 }
    559             } else {
    560                 //NSLog(@"TODO: Implement character %d", (int)character);
    561             }
    562             break;
    563     }
    564 }
    565 
    566 static inline void processKeyEvent(NSEvent *keyEvent, qboolean keyDownFlag, int currentTime)
    567 {
    568     NSEventType eventType;
    569     NSString *characters;
    570     unsigned int characterIndex, characterCount;
    571 
    572     eventType = [keyEvent type];
    573     characters = [keyEvent charactersIgnoringModifiers];
    574     characterCount = [characters length];
    575 
    576     for (characterIndex = 0; characterIndex < characterCount; characterIndex++) {
    577         sendEventForCharacter(keyEvent, [characters characterAtIndex:characterIndex], keyDownFlag, currentTime);
    578     }
    579 }
    580 
    581 static inline void sendEventForMaskChangeInFlags(int quakeKey, unsigned int modifierMask, unsigned int newModifierFlags, int currentTime)
    582 {
    583     BOOL oldHadModifier, newHasModifier;
    584 
    585     oldHadModifier = (currentModifierFlags & modifierMask) != 0;
    586     newHasModifier = (newModifierFlags & modifierMask) != 0;
    587     if (oldHadModifier != newHasModifier) {
    588         // NSLog(@"Key %d posted for modifier mask modifierMask", quakeKey);
    589         Sys_QueEvent(currentTime, SE_KEY, quakeKey, newHasModifier, 0, NULL);
    590     }
    591 }
    592 
    593 static inline void processFlagsChangedEvent(NSEvent *flagsChangedEvent, int currentTime)
    594 {
    595     int newModifierFlags;
    596 
    597     newModifierFlags = [flagsChangedEvent modifierFlags];
    598     sendEventForMaskChangeInFlags(K_COMMAND, NSCommandKeyMask, newModifierFlags, currentTime);
    599     sendEventForMaskChangeInFlags(K_CAPSLOCK, NSAlphaShiftKeyMask, newModifierFlags, currentTime);
    600     sendEventForMaskChangeInFlags(K_ALT, NSAlternateKeyMask, newModifierFlags, currentTime);
    601     sendEventForMaskChangeInFlags(K_CTRL, NSControlKeyMask, newModifierFlags, currentTime);
    602     sendEventForMaskChangeInFlags(K_SHIFT, NSShiftKeyMask, newModifierFlags, currentTime);
    603     currentModifierFlags = newModifierFlags;
    604 }
    605 
    606 static inline void processSystemDefinedEvent(NSEvent *systemDefinedEvent, int currentTime)
    607 {
    608     static int oldButtons = 0;
    609     int buttonsDelta;
    610     int buttons;
    611     int isDown;
    612     
    613     if ([systemDefinedEvent subtype] == 7) {
    614 
    615         if (!mouseactive)
    616             return;
    617         
    618     
    619 	buttons = [systemDefinedEvent data2];
    620         buttonsDelta = oldButtons ^ buttons;
    621         
    622         //Com_Printf("uberbuttons: %08lx %08lx\n",buttonsDelta,buttons);
    623 
    624 
    625 	if (buttonsDelta & 1) {
    626             isDown = buttons & 1;
    627             Sys_QueEvent(currentTime, SE_KEY, K_MOUSE1, isDown, 0, NULL);
    628             if (in_showevents->integer) {
    629                 Com_Printf("MOUSE2: %s\n", isDown ? "down" : "up");
    630             }
    631 	}
    632 
    633 	if (buttonsDelta & 2) {
    634             isDown = buttons & 2;
    635             Sys_QueEvent(currentTime, SE_KEY, K_MOUSE2, isDown, 0, NULL);
    636             if (in_showevents->integer) {
    637                 Com_Printf("MOUSE3: %s\n", isDown ? "down" : "up");
    638             }
    639 	}
    640 
    641 	if (buttonsDelta & 4) {
    642             isDown = buttons & 4;
    643             Sys_QueEvent(currentTime, SE_KEY, K_MOUSE3, isDown, 0, NULL);
    644             if (in_showevents->integer) {
    645                 Com_Printf("MOUSE1: %s\n", isDown ? "down" : "up");
    646             }
    647 	}
    648 
    649 	if (buttonsDelta & 8) {
    650             isDown = buttons & 8;
    651             Sys_QueEvent(currentTime, SE_KEY, K_MOUSE4, isDown, 0, NULL);
    652             if (in_showevents->integer) {
    653                 Com_Printf("MOUSE4: %s\n", isDown ? "down" : "up");
    654             }
    655         }
    656         
    657 	if (buttonsDelta & 16) {
    658             isDown = buttons & 16;
    659             Sys_QueEvent(currentTime, SE_KEY, K_MOUSE5, isDown, 0, NULL);
    660             if (in_showevents->integer) {
    661                 Com_Printf("MOUSE5: %s\n", isDown ? "down" : "up");
    662             }
    663 	}
    664         
    665         oldButtons = buttons;
    666     }
    667 }
    668 
    669 static inline void processEvent(NSEvent *event, int currentTime)
    670 {
    671     NSEventType eventType;
    672 
    673     if (!inputActive)
    674         return;
    675 
    676     eventType = [event type];
    677 
    678     if (in_showevents->integer)
    679         NSLog(@"event = %@", event);
    680     
    681     switch (eventType) {
    682         // These six event types are ignored since we do all of our mouse down/up process via the uber-mouse system defined event.  We have to accept these events however since they get enqueued and the queue will fill up if we don't.
    683         case NSLeftMouseDown:
    684             //Sys_QueEvent(currentTime, SE_KEY, K_MOUSE1, qtrue, 0, NULL);
    685             return;
    686         case NSLeftMouseUp:
    687             //Sys_QueEvent(currentTime, SE_KEY, K_MOUSE1, qfalse, 0, NULL);
    688             return;
    689         case NSRightMouseDown:
    690             //Sys_QueEvent(currentTime, SE_KEY, K_MOUSE2, qtrue, 0, NULL);
    691             return;
    692         case NSRightMouseUp:
    693             //Sys_QueEvent(currentTime, SE_KEY, K_MOUSE2, qfalse, 0, NULL);
    694             return;
    695         case 25: // other mouse down
    696             return;
    697         case 26: // other mouse up
    698             return;
    699             
    700         case NSMouseMoved:
    701         case NSLeftMouseDragged:
    702         case NSRightMouseDragged:
    703         case 27: // other mouse dragged
    704             Sys_ProcessMouseMovedEvent(event, currentTime);
    705             return;
    706         case NSKeyDown:
    707         case NSKeyUp:
    708             processKeyEvent(event, eventType == NSKeyDown, currentTime);
    709             return;
    710         case NSFlagsChanged:
    711             processFlagsChangedEvent(event, currentTime);
    712             return;
    713 	case NSSystemDefined:
    714 	    processSystemDefinedEvent(event, currentTime);
    715 	    return;
    716         case NSScrollWheel:
    717             if ([event deltaY] < 0.0) {
    718                 Sys_QueEvent(currentTime, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL );
    719                 Sys_QueEvent(currentTime, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL );
    720             } else {
    721                 Sys_QueEvent(currentTime, SE_KEY, K_MWHEELUP, qtrue, 0, NULL );
    722                 Sys_QueEvent(currentTime, SE_KEY, K_MWHEELUP, qfalse, 0, NULL );
    723             }
    724             return;
    725         default:
    726             break;
    727     }
    728     [NSApp sendEvent:event];
    729 }
    730 
    731 static void Sys_SendKeyEvents(int currentTime)
    732 {
    733 #ifndef DEDICATED
    734     NSEvent *event;
    735     NSDate *timeout;
    736     extern float SNDDMA_GetBufferDuration();
    737     
    738     timeout = distantPast;
    739     if (Sys_IsHidden)
    740         timeout = [NSDate dateWithTimeIntervalSinceNow: 0.25 * SNDDMA_GetBufferDuration()];
    741     
    742     // This gets call regardless of whether inputActive is true or not.  This is important since we need to be poking the event queue in order for the unhide event to make its way through the system.  This means that when we hide, we can just shut down the input system and reeanbled it when we unhide.
    743     while ((event = [NSApp nextEventMatchingMask: NSAnyEventMask
    744                                        untilDate: timeout
    745                                           inMode: NSDefaultRunLoopMode
    746                                          dequeue:YES])) {
    747             if (Sys_IsHidden) {
    748                 // Just let NSApp handle events so that we'll get the app activation event
    749                 [NSApp sendEvent: event];
    750                 timeout = [NSDate dateWithTimeIntervalSinceNow: 0.1];
    751             } else {
    752                 static int lastEventTime = 0;
    753                 static BOOL lastEventTimeValid = NO;
    754 
    755                 // Mac OS X 10.0.3 has a bug where the if the monitor goes to sleep in fullscreen GL mode, the gamma won't be restored.  We'll restore the gamma if there is a pause while in the game of more than 10 seconds.  We don't do this on the 'Sys_IsHidden' branch since unhiding will restore the monitor gamma.
    756                 if ((currentTime - lastEventTime > 1 * 1000) && lastEventTimeValid) {
    757                     //Com_Printf("Restoring monitor gamma after being idle for %f seconds.\n", (currentTime - lastEventTime) / 1000.0);
    758                     [NSCursor hide];
    759                     Sys_SetScreenFade(&glw_state.inGameTable, 1.0);
    760                 }
    761                 lastEventTime = [event timestamp] * 1000.0;	//currentTime;
    762                 lastEventTimeValid = YES;
    763                 
    764                 processEvent(event, lastEventTime);
    765             }
    766     }
    767 #endif
    768 }
    769 
    770 /*
    771 ========================================================================
    772 
    773 EVENT LOOP
    774 
    775 ========================================================================
    776 */
    777 
    778 extern qboolean	Sys_GetPacket ( netadr_t *net_from, msg_t *net_message );
    779 
    780 #define	MAX_QUED_EVENTS		256
    781 #define	MASK_QUED_EVENTS	( MAX_QUED_EVENTS - 1 )
    782 
    783 static sysEvent_t	eventQue[MAX_QUED_EVENTS];
    784 static int              eventHead, eventTail;
    785 static byte		sys_packetReceived[MAX_MSGLEN];
    786 
    787 /*
    788 ================
    789 Sys_QueEvent
    790 
    791 A time of 0 will get the current time
    792 Ptr should either be null, or point to a block of data that can
    793 be freed by the game later.
    794 ================
    795 */
    796 void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ) {
    797 	sysEvent_t	*ev;
    798         int	i,j;
    799 #ifndef DEDICATED
    800     if (in_showevents->integer)
    801         NSLog(@"EVENT ENQUEUE:  time=%d type=%d value=0x%08x value2=0x%08x\n", time, type, value, value2);
    802 #endif
    803 
    804 	if ( eventHead - eventTail >= MAX_QUED_EVENTS ) {
    805 		Com_Printf("Sys_QueEvent: overflow\n");
    806 	}
    807 
    808 	if ( !time ) {
    809 		time = Sys_Milliseconds();
    810 	}
    811 
    812 	// insert it by time
    813 	for ( i = eventTail ; i < eventHead ; i++ ) {
    814 		ev = &eventQue[ i & MASK_QUED_EVENTS ];
    815 		if ( ev->evTime > time ) {
    816 			break;
    817 		}
    818 	}
    819 
    820 	// insert before i
    821 	for ( j = eventHead ; j > i ; j-- ) {
    822 		eventQue[ j & MASK_QUED_EVENTS ] = eventQue[ (j-1) & MASK_QUED_EVENTS ];
    823 	}
    824 	ev = &eventQue[ i & MASK_QUED_EVENTS ];
    825 
    826 	eventHead++;
    827 
    828 	ev->evTime = time;
    829 	ev->evType = type;
    830 	ev->evValue = value;
    831 	ev->evValue2 = value2;
    832 	ev->evPtrLength = ptrLength;
    833 	ev->evPtr = ptr;
    834 }
    835 
    836 /*
    837 ================
    838 Sys_GetEvent
    839 
    840 ================
    841 */
    842 sysEvent_t Sys_GetEvent( void )
    843 {
    844     sysEvent_t	ev;
    845     char       *s;
    846     msg_t       netmsg;
    847     netadr_t	adr;
    848     int         currentTime;
    849     
    850     // return if we have data
    851     if (eventHead > eventTail) {
    852         eventTail++;
    853         return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
    854     }
    855 
    856     // The queue must be empty.  Check all of the event sources.  If the events are
    857     // already in the queue, we can't imply any real ordering, so we'll avoid extra
    858     // system calls and give them all the same time.
    859     currentTime = Sys_Milliseconds();
    860 
    861     // Check for mouse and keyboard events
    862     Sys_SendKeyEvents(currentTime);
    863 
    864     // check for console commands
    865     s = Sys_ConsoleInput();
    866     if ( s ) {
    867         char	*b;
    868         int		len;
    869     
    870         len = strlen( s ) + 1;
    871         b = Z_Malloc( len );
    872         strcpy( b, s );
    873         Sys_QueEvent( currentTime, SE_CONSOLE, 0, 0, len, b );
    874     }
    875     
    876 
    877     // During debugging it is sometimes usefull to be able to start/stop mouse input.
    878     // Don't turn on the input when we've disabled it because we're hidden, however.
    879     if (!com_dedicated->integer) {
    880         if (in_nomouse->integer == mouseactive && !Sys_IsHidden) {
    881             if (in_nomouse->integer)
    882                 Sys_StopMouseInput();
    883             else
    884                 Sys_StartMouseInput();
    885         }
    886     }
    887     
    888     // check for network packets
    889     MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) );
    890     if ( Sys_GetPacket ( &adr, &netmsg ) ) {
    891         netadr_t		*buf;
    892         int				len;
    893     
    894         // copy out to a seperate buffer for qeueing
    895         len = sizeof( netadr_t ) + netmsg.cursize;
    896         buf = Z_Malloc( len );
    897         *buf = adr;
    898         memcpy( buf+1, netmsg.data, netmsg.cursize );
    899         Sys_QueEvent( currentTime, SE_PACKET, 0, 0, len, buf );
    900     }
    901 
    902     // If we got an event, return it
    903     if (eventHead > eventTail) {
    904         eventTail++;
    905         return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
    906     }
    907     
    908     // Otherwise, return an empty event to indicate that there are no events pending.
    909     memset( &ev, 0, sizeof( ev ) );
    910     ev.evTime = currentTime;
    911 
    912     return ev;
    913 }
    914 
    915 
    916