view src/video/quartz/SDL_QuartzEvents.m @ 79:ffadd05de74d

Allow the user to override the relative mouse mode. They almost never want to do this, as it seriously affects applications that rely on continuous relative mouse motion.
author Sam Lantinga <slouken@lokigames.com>
date Sat, 23 Jun 2001 22:00:59 +0000
parents 45b1c4303f87
children aac75d5f7869
line wrap: on
line source

/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997, 1998, 1999, 2000, 2001  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@devolution.com
*/

#include "SDL_QuartzKeys.h"

static void  QZ_InitOSKeymap (_THIS) {
	int i;

	for ( i=0; i<SDL_TABLESIZE(keymap); ++i )
		keymap[i] = SDLK_UNKNOWN;

	// This keymap is almost exactly the same as the OS 9 one
        keymap[QZ_ESCAPE] = SDLK_ESCAPE;
	keymap[QZ_F1] = SDLK_F1;
	keymap[QZ_F2] = SDLK_F2;
	keymap[QZ_F3] = SDLK_F3;
	keymap[QZ_F4] = SDLK_F4;
	keymap[QZ_F5] = SDLK_F5;
	keymap[QZ_F6] = SDLK_F6;
	keymap[QZ_F7] = SDLK_F7;
	keymap[QZ_F8] = SDLK_F8;
	keymap[QZ_F9] = SDLK_F9;
	keymap[QZ_F10] = SDLK_F10;
	keymap[QZ_F11] = SDLK_F11;
	keymap[QZ_F12] = SDLK_F12;
	keymap[QZ_PRINT] = SDLK_PRINT;
	keymap[QZ_SCROLLOCK] = SDLK_SCROLLOCK;
	keymap[QZ_PAUSE] = SDLK_PAUSE;
	keymap[QZ_POWER] = SDLK_POWER;
	keymap[QZ_BACKQUOTE] = SDLK_BACKQUOTE;
	keymap[QZ_1] = SDLK_1;
	keymap[QZ_2] = SDLK_2;
	keymap[QZ_3] = SDLK_3;
	keymap[QZ_4] = SDLK_4;
	keymap[QZ_5] = SDLK_5;
	keymap[QZ_6] = SDLK_6;
	keymap[QZ_7] = SDLK_7;
	keymap[QZ_8] = SDLK_8;
	keymap[QZ_9] = SDLK_9;
	keymap[QZ_0] = SDLK_0;
	keymap[QZ_MINUS] = SDLK_MINUS;
	keymap[QZ_EQUALS] = SDLK_EQUALS;
	keymap[QZ_BACKSPACE] = SDLK_BACKSPACE;
	keymap[QZ_INSERT] = SDLK_INSERT;
	keymap[QZ_HOME] = SDLK_HOME;
	keymap[QZ_PAGEUP] = SDLK_PAGEUP;
	keymap[QZ_NUMLOCK] = SDLK_NUMLOCK;
	keymap[QZ_KP_EQUALS] = SDLK_KP_EQUALS;
	keymap[QZ_KP_DIVIDE] = SDLK_KP_DIVIDE;
	keymap[QZ_KP_MULTIPLY] = SDLK_KP_MULTIPLY;
	keymap[QZ_TAB] = SDLK_TAB;
	keymap[QZ_q] = SDLK_q;
	keymap[QZ_w] = SDLK_w;
	keymap[QZ_e] = SDLK_e;
	keymap[QZ_r] = SDLK_r;
	keymap[QZ_t] = SDLK_t;
	keymap[QZ_y] = SDLK_y;
	keymap[QZ_u] = SDLK_u;
	keymap[QZ_i] = SDLK_i;
	keymap[QZ_o] = SDLK_o;
	keymap[QZ_p] = SDLK_p;
	keymap[QZ_LEFTBRACKET] = SDLK_LEFTBRACKET;
	keymap[QZ_RIGHTBRACKET] = SDLK_RIGHTBRACKET;
	keymap[QZ_BACKSLASH] = SDLK_BACKSLASH;
	keymap[QZ_DELETE] = SDLK_DELETE;
	keymap[QZ_END] = SDLK_END;
	keymap[QZ_PAGEDOWN] = SDLK_PAGEDOWN;
	keymap[QZ_KP7] = SDLK_KP7;
	keymap[QZ_KP8] = SDLK_KP8;
	keymap[QZ_KP9] = SDLK_KP9;
	keymap[QZ_KP_MINUS] = SDLK_KP_MINUS;
	keymap[QZ_CAPSLOCK] = SDLK_CAPSLOCK;
	keymap[QZ_a] = SDLK_a;
	keymap[QZ_s] = SDLK_s;
	keymap[QZ_d] = SDLK_d;
	keymap[QZ_f] = SDLK_f;
	keymap[QZ_g] = SDLK_g;
	keymap[QZ_h] = SDLK_h;
	keymap[QZ_j] = SDLK_j;
	keymap[QZ_k] = SDLK_k;
	keymap[QZ_l] = SDLK_l;
	keymap[QZ_SEMICOLON] = SDLK_SEMICOLON;
	keymap[QZ_QUOTE] = SDLK_QUOTE;
	keymap[QZ_RETURN] = SDLK_RETURN;
	keymap[QZ_KP4] = SDLK_KP4;
	keymap[QZ_KP5] = SDLK_KP5;
	keymap[QZ_KP6] = SDLK_KP6;
	keymap[QZ_KP_PLUS] = SDLK_KP_PLUS;
	keymap[QZ_LSHIFT] = SDLK_LSHIFT;
	keymap[QZ_z] = SDLK_z;
	keymap[QZ_x] = SDLK_x;
	keymap[QZ_c] = SDLK_c;
	keymap[QZ_v] = SDLK_v;
	keymap[QZ_b] = SDLK_b;
	keymap[QZ_n] = SDLK_n;
	keymap[QZ_m] = SDLK_m;
	keymap[QZ_COMMA] = SDLK_COMMA;
	keymap[QZ_PERIOD] = SDLK_PERIOD;
	keymap[QZ_SLASH] = SDLK_SLASH;
	keymap[QZ_UP] = SDLK_UP;
	keymap[QZ_KP1] = SDLK_KP1;
	keymap[QZ_KP2] = SDLK_KP2;
	keymap[QZ_KP3] = SDLK_KP3;
	keymap[QZ_KP_ENTER] = SDLK_KP_ENTER;
	keymap[QZ_LCTRL] = SDLK_LCTRL;
	keymap[QZ_LALT] = SDLK_LALT;
	keymap[QZ_LMETA] = SDLK_LMETA;
	keymap[QZ_SPACE] = SDLK_SPACE;
	keymap[QZ_LEFT] = SDLK_LEFT;
	keymap[QZ_DOWN] = SDLK_DOWN;
	keymap[QZ_RIGHT] = SDLK_RIGHT;
	keymap[QZ_KP0] = SDLK_KP0;
	keymap[QZ_KP_PERIOD] = SDLK_KP_PERIOD;
	keymap[QZ_IBOOK_ENTER] = SDLK_KP_ENTER;
	keymap[QZ_IBOOK_RIGHT] = SDLK_RIGHT;
	keymap[QZ_IBOOK_DOWN] = SDLK_DOWN;
	keymap[QZ_IBOOK_UP]   = SDLK_UP;
	keymap[QZ_IBOOK_LEFT] = SDLK_LEFT;
}

