src/video/quartz/SDL_QuartzEvents.m
changeset 172 37e3ca9254c7
parent 168 e92aa316c517
child 252 e8157fcb3114
--- a/src/video/quartz/SDL_QuartzEvents.m	Tue Sep 11 18:52:45 2001 +0000
+++ b/src/video/quartz/SDL_QuartzEvents.m	Tue Sep 11 19:00:18 2001 +0000
@@ -1,37 +1,43 @@
 /*
-    SDL - Simple DirectMedia Layer
-    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
+	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 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.
+	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
+	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
+	Sam Lantinga
+	slouken@devolution.com
 */
 
 #include "SDL_QuartzKeys.h"
 
-static int last_virtual_button = 0; // Last virtual mouse button pressed
+static SDLKey keymap[256];
+static unsigned int currentMods = 0; /* Current keyboard modifiers, to track modifier state */
+static int last_virtual_button = 0; /* Last virtual mouse button pressed */
 
-static void  QZ_InitOSKeymap (_THIS) {
+static void	 QZ_InitOSKeymap (_THIS) {
+	const void *KCHRPtr;
+	UInt32 state;
+	UInt32 value;
 	int i;
-
+	int world = SDLK_WORLD_0;
+	
 	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;
+	/* 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;
@@ -135,261 +141,322 @@
 	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_UP]	  = SDLK_UP;
 	keymap[QZ_IBOOK_LEFT] = SDLK_LEFT;
+	
+	/* Up there we setup a static scancode->keysym map. However, it will not
+	 * work very well on international keyboard. Hence we now query MacOS
+	 * for its own keymap to adjust our own mapping table. However, this is
+	 * bascially only useful for ascii char keys. This is also the reason
+	 * why we keep the static table, too.
+	 */
+	
+	/* Get a pointer to the systems cached KCHR */
+	KCHRPtr = (void *)GetScriptManagerVariable(smKCHRCache);
+	if (KCHRPtr)
+	{
+		/* Loop over all 127 possible scan codes */
+		for (i = 0; i < 0x7F; i++)
+		{
+			/* We pretend a clean start to begin with (i.e. no dead keys active */
+			state = 0;
+			
+			/* Now translate the key code to a key value */
+			value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
+			
+			/* If the state become 0, it was a dead key. We need to translate again,
+			passing in the new state, to get the actual key value */
+			if (state != 0)
+				value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
+			
+			/* Now we should have an ascii value, or 0. Try to figure out to which SDL symbol it maps */
+			if (value >= 128)	 /* Some non-ASCII char, map it to SDLK_WORLD_* */
+				keymap[i] = world++;
+			else if (value >= 32)	 /* non-control ASCII char */
+				keymap[i] = value;
+		}
+	}
+	
+	/* The keypad codes are re-setup here, because the loop above cannot
+	 * distinguish between a key on the keypad and a regular key. We maybe
+	 * could get around this problem in another fashion: NSEvent's flags
+	 * include a "NSNumericPadKeyMask" bit; we could check that and modify
+	 * the symbol we return on the fly. However, this flag seems to exhibit
+	 * some weird behaviour related to the num lock key
+	 */
+	keymap[QZ_KP0] = SDLK_KP0;
+	keymap[QZ_KP1] = SDLK_KP1;
+	keymap[QZ_KP2] = SDLK_KP2;
+	keymap[QZ_KP3] = SDLK_KP3;
+	keymap[QZ_KP4] = SDLK_KP4;
+	keymap[QZ_KP5] = SDLK_KP5;
+	keymap[QZ_KP6] = SDLK_KP6;
+	keymap[QZ_KP7] = SDLK_KP7;
+	keymap[QZ_KP8] = SDLK_KP8;
+	keymap[QZ_KP9] = SDLK_KP9;
+	keymap[QZ_KP_MINUS] = SDLK_KP_MINUS;
+	keymap[QZ_KP_PLUS] = SDLK_KP_PLUS;
+	keymap[QZ_KP_PERIOD] = SDLK_KP_PERIOD;
+	keymap[QZ_KP_EQUALS] = SDLK_KP_EQUALS;
+	keymap[QZ_KP_DIVIDE] = SDLK_KP_DIVIDE;
+	keymap[QZ_KP_MULTIPLY] = SDLK_KP_MULTIPLY;
+	keymap[QZ_KP_ENTER] = SDLK_KP_ENTER;
 }
 
 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);
-        }
+	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 } ;
+	const int mapping[] = { SDLK_CAPSLOCK, SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA } ;
+
+	int i;
+	int bit;
+	SDL_keysym key;
 