static void QZ_DoKey (int state, NSEvent *event) {

        NSString *chars;
        int i;
        SDL_keysym key;
        
        /* An event can contain multiple characters */
        /* I'll ignore this fact for now, since there is only one virtual key code per event */
        chars = [ event characters ];
        for (i =0; i < 1 /*[ chars length ] */; i++) {
                    
            key.scancode = [ event keyCode ];
            key.sym      = keymap [ key.scancode ];
            key.unicode  = [ chars characterAtIndex:i];
            key.mod      = KMOD_NONE;
                        
            SDL_PrivateKeyboard (state, &key);
        }
}

static void QZ_DoModifiers (unsigned int newMods) {

    const int offset = 18;
    const int mapping[] = { SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, 0, SDLK_LMETA } ;

    int bit;
    SDL_keysym key;
    key.scancode = 0;
    key.sym      = SDLK_UNKNOWN;
    key.unicode  = 0;
    key.mod      = KMOD_NONE;
    
    /* Iterate through the bits, testing each against the current modifiers */
    for (bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1) {
    
        unsigned int currentMask, newMask;
        
        currentMask = currentMods & bit;
        newMask     = newMods & bit;
        
        if ( currentMask && 
             currentMask != newMask ) {  /* modifier up event */

            key.sym = mapping[ currentMask >> offset ];
            SDL_PrivateKeyboard (SDL_RELEASED, &key);
        }
        else
        if ( newMask &&
             currentMask != newMask ) {  /* modifier down event */
         
            key.sym = mapping [ newMask >> offset ];
            SDL_PrivateKeyboard (SDL_PRESSED, &key);
        }
    }
    
    currentMods = newMods;
}

static void QZ_DoActivate (_THIS, NSPoint p) {
    
    inForeground = YES;

    /* Regrab the mouse */
    if (currentGrabMode == SDL_GRAB_ON) {
        QZ_WarpWMCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2);
        CGAssociateMouseAndMouseCursorPosition (0);
    }
    
    SDL_PrivateAppActive (1, SDL_APPINPUTFOCUS);
}

static void QZ_DoDeactivate (_THIS) {
    
    inForeground = NO;

    /* Ungrab mouse if it is grabbed */
    if (currentGrabMode == SDL_GRAB_ON) {
        CGAssociateMouseAndMouseCursorPosition (1);
    }
    
    SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS);
}