-    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.scancode = 0;
+	key.sym		 = SDLK_UNKNOWN;
+	key.unicode	 = 0;
+	key.mod		 = KMOD_NONE;
+	
+	/* Iterate through the bits, testing each against the current modifiers */
+	for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
+	
+		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;
+			key.sym = mapping[i];
+			/* If this was Caps Lock, we need some additional voodoo to make SDL happy */
+			if (bit == NSAlphaShiftKeyMask)
+				SDL_PrivateKeyboard (SDL_PRESSED, &key);
+			SDL_PrivateKeyboard (SDL_RELEASED, &key);
+		}
+		else
+		if ( newMask &&
+			 currentMask != newMask ) {	 /* modifier down event */
+		
+			key.sym = mapping[i];
+			SDL_PrivateKeyboard (SDL_PRESSED, &key);
+			/* If this was Caps Lock, we need some additional voodoo to make SDL happy */
+			if (bit == NSAlphaShiftKeyMask)
+				SDL_PrivateKeyboard (SDL_RELEASED, &key);
+		}
+	}
+	
+	currentMods = newMods;
 }
 
 static void QZ_DoActivate (_THIS)
 {
-    inForeground = YES;
-
-    /* Regrab the mouse */
-    if (currentGrabMode == SDL_GRAB_ON) {
-        QZ_WarpWMCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2);
-        CGAssociateMouseAndMouseCursorPosition (0);
-    }
+	inForeground = YES;
 
-    /* Hide the mouse cursor if inside the app window */
-    // FIXME
-    if (!QZ_cursor_visible) {
-            HideCursor ();
-    }
-    
-    SDL_PrivateAppActive (1, SDL_APPINPUTFOCUS);
+	/* Regrab the mouse */
+	if (currentGrabMode == SDL_GRAB_ON) {
+		QZ_WarpWMCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2);
+		CGAssociateMouseAndMouseCursorPosition (0);
+	}
+
+	/* Hide the mouse cursor if inside the app window */
+	if (!QZ_cursor_visible) {
+		HideCursor ();
+	}
+	
+	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);
-    }
+	
+	inForeground = NO;
 
-    /* Show the mouse cursor */
-    // FIXME
-    if (!QZ_cursor_visible) {
-            ShowCursor ();
-    }
-    
-    SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS);
+	/* Ungrab mouse if it is grabbed */
+	if (currentGrabMode == SDL_GRAB_ON) {
+		CGAssociateMouseAndMouseCursorPosition (1);
+	}
+
+	/* Show the mouse cursor */
+	if (!QZ_cursor_visible) {
+		ShowCursor ();
+	}
+	
+	SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS);
 }
 
 static void QZ_PumpEvents (_THIS)
 {
-    NSDate *distantPast;
-    NSEvent *event;
-    NSRect winRect;
-    NSRect titleBarRect;
-    NSAutoreleasePool *pool;
-    
-    distantPast = [ [ NSDate distantPast ] retain ];
-    
-    pool = [ [ NSAutoreleasePool alloc ] init ];
-    
-    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;
-            BOOL isForGameWin;
+	NSDate *distantPast;
+	NSEvent *event;
+	NSRect winRect;
+	NSRect titleBarRect;
+	NSAutoreleasePool *pool;
+	
+	pool = [ [ NSAutoreleasePool alloc ] init ];
+	distantPast = [ NSDate distantPast ];
+	
+	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;
+			BOOL isForGameWin;
 
-            #define DO_MOUSE_DOWN(button, sendToWindow) do {                 \
-                if ( inForeground ) {                                        \
-                    if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) ||       \
-                         NSPointInRect([event locationInWindow], winRect) )  \
-                        SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);  \
-                }                                                            \
-                else {                                                       \
-                    QZ_DoActivate (this);                                    \
-                }                                                            \
-                [ NSApp sendEvent:event ];                                   \
-                } while(0)
-                
-            #define DO_MOUSE_UP(button, sendToWindow) do {                   \
-                if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) ||           \
-                     !NSPointInRect([event locationInWindow], titleBarRect) )\
-                    SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);     \
-                [ NSApp sendEvent:event ];                                   \
-                } while(0)
+			#define DO_MOUSE_DOWN(button, sendToWindow) do {				 \
+				if ( inForeground ) {										 \
+					if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) ||		 \
+						 NSPointInRect([event locationInWindow], winRect) )	 \
+						SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);	 \
+				}															 \
+				else {														 \
+					QZ_DoActivate (this);									 \
+				}															 \
+				[ NSApp sendEvent:event ];									 \
+				} while(0)
+				
+			#define DO_MOUSE_UP(button, sendToWindow) do {					 \
+				if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) ||			 \
+					 !NSPointInRect([event locationInWindow], titleBarRect) )\
+					SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);	 \
+				[ NSApp sendEvent:event ];									 \
+				} while(0)
 