static void QZ_PumpEvents (_THIS) { 

    NSDate *distantPast = [ NSDate distantPast ];
    
    //NSAutoreleasePool *pool;
    //pool = [ [ NSAutoreleasePool alloc ] init ];
    
    NSEvent *event;
    NSRect winRect;
    NSRect titleBarRect;
            
    winRect = NSMakeRect (0, 0, SDL_VideoSurface->w + 1, SDL_VideoSurface->h + 1);
    titleBarRect = NSMakeRect ( 0, SDL_VideoSurface->h, SDL_VideoSurface->w,
        SDL_VideoSurface->h + 22 );
            
    do {
    
        /* Poll for an event. This will not block */
        event = [ NSApp nextEventMatchingMask:NSAnyEventMask
                    untilDate:distantPast
                    inMode: NSDefaultRunLoopMode dequeue:YES ];
    
        if (event != nil) {
            unsigned int type;
            NSPoint p;
            
            type = [ event type ];
            p = [ event locationInWindow ];
            
            #define DO_MOUSE_DOWN(button, sendToWindow)                                                \
                if ( inForeground ) {                                                                  \
                    if ( NSPointInRect(p,winRect))                                                     \
                        SDL_PrivateMouseButton (SDL_PRESSED, button, p.x, SDL_VideoSurface->h - p.y);  \
                    else if (sendToWindow)                                                             \
                            [ window sendEvent:event ];                                                   \
                }                                                                                      \
                else {                                                                                 \
                    QZ_DoActivate (this, p);                                                           \
                }       
            
            #define DO_MOUSE_UP(button, sendToWindow)                                          \
                if ( ! NSPointInRect (p, titleBarRect) ) \
                    SDL_PrivateMouseButton (SDL_RELEASED, button, p.x, SDL_VideoSurface->h - p.y); \
                if (sendToWindow)                                                              \
                    [ window sendEvent:event ]
                    
            switch ( type) {
            
            case NSLeftMouseDown:  
                if ( NSCommandKeyMask & currentMods ) {
                        DO_MOUSE_DOWN (3, 0);
                } 
                else if ( NSAlternateKeyMask & currentMods ) {
                    DO_MOUSE_DOWN (2, 0);
                } 
                else {
                    DO_MOUSE_DOWN (1, 1);
                }
                break;
            case 25:               DO_MOUSE_DOWN (2, 0); break;
            case NSRightMouseDown: DO_MOUSE_DOWN (3, 0); break;   
            case NSLeftMouseUp:    
            if ( NSCommandKeyMask & currentMods ) {
                        DO_MOUSE_UP (3, 0);
                } 
                else if ( NSAlternateKeyMask & currentMods ) {
                    DO_MOUSE_UP (2, 0);
                } 
                else
                    DO_MOUSE_UP (1, 1);
                break;
            case 26:               DO_MOUSE_UP (2, 0);   break;
            case NSRightMouseUp:   DO_MOUSE_UP (3, 0);   break;
            case NSSystemDefined:
                //if ([event subtype] == 7) {
                //    unsigned int buttons;   // up to 32 mouse button states!
                //    buttons = [ event data2 ];
                //}
                break;
            case NSLeftMouseDragged:
            case NSRightMouseDragged:
            case 27:
                SDL_PrivateMouseMotion (SDL_PRESSED, 0, p.x, SDL_VideoSurface->h - p.y);
                break;
            case NSMouseMoved:
                {
                   static int moves = 0;
                    
                   if ( (moves % 10) == 0 ) {
                        SDL_PrivateMouseMotion (SDL_RELEASED, 0, p.x, SDL_VideoSurface->h - p.y);
                        moves = 0;
                   }
                   else {
                        CGMouseDelta dx, dy;
                        CGGetLastMouseDelta (&dx, &dy);
                        SDL_PrivateMouseMotion (SDL_RELEASED, 1, dx, dy);
                        moves++;
                   }
                }
                break;
            case NSScrollWheel:
                {
                    if (NSPointInRect(p, winRect)) {
                        float dy;
                        dy = [ event deltaY ];
                        if ( dy > 0.0 ) /* Scroll up */
                            SDL_PrivateMouseButton (SDL_PRESSED, 4, p.x, SDL_VideoSurface->h - p.y);
                        else /* Scroll down */
                            SDL_PrivateMouseButton (SDL_PRESSED, 5, p.x, SDL_VideoSurface->h - p.y);
                    }
                }
                break;
            case NSKeyUp:
                QZ_DoKey (SDL_RELEASED, event);
                break;
            case NSKeyDown:
                QZ_DoKey (SDL_PRESSED, event);
                break;
            case NSFlagsChanged:
                QZ_DoModifiers( [ event modifierFlags ] );
                break;
            case NSMouseEntered: break;
            case NSMouseExited: break;
            case NSAppKitDefined:
                switch ( [ event subtype ] ) {
                case NSApplicationActivatedEventType:
                    QZ_DoActivate (this, p);
                    break;
                case NSApplicationDeactivatedEventType:
                    QZ_DoDeactivate (this);
                    break;
                case NSWindowMovedEventType:
                    [ window sendEvent:event ];
                    break;
                }
                break;
            case NSApplicationDefined: break;
            case NSPeriodic: break;
            case NSCursorUpdate: break;
            }
        }
       // [ pool release ];

      } while (event != nil);
}