-            type = [ event type ];
-            isForGameWin = (qz_window == [ event window ]);
-            switch (type) {
-            
-            case NSLeftMouseDown:  
-                if ( NSCommandKeyMask & currentMods ) {
-                    last_virtual_button = 3;
-                    DO_MOUSE_DOWN (3, 0);
-                } 
-                else if ( NSAlternateKeyMask & currentMods ) {
-                    last_virtual_button = 2;
-                    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 ( last_virtual_button != 0 ) {
-                    DO_MOUSE_UP (last_virtual_button, 0);
-                    last_virtual_button = 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:
-            case NSMouseMoved:
-                if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN)
-                	|| NSPointInRect([event locationInWindow], winRect) )
-                {
-                   static int moves = 0;
-                   NSPoint p;
-            
-                   if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
-                       p = [ NSEvent mouseLocation ];
-                       p.y = [[NSScreen mainScreen] frame].size.height - p.y;
-                   } else {
-            	       p = [ event locationInWindow ];
-                       p.y = SDL_VideoSurface->h - p.y;
-                   }
+			type = [ event type ];
+			isForGameWin = (qz_window == [ event window ]);
+			switch (type) {
+			
+			case NSLeftMouseDown:
+				if ( NSCommandKeyMask & currentMods ) {
+					last_virtual_button = 3;
+					DO_MOUSE_DOWN (3, 0);
+				}
+				else if ( NSAlternateKeyMask & currentMods ) {
+					last_virtual_button = 2;
+					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 ( last_virtual_button != 0 ) {
+					DO_MOUSE_UP (last_virtual_button, 0);
+					last_virtual_button = 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:
+			case NSMouseMoved:
+				if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN)
+					|| NSPointInRect([event locationInWindow], winRect) )
+				{
+				   static int moves = 0;
+				   NSPoint p;
+			
+				   if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
+					   p = [ NSEvent mouseLocation ];
+					   p.y = [[NSScreen mainScreen] frame].size.height - p.y;
+				   } else {
+					   p = [ event locationInWindow ];
+					   p.y = SDL_VideoSurface->h - p.y;
+				   }
 
-                   if ( (moves % 10) == 0 ) {
-                        SDL_PrivateMouseMotion (0, 0, p.x, p.y);
-                   }
-                   else {
-                        CGMouseDelta dx, dy;
-                        CGGetLastMouseDelta (&dx, &dy);
-                        SDL_PrivateMouseMotion (0, 1, dx, dy);
-                   }
-                   moves++;
-                }
-                break;
-            case NSScrollWheel:
-                {
-                    if (NSPointInRect([ event locationInWindow ], winRect)) {
-                        float dy;
-                        dy = [ event deltaY ];
-                        if ( dy > 0.0 ) /* Scroll up */
-                            SDL_PrivateMouseButton (SDL_PRESSED, 4, 0, 0);
-                        else /* Scroll down */
-                            SDL_PrivateMouseButton (SDL_PRESSED, 5, 0, 0);
-                    }
-                }
-                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);
-                    break;
-                case NSApplicationDeactivatedEventType:
-                    QZ_DoDeactivate (this);
-                    break;
-                }
-                [ NSApp sendEvent:event ];
-                break;
-//            case NSApplicationDefined: break;
-//            case NSPeriodic: break;
-//            case NSCursorUpdate: break;
-            default:
-                [ NSApp sendEvent:event ];
-            }
-        }
-      } while (event != nil);
-      
-      [ pool release ];
-      [ distantPast release ];
+				   if ( (moves % 10) == 0 ) {
+						SDL_PrivateMouseMotion (0, 0, p.x, p.y);
+				   }
+				   else {
+						CGMouseDelta dx, dy;
+						CGGetLastMouseDelta (&dx, &dy);
+						SDL_PrivateMouseMotion (0, 1, dx, dy);
+				   }
+				   moves++;
+				}
+				break;
+			case NSScrollWheel:
+				{
+					if (NSPointInRect([ event locationInWindow ], winRect)) {
+						float dy;
+						dy = [ event deltaY ];
+						if ( dy > 0.0 ) /* Scroll up */
+							SDL_PrivateMouseButton (SDL_PRESSED, 4, 0, 0);
+						else /* Scroll down */
+							SDL_PrivateMouseButton (SDL_PRESSED, 5, 0, 0);
+					}
+				}
+				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);
+					break;
+				case NSApplicationDeactivatedEventType:
+					QZ_DoDeactivate (this);
+					break;
+				}
+				[ NSApp sendEvent:event ];
+				break;
+			/* case NSApplicationDefined: break; */
+			/* case NSPeriodic: break; */
+			/* case NSCursorUpdate: break; */
+			default:
+				[ NSApp sendEvent:event ];
+			}
+		}
+	  } while (event != nil);
+	
+	  [ pool release ];
 }