Date: Sat, 8 Sep 2001 04:42:23 +0200
authorSam Lantinga <slouken@libsdl.org>
Tue, 11 Sep 2001 19:00:18 +0000
changeset 17237e3ca9254c7
parent 171 02e27b705645
child 173 83018110dce8
Date: Sat, 8 Sep 2001 04:42:23 +0200
From: Max Horn <max@quendi.de>
Subject: SDL/OSX: Joystick; Better key handling

I just finished implementing improved keyhandling for OS X (in fact
the code should be easily ported to the "normal" MacOS part of SDL, I
just had no chance yet). Works like this:
First init the mapping table statically like before. Them, it queries
the OS for the "official" key table, then iterates over all 127
scancode and gets the associates ascii code. It ignores everythng
below 32 (has to, as it would lead to many problems if we did not...
e.g. both ESC and NUM LOCk produce an ascii code 27 on my keyboard),
and all stuff above 127 is mapped to SDLK_WORLD_* simply in the order
it is encountered.
In addition, caps lock is now working, too.
The code work flawless for me, but since I only have one keyboard, I
may have not encountered some serious problem... but I am pretty
confident that it is better than the old code in most cases.


The joystick driver works fine for me, too. I think it can be added
to CVS already. It would simply be helpful if more people would test
it. Hm, I wonder if Maelstrom or GLTron has Joystick support? That
would be a wonderful test application :)


I also took the liberty of modifying some text files like BUGS,
README.CVS, README.MacOSX (which now contains the OS X docs I long
promised)
BUGS
README.CVS
README.MacOS
README.MacOSX
configure.in
sdl.m4
src/joystick/Makefile.am
src/joystick/darwin/.cvsignore
src/joystick/darwin/Makefile.am
src/joystick/darwin/SDL_sysjoystick.c
src/video/quartz/SDL_QuartzEvents.m
src/video/quartz/SDL_QuartzVideo.m
test/acinclude.m4
     1.1 --- a/BUGS	Tue Sep 11 18:52:45 2001 +0000
     1.2 +++ b/BUGS	Tue Sep 11 19:00:18 2001 +0000
     1.3 @@ -68,9 +68,9 @@
     1.4  	Not all of the keys are properly recognized on the keyboard.
     1.5  
     1.6  MacOS X:
     1.7 -	Joystick and CD-ROM functions are not implemented yet.
     1.8 +	CD-ROM functions are not implemented yet.
     1.9  
    1.10 -	Window management buttons don't draw correctly.
    1.11 +	Joystick code is not extensively tested yet.
    1.12  
    1.13  	Window may not close when unsetting video mode and resetting.
    1.14  
    1.15 @@ -98,8 +98,6 @@
    1.16  	cursor in the center of the window/screen.  Also, mouse moved events
    1.17  	are not generated, and the keyboard cannot be grabbed.
    1.18  
    1.19 -	Not all of the keys are properly recognized on the keyboard.
    1.20 -
    1.21  	MacOS X seems to have a broken pthread_cancel() implementation.
    1.22  
    1.23  FreeBSD:
     2.1 --- a/README.CVS	Tue Sep 11 18:52:45 2001 +0000
     2.2 +++ b/README.CVS	Tue Sep 11 19:00:18 2001 +0000
     2.3 @@ -1,13 +1,13 @@
     2.4  
     2.5  The latest development version of SDL is available via CVS:
     2.6  
     2.7 -cvs -d :pserver:guest@cvs.lokigames.com:/cvs login
     2.8 -# use the password "guest"
     2.9 -cvs -d :pserver:guest@cvs.lokigames.com:/cvs checkout SDL
    2.10 +cvs -d :pserver:guest@libsdl.org:/home/slouken/libsdl.org/cvs login
    2.11 +# No password, so just hit enter when prompted for a password
    2.12 +cvs -d :pserver:guest@libsdl.org:/home/slouken/libsdl.org/cvs checkout SDL
    2.13  
    2.14  When you check a fresh copy of SDL out of CVS, you need to generate
    2.15  the files used by make by running the "autogen.sh" script, which will
    2.16  run aclocal, automake, autoconf and then run configure.
    2.17  
    2.18 -There is a web interface to cvs at http://cvs.lokigames.com/
    2.19 +There is a web interface to cvs at http://www.libsdl.org/cgi/cvsweb.cgi
    2.20  
     3.1 --- a/README.MacOS	Tue Sep 11 18:52:45 2001 +0000
     3.2 +++ b/README.MacOS	Tue Sep 11 19:00:18 2001 +0000
     3.3 @@ -52,9 +52,12 @@
     3.4    If you have a project you'd like me to know about, or want to ask questions,
     3.5    go ahead and join the SDL developer's mailing list by sending e-mail to:
     3.6  
     3.7 -	majordomo@lokigames.com
     3.8 +	sdl-request@libsdl.org
     3.9  
    3.10 -  and put the line "subscribe sdl" in the body of the message.
    3.11 +  and put "subscribe" into the subject of the message. Or alternatively you
    3.12 +  can use the web interface:
    3.13 +
    3.14 +	http://www.libsdl.org/mailman/listinfo/sdl
    3.15    
    3.16  ==============================================================================
    3.17  
     4.1 --- a/README.MacOSX	Tue Sep 11 18:52:45 2001 +0000
     4.2 +++ b/README.MacOSX	Tue Sep 11 19:00:18 2001 +0000
     4.3 @@ -18,11 +18,7 @@
     4.4  
     4.5  (You may need to create the subdirs of /usr/local manually.)
     4.6  
     4.7 -For some reason, libtool doesn't run ranlib properly, so do this
     4.8 -manually:
     4.9 -
    4.10 -	ranlib /usr/local/lib/libSDL.a
    4.11 -
    4.12 +/*
    4.13  To use the library once it's built, you need to use the "Carbon
    4.14  framework", which is the port of the old Mac Toolbox to OS X.
    4.15  To do this, use the -F and -framework arguments for compiling
    4.16 @@ -33,6 +29,79 @@
    4.17  
    4.18  sdl-config knows about the linking path and -framework, so it's
    4.19  recommended to use it to fill in your Makefile variables.
    4.20 +*/
    4.21 +
    4.22 +To use the library once it's built, you essential have two possibilities:
    4.23 +use the traditional autoconf/automake/make method, or use Apple's Project Builder.
    4.24 +
    4.25 +==============================================================================
    4.26 +Using the Simple DirectMedia Layer with a traditional Makefile
    4.27 +==============================================================================
    4.28 +
    4.29 +In the following, it will be mostly assumed that you are using autoconf and
    4.30 +automake to setup your SDL project, and furthermore that you use the AM_PATH_SDL
    4.31 +macro provided by SDL in sdl.m4. If you are not using these tools, you can
    4.32 +still use SDL but it will be somewhat hard to get running.
    4.33 +
    4.34 +Only step 1) is really required to get started, but for full OS X support you
    4.35 +will want to do the other steps, too.
    4.36 +
    4.37 +1) Update your acinclude.m4 file in case you have copied an older version of
    4.38 +   sdl.m4 into it. This is essential as AM_PATH_SDL now performs some additional
    4.39 +   tasks when used on MacOS X
    4.40 +
    4.41 +   Rationale: AM_PATH_SDL copies /usr/local/share/sdl/Info.plist and the folder
    4.42 +   /usr/local/share/sdl/SDLMain.nib/ into the directory where configure is invoked.
    4.43 +   This is essential for the configure script to be able to run the test code
    4.44 +   that detects SDL.
    4.45 +
    4.46 +2) Copy SDL's Info.plist.in file (from src/main/macosx) into your project's main
    4.47 +   folder (the same spot that your configure.in sits), and edit it to suite your
    4.48 +   needs. Then add it to your AC_OUTPUT list in configure.in
    4.49 +
    4.50 +   Rationale: The Info.plist file can be used to specify an icon file for
    4.51 +   your app, and also to provide a human readable version/copyright string
    4.52 +   and other meta-information to the user via the Finder's Get Info dialog.
    4.53 +
    4.54 +3) Add something like the following rule to your Makefile.am:
    4.55 +
    4.56 +APP_NAME.app: EXE_NAME
    4.57 +	mkdir -p $@/Contents/MacOS
    4.58 +	mkdir -p $@/Contents/Resources
    4.59 +	mkdir -p $@/Contents/Resources/SDLMain.nib
    4.60 +	echo "APPL????" > $@/Contents/PkgInfo
    4.61 +	$(INSTALL_DATA) Info.plist $@/Contents/
    4.62 +	$(INSTALL_DATA) SDLMain.nib/*.nib $@/Contents/Resources/
    4.63 +	$(INSTALL_PROGRAM) $< $@/Contents/MacOS/
    4.64 +
    4.65 +   You should replace EXE_NAME with the name of the executable. APP_NAME is what
    4.66 +   will be visible to the user in the Finder. Usually it will be the same
    4.67 +   as EXE_NAME but capitalized. E.g. if EXE_NAME is "testgame" then APP_NAME 
    4.68 +   usually is "TestGame"
    4.69 +
    4.70 +   If your project builds more than one application, you will have to do a bit more.
    4.71 +   For each of your target applications, you need a seperate rule. Furthermore, each
    4.72 +   needs its own Info.plist file, since that has to contain the exact name of the 
    4.73 +   executable (i.e. EXE_NAME above). One way to do that is to use sed in your make rules
    4.74 +   and modify a single master Info.plist.
    4.75 +
    4.76 +   Rationale: on Mac OS X, executables have to be put into so-called "bundles".
    4.77 +   The make rule given above will construct such a bundle around the executable
    4.78 +   for you. You need to make a copy of it for each target application.
    4.79 +
    4.80 +4) If you want the create bundles to be installed, you may want to add this
    4.81 +   rule to your Makefile.am:
    4.82 +
    4.83 +install-exec-local: Exult.app
    4.84 +	mkdir -p /Applications/
    4.85 +	cp -r $< /Applications/
    4.86 +
    4.87 +   This rule takes the Bundle created by the rule from step 3 and installs them
    4.88 +   into /Applications/. An alternate installation place would be $HOME/Applications/
    4.89 +
    4.90 +   Again, if you want to install multiple applications, you will have to augment
    4.91 +   the make rule accordingly.
    4.92 +
    4.93  
    4.94  ==============================================================================
    4.95  Using the Simple DirectMedia Layer with Project Builder
    4.96 @@ -122,3 +191,4 @@
    4.97          but I expect that things will still work on older versions.
    4.98          
    4.99  Known bugs are listed in the file "BUGS"
   4.100 + LocalWords:  Stuffit
     5.1 --- a/configure.in	Tue Sep 11 18:52:45 2001 +0000
     5.2 +++ b/configure.in	Tue Sep 11 19:00:18 2001 +0000
     5.3 @@ -2056,8 +2056,8 @@
     5.4          fi
     5.5          # Set up files for the joystick library
     5.6          if test x$enable_joystick = xyes; then
     5.7 -            JOYSTICK_SUBDIRS="$JOYSTICK_SUBDIRS dummy"
     5.8 -            JOYSTICK_DRIVERS="$JOYSTICK_DRIVERS dummy/libjoystick_dummy.la"
     5.9 +            JOYSTICK_SUBDIRS="$JOYSTICK_SUBDIRS darwin"
    5.10 +            JOYSTICK_DRIVERS="$JOYSTICK_DRIVERS darwin/libjoystick_darwin.la"
    5.11          fi
    5.12          # Set up files for the cdrom library
    5.13          if test x$enable_cdrom = xyes; then
    5.14 @@ -2192,6 +2192,7 @@
    5.15  src/Makefile
    5.16  src/main/Makefile
    5.17  src/main/macosx/Makefile
    5.18 +src/main/macosx/Info.plist
    5.19  src/audio/Makefile
    5.20  src/audio/alsa/Makefile
    5.21  src/audio/arts/Makefile
    5.22 @@ -2236,6 +2237,7 @@
    5.23  src/joystick/Makefile
    5.24  src/joystick/amigaos/Makefile
    5.25  src/joystick/beos/Makefile
    5.26 +src/joystick/darwin/Makefile
    5.27  src/joystick/dummy/Makefile
    5.28  src/joystick/linux/Makefile
    5.29  src/joystick/macos/Makefile
     6.1 --- a/sdl.m4	Tue Sep 11 18:52:45 2001 +0000
     6.2 +++ b/sdl.m4	Tue Sep 11 19:00:18 2001 +0000
     6.3 @@ -32,6 +32,7 @@
     6.4       fi
     6.5    fi
     6.6  
     6.7 +  AC_REQUIRE([AC_CANONICAL_TARGET])
     6.8    AC_PATH_PROG(SDL_CONFIG, sdl-config, no)
     6.9    min_sdl_version=ifelse([$1], ,0.11.0,$1)
    6.10    AC_MSG_CHECKING(for SDL - version >= $min_sdl_version)
     7.1 --- a/src/joystick/Makefile.am	Tue Sep 11 18:52:45 2001 +0000
     7.2 +++ b/src/joystick/Makefile.am	Tue Sep 11 19:00:18 2001 +0000
     7.3 @@ -5,7 +5,7 @@
     7.4  
     7.5  # Define which subdirectories need to be built
     7.6  SUBDIRS = @JOYSTICK_SUBDIRS@
     7.7 -DIST_SUBDIRS = dummy amigaos beos linux macos win32
     7.8 +DIST_SUBDIRS = dummy amigaos beos darwin linux macos win32
     7.9  
    7.10  DRIVERS = @JOYSTICK_DRIVERS@
    7.11  
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/joystick/darwin/.cvsignore	Tue Sep 11 19:00:18 2001 +0000
     8.3 @@ -0,0 +1,6 @@
     8.4 +Makefile.in
     8.5 +Makefile
     8.6 +.libs
     8.7 +*.o
     8.8 +*.lo
     8.9 +*.la
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/joystick/darwin/Makefile.am	Tue Sep 11 19:00:18 2001 +0000
     9.3 @@ -0,0 +1,8 @@
     9.4 +
     9.5 +## Makefile.am for the darwin/MacOS X joystick driver for SDL
     9.6 +
     9.7 +noinst_LTLIBRARIES = libjoystick_darwin.la
     9.8 +libjoystick_darwin_la_SOURCES = $(SRCS)
     9.9 +
    9.10 +# The SDL joystick driver sources
    9.11 +SRCS =  SDL_sysjoystick.c
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/joystick/darwin/SDL_sysjoystick.c	Tue Sep 11 19:00:18 2001 +0000
    10.3 @@ -0,0 +1,776 @@
    10.4 +/*
    10.5 +	SDL - Simple DirectMedia Layer
    10.6 +	Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
    10.7 +
    10.8 +	This library is free software; you can redistribute it and/or
    10.9 +	modify it under the terms of the GNU Library General Public
   10.10 +	License as published by the Free Software Foundation; either
   10.11 +	version 2 of the License, or (at your option) any later version.
   10.12 +
   10.13 +	This library is distributed in the hope that it will be useful,
   10.14 +	but WITHOUT ANY WARRANTY; without even the implied warranty of
   10.15 +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   10.16 +	Library General Public License for more details.
   10.17 +
   10.18 +	You should have received a copy of the GNU Library General Public
   10.19 +	License along with this library; if not, write to the Free
   10.20 +	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   10.21 +
   10.22 +	Sam Lantinga
   10.23 +	slouken@devolution.com
   10.24 +*/
   10.25 +
   10.26 +/* SDL joystick driver for Darwn / MacOS X, based on the IOKit HID API */
   10.27 +/* Written 2001 by Max Horn */
   10.28 +
   10.29 +#include <stdio.h>
   10.30 +#include <stdlib.h>
   10.31 +#include <unistd.h>
   10.32 +#include <ctype.h>
   10.33 +#include <sys/errno.h>
   10.34 +#include <sysexits.h>
   10.35 +#include <mach/mach.h>
   10.36 +#include <mach/mach_error.h>
   10.37 +#include <IOKit/IOKitLib.h>
   10.38 +#include <IOKit/IOCFPlugIn.h>
   10.39 +#include <IOKit/IOUSBHIDParser.h>
   10.40 +#include <IOKit/hid/IOHIDLib.h>
   10.41 +#include <IOKit/hid/IOHIDKeys.h>
   10.42 +#include <CoreFoundation/CoreFoundation.h>
   10.43 +
   10.44 +#include "SDL_error.h"
   10.45 +#include "SDL_joystick.h"
   10.46 +#include "SDL_sysjoystick.h"
   10.47 +#include "SDL_joystick_c.h"
   10.48 +
   10.49 +struct recElement
   10.50 +{
   10.51 +	IOHIDElementCookie cookie;				// unique value which identifies element, will NOT change
   10.52 +	long min;								// reported min value possible
   10.53 +	long max;								// reported max value possible
   10.54 +/*
   10.55 +	TODO: maybe should handle the following stuff somehow?
   10.56 +
   10.57 +	long scaledMin;							// reported scaled min value possible
   10.58 +	long scaledMax;							// reported scaled max value possible
   10.59 +	long size;								// size in bits of data return from element
   10.60 +	Boolean relative;						// are reports relative to last report (deltas)
   10.61 +	Boolean wrapping;						// does element wrap around (one value higher than max is min)
   10.62 +	Boolean nonLinear;						// are the values reported non-linear relative to element movement
   10.63 +	Boolean preferredState;					// does element have a preferred state (such as a button)
   10.64 +	Boolean nullState;						// does element have null state
   10.65 +*/
   10.66 +
   10.67 +	/* runtime variables used for auto-calibration */
   10.68 +	long minReport;							// min returned value
   10.69 +	long maxReport;							// max returned value
   10.70 +	
   10.71 +	struct recElement * pNext;				// next element in list
   10.72 +};
   10.73 +typedef struct recElement recElement;
   10.74 +
   10.75 +struct joystick_hwdata
   10.76 +{
   10.77 +	IOHIDDeviceInterface ** interface;		// interface to device, NULL = no interface
   10.78 +
   10.79 +	char product[256];							// name of product
   10.80 +	long usage;								// usage page from IOUSBHID Parser.h which defines general usage
   10.81 +	long usagePage;							// usage within above page from IOUSBHID Parser.h which defines specific usage
   10.82 +
   10.83 +	long axes;								// number of axis (calculated, not reported by device)
   10.84 +	long buttons;							// number of buttons (calculated, not reported by device)
   10.85 +	long hats;								// number of hat switches (calculated, not reported by device)
   10.86 +	long elements;							// number of total elements (shouldbe total of above) (calculated, not reported by device)
   10.87 +
   10.88 +	recElement* firstAxis;
   10.89 +	recElement* firstButton;
   10.90 +	recElement* firstHat;
   10.91 +
   10.92 +	struct recDevice* pNext;				// next device
   10.93 +};
   10.94 +typedef struct joystick_hwdata recDevice;
   10.95 +
   10.96 +
   10.97 +/* Linked list of all available devices */
   10.98 +static recDevice *gpDeviceList = NULL;
   10.99 +
  10.100 +
  10.101 +void HIDReportErrorNum (char * strError, long numError)
  10.102 +{
  10.103 +	SDL_SetError(strError);
  10.104 +}
  10.105 +
  10.106 +static void HIDGetCollectionElements (CFMutableDictionaryRef deviceProperties, recDevice *pDevice);
  10.107 +
  10.108 +/* returns current value for element, polling element
  10.109 + * will return 0 on error conditions which should be accounted for by application
  10.110 + */
  10.111 +
  10.112 +SInt32 HIDGetElementValue (recDevice *pDevice, recElement *pElement)
  10.113 +{
  10.114 +	IOReturn result = kIOReturnSuccess;
  10.115 +	IOHIDEventStruct hidEvent;
  10.116 +	hidEvent.value = 0;
  10.117 +	
  10.118 +	if (NULL != pDevice && NULL != pElement && NULL != pDevice->interface)
  10.119 +	{
  10.120 +		result = (*(pDevice->interface))->getElementValue(pDevice->interface, pElement->cookie, &hidEvent);
  10.121 +		if (kIOReturnSuccess == result)
  10.122 +		{
  10.123 +			/* record min and max for auto calibration */
  10.124 +			if (hidEvent.value < pElement->minReport)
  10.125 +				pElement->minReport = hidEvent.value;
  10.126 +			if (hidEvent.value > pElement->maxReport)
  10.127 +				pElement->maxReport = hidEvent.value;
  10.128 +		}
  10.129 +	}
  10.130 +
  10.131 +	// auto user scale
  10.132 +	return hidEvent.value;
  10.133 +}
  10.134 +
  10.135 +/* similiar to HIDGetElementValue, but auto-calibrates the value before returning it */
  10.136 +
  10.137 +SInt32 HIDCalibratedValue (recDevice *pDevice, recElement *pElement)
  10.138 +{
  10.139 +	float deviceScale = pElement->max - pElement->min;
  10.140 +	float readScale = pElement->maxReport - pElement->minReport;
  10.141 +	SInt32 value = HIDGetElementValue(pDevice, pElement);
  10.142 +	if (readScale == 0)
  10.143 +		return value; // no scaling at all
  10.144 +	else
  10.145 +		return ((value - pElement->minReport) * deviceScale / readScale) + pElement->min;
  10.146 +}
  10.147 +
  10.148 +/* similiar to HIDCalibratedValue but calibrates to an arbitrary scale instead of the elements default scale */
  10.149 +
  10.150 +SInt32 HIDScaledCalibratedValue (recDevice *pDevice, recElement *pElement, long min, long max)
  10.151 +{
  10.152 +	float deviceScale = max - min;
  10.153 +	float readScale = pElement->maxReport - pElement->minReport;
  10.154 +	SInt32 value = HIDGetElementValue(pDevice, pElement);
  10.155 +	if (readScale == 0)
  10.156 +		return value; // no scaling at all
  10.157 +	else
  10.158 +		return ((value - pElement->minReport) * deviceScale / readScale) + min;
  10.159 +}
  10.160 +
  10.161 +/* Create and open an interface to device, required prior to extracting values or building queues.
  10.162 + * Note: appliction now owns the device and must close and release it prior to exiting
  10.163 + */
  10.164 +
  10.165 +IOReturn HIDCreateOpenDeviceInterface (io_object_t hidDevice, recDevice *pDevice)
  10.166 +{
  10.167 +	IOReturn result = kIOReturnSuccess;
  10.168 +	HRESULT plugInResult = S_OK;
  10.169 +	SInt32 score = 0;
  10.170 +	IOCFPlugInInterface ** ppPlugInInterface = NULL;
  10.171 +	
  10.172 +	if (NULL == pDevice->interface)
  10.173 +	{
  10.174 +		result = IOCreatePlugInInterfaceForService (hidDevice, kIOHIDDeviceUserClientTypeID,
  10.175 +													kIOCFPlugInInterfaceID, &ppPlugInInterface, &score);
  10.176 +		if (kIOReturnSuccess == result)
  10.177 +		{
  10.178 +			// Call a method of the intermediate plug-in to create the device interface
  10.179 +			plugInResult = (*ppPlugInInterface)->QueryInterface (ppPlugInInterface,
  10.180 +								CFUUIDGetUUIDBytes (kIOHIDDeviceInterfaceID), (void *) &(pDevice->interface));
  10.181 +			if (S_OK != plugInResult)
  10.182 +				HIDReportErrorNum ("CouldnŐt query HID class device interface from plugInInterface", plugInResult);
  10.183 +			(*ppPlugInInterface)->Release (ppPlugInInterface);
  10.184 +		}
  10.185 +		else
  10.186 +			HIDReportErrorNum ("Failed to create **plugInInterface via IOCreatePlugInInterfaceForService.", result);
  10.187 +	}
  10.188 +	if (NULL != pDevice->interface)
  10.189 +	{
  10.190 +		result = (*(pDevice->interface))->open (pDevice->interface, 0);
  10.191 +		if (kIOReturnSuccess != result)
  10.192 +			HIDReportErrorNum ("Failed to open pDevice->interface via open.", result);
  10.193 +	}
  10.194 +	return result;
  10.195 +}
  10.196 +
  10.197 +/* Closes and releases interface to device, should be done prior to exting application
  10.198 + * Note: will have no affect if device or interface do not exist
  10.199 + * application will "own" the device if interface is not closed
  10.200 + * (device may have to be plug and re-plugged in different location to get it working again without a restart)
  10.201 + */
  10.202 +
  10.203 +IOReturn HIDCloseReleaseInterface (recDevice *pDevice)
  10.204 +{
  10.205 +	IOReturn result = kIOReturnSuccess;
  10.206 +	
  10.207 +	if ((NULL != pDevice) && (NULL != pDevice->interface))
  10.208 +	{
  10.209 +		// close the interface
  10.210 +		result = (*(pDevice->interface))->close (pDevice->interface);
  10.211 +		if (kIOReturnNotOpen == result)
  10.212 +		{
  10.213 +			//  do nothing as device was not opened, thus can't be closed
  10.214 +		}
  10.215 +		else if (kIOReturnSuccess != result)
  10.216 +			HIDReportErrorNum ("Failed to close IOHIDDeviceInterface.", result);
  10.217 +		//release the interface
  10.218 +		result = (*(pDevice->interface))->Release (pDevice->interface);
  10.219 +		if (kIOReturnSuccess != result)
  10.220 +			HIDReportErrorNum ("Failed to release IOHIDDeviceInterface.", result);
  10.221 +		pDevice->interface = NULL;
  10.222 +	}	
  10.223 +	return result;
  10.224 +}
  10.225 +
  10.226 +/* extracts actual specific element information from each element CF dictionary entry */
  10.227 +
  10.228 +static void HIDGetElementInfo (CFTypeRef refElement, recElement *pElement)
  10.229 +{
  10.230 +	long number;
  10.231 +	CFTypeRef refType;
  10.232 +
  10.233 +	refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementCookieKey));
  10.234 +	if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
  10.235 +		pElement->cookie = (IOHIDElementCookie) number;
  10.236 +	refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementMinKey));
  10.237 +	if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
  10.238 +		pElement->min = number;
  10.239 +		pElement->maxReport = pElement->min;
  10.240 +	refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementMaxKey));
  10.241 +	if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
  10.242 +		pElement->max = number;
  10.243 +		pElement->minReport = pElement->max;
  10.244 +/*
  10.245 +	TODO: maybe should handle the following stuff somehow?
  10.246 +
  10.247 +	refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementScaledMinKey));
  10.248 +	if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
  10.249 +		pElement->scaledMin = number;
  10.250 +	refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementScaledMaxKey));
  10.251 +	if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
  10.252 +		pElement->scaledMax = number;
  10.253 +	refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementSizeKey));
  10.254 +	if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
  10.255 +		pElement->size = number;
  10.256 +	refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementIsRelativeKey));
  10.257 +	if (refType)
  10.258 +		pElement->relative = CFBooleanGetValue (refType);
  10.259 +	refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementIsWrappingKey));
  10.260 +	if (refType)
  10.261 +		pElement->wrapping = CFBooleanGetValue (refType);
  10.262 +	refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementIsNonLinearKey));
  10.263 +	if (refType)
  10.264 +		pElement->nonLinear = CFBooleanGetValue (refType);
  10.265 +	refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementHasPreferedStateKey));
  10.266 +	if (refType)
  10.267 +		pElement->preferredState = CFBooleanGetValue (refType);
  10.268 +	refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementHasNullStateKey));
  10.269 +	if (refType)
  10.270 +		pElement->nullState = CFBooleanGetValue (refType);
  10.271 +*/
  10.272 +}			
  10.273 +
  10.274 +/* examines CF dictionary vlaue in device element hierarchy to determine if it is element of interest or a collection of more elements
  10.275 + * if element of interest allocate storage, add to list and retrieve element specific info
  10.276 + * if collection then pass on to deconstruction collection into additional individual elements
  10.277 + */
  10.278 +
  10.279 +static void HIDAddElement (CFTypeRef refElement, recDevice* pDevice)
  10.280 +{
  10.281 +	recElement* element = NULL;
  10.282 +	recElement** headElement = NULL;
  10.283 +	long elementType, usagePage, usage;
  10.284 +	CFTypeRef refElementType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementTypeKey));
  10.285 +	CFTypeRef refUsagePage = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementUsagePageKey));
  10.286 +	CFTypeRef refUsage = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementUsageKey));
  10.287 +
  10.288 +
  10.289 +	if ((refElementType) && (CFNumberGetValue (refElementType, kCFNumberLongType, &elementType)))
  10.290 +	{
  10.291 +		/* look at types of interest */
  10.292 +		if ((elementType == kIOHIDElementTypeInput_Misc) || (elementType == kIOHIDElementTypeInput_Button) ||
  10.293 +			(elementType == kIOHIDElementTypeInput_Axis))
  10.294 +		{
  10.295 +			if (refUsagePage && CFNumberGetValue (refUsagePage, kCFNumberLongType, &usagePage) &&
  10.296 +				refUsage && CFNumberGetValue (refUsage, kCFNumberLongType, &usage))
  10.297 +			{
  10.298 +				switch (usagePage) /* only interested in kHIDPage_GenericDesktop and kHIDPage_Button */
  10.299 +				{
  10.300 +					case kHIDPage_GenericDesktop:
  10.301 +						{
  10.302 +							switch (usage) /* look at usage to determine function */
  10.303 +							{
  10.304 +								case kHIDUsage_GD_X:
  10.305 +								case kHIDUsage_GD_Y:
  10.306 +								case kHIDUsage_GD_Z:
  10.307 +								case kHIDUsage_GD_Rx:
  10.308 +								case kHIDUsage_GD_Ry:
  10.309 +								case kHIDUsage_GD_Rz:
  10.310 +									element = (recElement *) NewPtrClear (sizeof (recElement));
  10.311 +									if (element)
  10.312 +									{
  10.313 +										pDevice->axes++;
  10.314 +										headElement = &(pDevice->firstAxis);
  10.315 +									}
  10.316 +								break;
  10.317 +								case kHIDUsage_GD_Hatswitch:
  10.318 +									element = (recElement *) NewPtrClear (sizeof (recElement));
  10.319 +									if (element)
  10.320 +									{
  10.321 +										pDevice->hats++;
  10.322 +										headElement = &(pDevice->firstHat);
  10.323 +									}
  10.324 +								break;
  10.325 +							}							
  10.326 +						}
  10.327 +						break;
  10.328 +					case kHIDPage_Button:
  10.329 +						element = (recElement *) NewPtrClear (sizeof (recElement));
  10.330 +						if (element)
  10.331 +						{
  10.332 +							pDevice->buttons++;
  10.333 +							headElement = &(pDevice->firstButton);
  10.334 +						}
  10.335 +						break;
  10.336 +					default:
  10.337 +						break;
  10.338 +				}
  10.339 +			}
  10.340 +		}
  10.341 +		else if (kIOHIDElementTypeCollection == elementType)
  10.342 +			HIDGetCollectionElements ((CFMutableDictionaryRef) refElement, pDevice);
  10.343 +	}
  10.344 +
  10.345 +	if (element && headElement) /* add to list */
  10.346 +	{
  10.347 +		pDevice->elements++;
  10.348 +		if (NULL == *headElement)
  10.349 +			*headElement = element;
  10.350 +		else
  10.351 +		{
  10.352 +			recElement *elementPrevious, *elementCurrent;
  10.353 +			elementCurrent = *headElement;
  10.354 +			while (elementCurrent)
  10.355 +			{
  10.356 +				elementPrevious = elementCurrent;
  10.357 +				elementCurrent = elementPrevious->pNext;
  10.358 +			}
  10.359 +			elementPrevious->pNext = element;
  10.360 +		}
  10.361 +		element->pNext = NULL;
  10.362 +		HIDGetElementInfo (refElement, element);
  10.363 +	}
  10.364 +}
  10.365 +
  10.366 +/* collects information from each array member in device element list (each array memeber = element) */
  10.367 +
  10.368 +static void HIDGetElementsCFArrayHandler (const void * value, void * parameter)
  10.369 +{
  10.370 +	if (CFGetTypeID (value) == CFDictionaryGetTypeID ())
  10.371 +		HIDAddElement ((CFTypeRef) value, (recDevice *) parameter);
  10.372 +}
  10.373 +
  10.374 +/* handles retrieval of element information from arrays of elements in device IO registry information */
  10.375 +
  10.376 +static void HIDGetElements (CFTypeRef refElementCurrent, recDevice *pDevice)
  10.377 +{
  10.378 +	CFTypeID type = CFGetTypeID (refElementCurrent);
  10.379 +	if (type == CFArrayGetTypeID()) /* if element is an array */
  10.380 +	{
  10.381 +		CFRange range = {0, CFArrayGetCount (refElementCurrent)};
  10.382 +		/* CountElementsCFArrayHandler called for each array member */
  10.383 +		CFArrayApplyFunction (refElementCurrent, range, HIDGetElementsCFArrayHandler, pDevice);
  10.384 +	}
  10.385 +}			
  10.386 +
  10.387 +/* handles extracting element information from element collection CF types
  10.388 + * used from top level element decoding and hierarchy deconstruction to flatten device element list
  10.389 + */
  10.390 +
  10.391 +static void HIDGetCollectionElements (CFMutableDictionaryRef deviceProperties, recDevice *pDevice)
  10.392 +{
  10.393 +	CFTypeRef refElementTop = CFDictionaryGetValue (deviceProperties, CFSTR(kIOHIDElementKey));
  10.394 +	if (refElementTop)
  10.395 +		HIDGetElements (refElementTop, pDevice);
  10.396 +}
  10.397 +
  10.398 +/* use top level element usage page and usage to discern device usage page and usage setting appropriate vlaues in device record */
  10.399 +
  10.400 +static void HIDTopLevelElementHandler (const void * value, void * parameter)
  10.401 +{
  10.402 +	CFTypeRef refCF = 0;
  10.403 +	if (CFGetTypeID (value) != CFDictionaryGetTypeID ())
  10.404 +		return;
  10.405 +	refCF = CFDictionaryGetValue (value, CFSTR(kIOHIDElementUsagePageKey));
  10.406 +	if (!CFNumberGetValue (refCF, kCFNumberLongType, &((recDevice *) parameter)->usagePage))
  10.407 +		SDL_SetError ("CFNumberGetValue error retrieving pDevice->usagePage.");
  10.408 +	refCF = CFDictionaryGetValue (value, CFSTR(kIOHIDElementUsageKey));
  10.409 +	if (!CFNumberGetValue (refCF, kCFNumberLongType, &((recDevice *) parameter)->usage))
  10.410 +		SDL_SetError ("CFNumberGetValue error retrieving pDevice->usage.");
  10.411 +}
  10.412 +
  10.413 +/* extracts device info from CF dictionary records in IO registry */
  10.414 +
  10.415 +static void HIDGetDeviceInfo (io_object_t hidDevice, CFMutableDictionaryRef hidProperties, recDevice *pDevice)
  10.416 +{
  10.417 +	CFMutableDictionaryRef usbProperties = 0;
  10.418 +	io_registry_entry_t parent1, parent2;
  10.419 +	
  10.420 +	/* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
  10.421 +	 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
  10.422 +	 */
  10.423 +	if ((KERN_SUCCESS == IORegistryEntryGetParentEntry (hidDevice, kIOServicePlane, &parent1)) &&
  10.424 +		(KERN_SUCCESS == IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2)) &&
  10.425 +		(KERN_SUCCESS == IORegistryEntryCreateCFProperties (parent2, &usbProperties, kCFAllocatorDefault, kNilOptions)))
  10.426 +	{
  10.427 +		if (usbProperties)
  10.428 +		{
  10.429 +			CFTypeRef refCF = 0;
  10.430 +			/* get device info
  10.431 +			 * try hid dictionary first, if fail then go to usb dictionary
  10.432 +			 */
  10.433 +			
  10.434 +			
  10.435 +			/* get product name */
  10.436 +			refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDProductKey));
  10.437 +			if (!refCF)
  10.438 +				refCF = CFDictionaryGetValue (usbProperties, CFSTR("USB Product Name"));
  10.439 +			if (refCF)
  10.440 +			{
  10.441 +				if (!CFStringGetCString (refCF, pDevice->product, 256, CFStringGetSystemEncoding ()))
  10.442 +					SDL_SetError ("CFStringGetCString error retrieving pDevice->product.");
  10.443 +			}
  10.444 +			
  10.445 +			/* get usage page and usage */
  10.446 +			refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey));
  10.447 +			if (refCF)
  10.448 +			{
  10.449 +				if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usagePage))
  10.450 +					SDL_SetError ("CFNumberGetValue error retrieving pDevice->usagePage.");
  10.451 +				refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsageKey));
  10.452 +				if (refCF)
  10.453 +					if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usage))
  10.454 +						SDL_SetError ("CFNumberGetValue error retrieving pDevice->usage.");
  10.455 +			}
  10.456 +
  10.457 +			if (NULL == refCF) /* get top level element HID usage page or usage */
  10.458 +			{
  10.459 +				/* use top level element instead */
  10.460 +				CFTypeRef refCFTopElement = 0;
  10.461 +				refCFTopElement = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDElementKey));
  10.462 +				{
  10.463 +					/* refCFTopElement points to an array of element dictionaries */
  10.464 +					CFRange range = {0, CFArrayGetCount (refCFTopElement)};
  10.465 +					CFArrayApplyFunction (refCFTopElement, range, HIDTopLevelElementHandler, pDevice);
  10.466 +				}
  10.467 +			}
  10.468 +
  10.469 +			CFRelease (usbProperties);
  10.470 +		}
  10.471 +		else
  10.472 +			SDL_SetError ("IORegistryEntryCreateCFProperties failed to create usbProperties.");
  10.473 +
  10.474 +		if (kIOReturnSuccess != IOObjectRelease (parent2))
  10.475 +			SDL_SetError ("IOObjectRelease error with parent2.");
  10.476 +		if (kIOReturnSuccess != IOObjectRelease (parent1))
  10.477 +			SDL_SetError ("IOObjectRelease error with parent1.");
  10.478 +	}
  10.479 +}
  10.480 +
  10.481 +
  10.482 +static recDevice *HIDBuildDevice (io_object_t hidDevice)
  10.483 +{
  10.484 +	recDevice *pDevice = (recDevice *) NewPtrClear (sizeof (recDevice));
  10.485 +	if (pDevice)
  10.486 +	{
  10.487 +		/* get dictionary for HID properties */
  10.488 +		CFMutableDictionaryRef hidProperties = 0;
  10.489 +		kern_return_t result = IORegistryEntryCreateCFProperties (hidDevice, &hidProperties, kCFAllocatorDefault, kNilOptions);
  10.490 +		if ((result == KERN_SUCCESS) && hidProperties)
  10.491 +		{
  10.492 +			/* create device interface */
  10.493 +			result = HIDCreateOpenDeviceInterface (hidDevice, pDevice);
  10.494 +			if (kIOReturnSuccess == result)
  10.495 +			{
  10.496 +				HIDGetDeviceInfo (hidDevice, hidProperties, pDevice); /* hidDevice used to find parents in registry tree */
  10.497 +				HIDGetCollectionElements (hidProperties, pDevice);
  10.498 +			}
  10.499 +			else
  10.500 +			{
  10.501 +				DisposePtr(pDevice);
  10.502 +				pDevice = NULL;
  10.503 +			}
  10.504 +			CFRelease (hidProperties);
  10.505 +		}
  10.506 +		else
  10.507 +		{
  10.508 +			DisposePtr(pDevice);
  10.509 +			pDevice = NULL;
  10.510 +		}
  10.511 +	}
  10.512 +	return pDevice;
  10.513 +}
  10.514 +
  10.515 +/* disposes of the element list associated with a device and the memory associated with the list
  10.516 + */
  10.517 +
  10.518 +static void HIDDisposeElementList (recElement **elementList)
  10.519 +{
  10.520 +	recElement *pElement = *elementList;
  10.521 +	while (pElement)
  10.522 +	{
  10.523 +		recElement *pElementNext = pElement->pNext;
  10.524 +		DisposePtr ((Ptr) pElement);
  10.525 +		pElement = pElementNext;
  10.526 +	}
  10.527 +	*elementList = NULL;
  10.528 +}
  10.529 +
  10.530 +/* disposes of a single device, closing and releaseing interface, freeing memory fro device and elements, setting device pointer to NULL
  10.531 + * all your device no longer belong to us... (i.e., you do not 'own' the device anymore)
  10.532 + */
  10.533 +
  10.534 +static recDevice *HIDDisposeDevice (recDevice **ppDevice)
  10.535 +{
  10.536 +	kern_return_t result = KERN_SUCCESS;
  10.537 +	recDevice *pDeviceNext = NULL;
  10.538 +	if (*ppDevice)
  10.539 +	{
  10.540 +		// save next device prior to disposing of this device
  10.541 +		pDeviceNext = (*ppDevice)->pNext;
  10.542 +		
  10.543 +		/* free element lists */
  10.544 +		HIDDisposeElementList (&(*ppDevice)->firstAxis);
  10.545 +		HIDDisposeElementList (&(*ppDevice)->firstButton);
  10.546 +		HIDDisposeElementList (&(*ppDevice)->firstHat);
  10.547 +		
  10.548 +		result = HIDCloseReleaseInterface (*ppDevice); /* function sanity checks interface value (now application does not own device) */
  10.549 +		if (kIOReturnSuccess != result)
  10.550 +			HIDReportErrorNum ("HIDCloseReleaseInterface failed when trying to dipose device.", result);
  10.551 +		DisposePtr ((Ptr)*ppDevice);
  10.552 +		*ppDevice = NULL;
  10.553 +	}
  10.554 +	return pDeviceNext;
  10.555 +}
  10.556 +
  10.557 +
  10.558 +/* Function to scan the system for joysticks.
  10.559 + * Joystick 0 should be the system default joystick.
  10.560 + * This function should return the number of available joysticks, or -1
  10.561 + * on an unrecoverable fatal error.
  10.562 + */
  10.563 +int SDL_SYS_JoystickInit(void)
  10.564 +{
  10.565 +	IOReturn result = kIOReturnSuccess;
  10.566 +	mach_port_t masterPort = NULL;
  10.567 +	io_iterator_t hidObjectIterator = NULL;
  10.568 +	CFMutableDictionaryRef hidMatchDictionary = NULL;
  10.569 +	recDevice *device, *lastDevice;
  10.570 +	io_object_t ioHIDDeviceObject = NULL;
  10.571 +	UInt32 usagePage = kHIDPage_GenericDesktop;
  10.572 +	UInt32 usage = kHIDUsage_GD_Joystick; /* We probably also should check for gamepads? */
  10.573 +	
  10.574 +	SDL_numjoysticks = 0;
  10.575 +	
  10.576 +	if (NULL != gpDeviceList)
  10.577 +	{
  10.578 +		SDL_SetError("Joystick: Device list already inited.");
  10.579 +		return -1;
  10.580 +	}
  10.581 +	
  10.582 +	result = IOMasterPort (bootstrap_port, &masterPort);
  10.583 +	if (kIOReturnSuccess != result)
  10.584 +	{
  10.585 +		SDL_SetError("Joystick: IOMasterPort error with bootstrap_port.");
  10.586 +		return -1;
  10.587 +	}
  10.588 +
  10.589 +	/* Set up a matching dictionary to search I/O Registry by class name for all HID class devices. */
  10.590 +	hidMatchDictionary = IOServiceMatching (kIOHIDDeviceKey);
  10.591 +	if ((hidMatchDictionary != NULL) && (usagePage) && (usage))
  10.592 +	{
  10.593 +		/* Add key for device type (joystick, in this case) to refine the matching dictionary. */
  10.594 +		CFNumberRef refUsage = NULL, refUsagePage = NULL;
  10.595 +
  10.596 +		refUsage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usagePage);
  10.597 +		CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsageKey), refUsage);
  10.598 +		refUsagePage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usage);
  10.599 +		CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsagePageKey), refUsagePage);
  10.600 +	}
  10.601 +	else
  10.602 +	{
  10.603 +		SDL_SetError("Joystick: Failed to get HID CFMutableDictionaryRef via IOServiceMatching.");
  10.604 +		return -1;
  10.605 +	}
  10.606 +	
  10.607 +	/*/ Now search I/O Registry for matching devices. */
  10.608 +	result = IOServiceGetMatchingServices (masterPort, hidMatchDictionary, &hidObjectIterator);
  10.609 +	/* Check for errors */
  10.610 +	if ((kIOReturnSuccess != result) || (NULL == hidObjectIterator))
  10.611 +	{
  10.612 +		SDL_SetError("Joystick: Couldn't create a HID object iterator.");
  10.613 +		return -1;
  10.614 +	}
  10.615 +	/* IOServiceGetMatchingServices consumes a reference to the dictionary, so we don't need to release the dictionary ref. */
  10.616 +
  10.617 +	/* build flat linked list of devices from device iterator */
  10.618 +
  10.619 +	gpDeviceList = lastDevice = NULL;
  10.620 +	
  10.621 +	while ((ioHIDDeviceObject = IOIteratorNext (hidObjectIterator)))
  10.622 +	{
  10.623 +		/* build a device record */
  10.624 +		device = HIDBuildDevice (ioHIDDeviceObject);
  10.625 +		if (!device)
  10.626 +			continue;
  10.627 +
  10.628 +		/* dump device object, it is no longer needed */
  10.629 +		result = IOObjectRelease (ioHIDDeviceObject);
  10.630 +//		if (KERN_SUCCESS != result)
  10.631 +//			HIDReportErrorNum ("IOObjectRelease error with ioHIDDeviceObject.", result);
  10.632 +		/* Add device to the end of the list */
  10.633 +		if (lastDevice)
  10.634 +			lastDevice->pNext = device;
  10.635 +		else
  10.636 +			gpDeviceList = device;
  10.637 +		lastDevice = device;
  10.638 +	}
  10.639 +	result = IOObjectRelease (hidObjectIterator); /* release the iterator */
  10.640 +
  10.641 +	/* Count the total number of devices we found */
  10.642 +	device = gpDeviceList;
  10.643 +	while (device)
  10.644 +	{
  10.645 +		SDL_numjoysticks++;
  10.646 +		device = device->pNext;
  10.647 +	}
  10.648 +	
  10.649 +	return SDL_numjoysticks;
  10.650 +}
  10.651 +
  10.652 +/* Function to get the device-dependent name of a joystick */
  10.653 +const char *SDL_SYS_JoystickName(int index)
  10.654 +{
  10.655 +	recDevice *device = gpDeviceList;
  10.656 +	
  10.657 +	for (; index > 0; index--)
  10.658 +		device = device->pNext;
  10.659 +
  10.660 +	return device->product;
  10.661 +}
  10.662 +
  10.663 +/* Function to open a joystick for use.
  10.664 + * The joystick to open is specified by the index field of the joystick.
  10.665 + * This should fill the nbuttons and naxes fields of the joystick structure.
  10.666 + * It returns 0, or -1 if there is an error.
  10.667 + */
  10.668 +int SDL_SYS_JoystickOpen(SDL_Joystick *joystick)
  10.669 +{
  10.670 +	recDevice *device = gpDeviceList;
  10.671 +	int index;
  10.672 +	
  10.673 +	for (index = joystick->index; index > 0; index--)
  10.674 +		device = device->pNext;
  10.675 +
  10.676 +	joystick->hwdata = device;
  10.677 +	joystick->name = device->product;
  10.678 +
  10.679 +	joystick->naxes = device->axes;
  10.680 +	joystick->nhats = device->hats;
  10.681 +	joystick->nballs = 0;
  10.682 +	joystick->nbuttons = device->buttons;
  10.683 +
  10.684 +	return 0;
  10.685 +}
  10.686 +
  10.687 +/* Function to update the state of a joystick - called as a device poll.
  10.688 + * This function shouldn't update the joystick structure directly,
  10.689 + * but instead should call SDL_PrivateJoystick*() to deliver events
  10.690 + * and update joystick device state.
  10.691 + */
  10.692 +void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
  10.693 +{
  10.694 +	recDevice *device = joystick->hwdata;
  10.695 +	recElement *element;
  10.696 +	SInt32 value;
  10.697 +	int i;
  10.698 +	
  10.699 +	element = device->firstAxis;
  10.700 +	i = 0;
  10.701 +	while (element)
  10.702 +	{
  10.703 +		value = HIDScaledCalibratedValue(device, element, -32768, 32767);
  10.704 +		if ( value != joystick->axes[i] )
  10.705 +			SDL_PrivateJoystickAxis(joystick, i, value);
  10.706 +		element = element->pNext;
  10.707 +		++i;
  10.708 +	}
  10.709 +	
  10.710 +	element = device->firstButton;
  10.711 +	i = 0;
  10.712 +	while (element)
  10.713 +	{
  10.714 +		value = HIDGetElementValue(device, element);
  10.715 +		if ( value != joystick->buttons[i] )
  10.716 +			SDL_PrivateJoystickButton(joystick, i, value);
  10.717 +		element = element->pNext;
  10.718 +		++i;
  10.719 +	}
  10.720 +	
  10.721 +	element = device->firstHat;
  10.722 +	i = 0;
  10.723 +	while (element)
  10.724 +	{
  10.725 +		Uint8 pos;
  10.726 +
  10.727 +		value = HIDGetElementValue(device, element);
  10.728 +		switch(value)
  10.729 +		{
  10.730 +			case 0:
  10.731 +				pos = SDL_HAT_CENTERED;
  10.732 +				break;
  10.733 +			case 1:
  10.734 +				pos = SDL_HAT_UP;
  10.735 +				break;
  10.736 +			case 2:
  10.737 +				pos = SDL_HAT_RIGHTUP;
  10.738 +				break;
  10.739 +			case 3:
  10.740 +				pos = SDL_HAT_RIGHT;
  10.741 +				break;
  10.742 +			case 4:
  10.743 +				pos = SDL_HAT_RIGHTDOWN;
  10.744 +				break;
  10.745 +			case 5:
  10.746 +				pos = SDL_HAT_DOWN;
  10.747 +				break;
  10.748 +			case 6:
  10.749 +				pos = SDL_HAT_LEFTDOWN;
  10.750 +				break;
  10.751 +			case 7:
  10.752 +				pos = SDL_HAT_LEFT;
  10.753 +				break;
  10.754 +			case 8:
  10.755 +				pos = SDL_HAT_LEFTUP;
  10.756 +				break;
  10.757 +		}
  10.758 +		if ( pos != joystick->hats[i] )
  10.759 +			SDL_PrivateJoystickHat(joystick, i, pos);
  10.760 +		element = element->pNext;
  10.761 +		++i;
  10.762 +	}
  10.763 +	
  10.764 +	return;
  10.765 +}
  10.766 +
  10.767 +/* Function to close a joystick after use */
  10.768 +void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
  10.769 +{
  10.770 +	/* Should we do anything here? */
  10.771 +	return;
  10.772 +}
  10.773 +
  10.774 +/* Function to perform any system-specific joystick related cleanup */
  10.775 +void SDL_SYS_JoystickQuit(void)
  10.776 +{
  10.777 +	while (NULL != gpDeviceList)
  10.778 +		gpDeviceList = HIDDisposeDevice (&gpDeviceList);
  10.779 +}
    11.1 --- a/src/video/quartz/SDL_QuartzEvents.m	Tue Sep 11 18:52:45 2001 +0000
    11.2 +++ b/src/video/quartz/SDL_QuartzEvents.m	Tue Sep 11 19:00:18 2001 +0000
    11.3 @@ -1,37 +1,43 @@
    11.4  /*
    11.5 -    SDL - Simple DirectMedia Layer
    11.6 -    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
    11.7 +	SDL - Simple DirectMedia Layer
    11.8 +	Copyright (C) 1997, 1998, 1999, 2000, 2001	Sam Lantinga
    11.9  
   11.10 -    This library is free software; you can redistribute it and/or
   11.11 -    modify it under the terms of the GNU Library General Public
   11.12 -    License as published by the Free Software Foundation; either
   11.13 -    version 2 of the License, or (at your option) any later version.
   11.14 +	This library is free software; you can redistribute it and/or
   11.15 +	modify it under the terms of the GNU Library General Public
   11.16 +	License as published by the Free Software Foundation; either
   11.17 +	version 2 of the License, or (at your option) any later version.
   11.18  
   11.19 -    This library is distributed in the hope that it will be useful,
   11.20 -    but WITHOUT ANY WARRANTY; without even the implied warranty of
   11.21 -    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   11.22 -    Library General Public License for more details.
   11.23 +	This library is distributed in the hope that it will be useful,
   11.24 +	but WITHOUT ANY WARRANTY; without even the implied warranty of
   11.25 +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   11.26 +	Library General Public License for more details.
   11.27  
   11.28 -    You should have received a copy of the GNU Library General Public
   11.29 -    License along with this library; if not, write to the Free
   11.30 -    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   11.31 +	You should have received a copy of the GNU Library General Public
   11.32 +	License along with this library; if not, write to the Free
   11.33 +	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   11.34  
   11.35 -    Sam Lantinga
   11.36 -    slouken@devolution.com
   11.37 +	Sam Lantinga
   11.38 +	slouken@devolution.com
   11.39  */
   11.40  
   11.41  #include "SDL_QuartzKeys.h"
   11.42  
   11.43 -static int last_virtual_button = 0; // Last virtual mouse button pressed
   11.44 +static SDLKey keymap[256];
   11.45 +static unsigned int currentMods = 0; /* Current keyboard modifiers, to track modifier state */
   11.46 +static int last_virtual_button = 0; /* Last virtual mouse button pressed */
   11.47  
   11.48 -static void  QZ_InitOSKeymap (_THIS) {
   11.49 +static void	 QZ_InitOSKeymap (_THIS) {
   11.50 +	const void *KCHRPtr;
   11.51 +	UInt32 state;
   11.52 +	UInt32 value;
   11.53  	int i;
   11.54 -
   11.55 +	int world = SDLK_WORLD_0;
   11.56 +	
   11.57  	for ( i=0; i<SDL_TABLESIZE(keymap); ++i )
   11.58  		keymap[i] = SDLK_UNKNOWN;
   11.59  
   11.60 -	// This keymap is almost exactly the same as the OS 9 one
   11.61 -        keymap[QZ_ESCAPE] = SDLK_ESCAPE;
   11.62 +	/* This keymap is almost exactly the same as the OS 9 one */
   11.63 +	keymap[QZ_ESCAPE] = SDLK_ESCAPE;
   11.64  	keymap[QZ_F1] = SDLK_F1;
   11.65  	keymap[QZ_F2] = SDLK_F2;
   11.66  	keymap[QZ_F3] = SDLK_F3;
   11.67 @@ -135,261 +141,322 @@
   11.68  	keymap[QZ_IBOOK_ENTER] = SDLK_KP_ENTER;
   11.69  	keymap[QZ_IBOOK_RIGHT] = SDLK_RIGHT;
   11.70  	keymap[QZ_IBOOK_DOWN] = SDLK_DOWN;
   11.71 -	keymap[QZ_IBOOK_UP]   = SDLK_UP;
   11.72 +	keymap[QZ_IBOOK_UP]	  = SDLK_UP;
   11.73  	keymap[QZ_IBOOK_LEFT] = SDLK_LEFT;
   11.74 +	
   11.75 +	/* Up there we setup a static scancode->keysym map. However, it will not
   11.76 +	 * work very well on international keyboard. Hence we now query MacOS
   11.77 +	 * for its own keymap to adjust our own mapping table. However, this is
   11.78 +	 * bascially only useful for ascii char keys. This is also the reason
   11.79 +	 * why we keep the static table, too.
   11.80 +	 */
   11.81 +	
   11.82 +	/* Get a pointer to the systems cached KCHR */
   11.83 +	KCHRPtr = (void *)GetScriptManagerVariable(smKCHRCache);
   11.84 +	if (KCHRPtr)
   11.85 +	{
   11.86 +		/* Loop over all 127 possible scan codes */
   11.87 +		for (i = 0; i < 0x7F; i++)
   11.88 +		{
   11.89 +			/* We pretend a clean start to begin with (i.e. no dead keys active */
   11.90 +			state = 0;
   11.91 +			
   11.92 +			/* Now translate the key code to a key value */
   11.93 +			value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
   11.94 +			
   11.95 +			/* If the state become 0, it was a dead key. We need to translate again,
   11.96 +			passing in the new state, to get the actual key value */
   11.97 +			if (state != 0)
   11.98 +				value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
   11.99 +			
  11.100 +			/* Now we should have an ascii value, or 0. Try to figure out to which SDL symbol it maps */
  11.101 +			if (value >= 128)	 /* Some non-ASCII char, map it to SDLK_WORLD_* */
  11.102 +				keymap[i] = world++;
  11.103 +			else if (value >= 32)	 /* non-control ASCII char */
  11.104 +				keymap[i] = value;
  11.105 +		}
  11.106 +	}
  11.107 +	
  11.108 +	/* The keypad codes are re-setup here, because the loop above cannot
  11.109 +	 * distinguish between a key on the keypad and a regular key. We maybe
  11.110 +	 * could get around this problem in another fashion: NSEvent's flags
  11.111 +	 * include a "NSNumericPadKeyMask" bit; we could check that and modify
  11.112 +	 * the symbol we return on the fly. However, this flag seems to exhibit
  11.113 +	 * some weird behaviour related to the num lock key
  11.114 +	 */
  11.115 +	keymap[QZ_KP0] = SDLK_KP0;
  11.116 +	keymap[QZ_KP1] = SDLK_KP1;
  11.117 +	keymap[QZ_KP2] = SDLK_KP2;
  11.118 +	keymap[QZ_KP3] = SDLK_KP3;
  11.119 +	keymap[QZ_KP4] = SDLK_KP4;
  11.120 +	keymap[QZ_KP5] = SDLK_KP5;
  11.121 +	keymap[QZ_KP6] = SDLK_KP6;
  11.122 +	keymap[QZ_KP7] = SDLK_KP7;
  11.123 +	keymap[QZ_KP8] = SDLK_KP8;
  11.124 +	keymap[QZ_KP9] = SDLK_KP9;
  11.125 +	keymap[QZ_KP_MINUS] = SDLK_KP_MINUS;
  11.126 +	keymap[QZ_KP_PLUS] = SDLK_KP_PLUS;
  11.127 +	keymap[QZ_KP_PERIOD] = SDLK_KP_PERIOD;
  11.128 +	keymap[QZ_KP_EQUALS] = SDLK_KP_EQUALS;
  11.129 +	keymap[QZ_KP_DIVIDE] = SDLK_KP_DIVIDE;
  11.130 +	keymap[QZ_KP_MULTIPLY] = SDLK_KP_MULTIPLY;
  11.131 +	keymap[QZ_KP_ENTER] = SDLK_KP_ENTER;
  11.132  }
  11.133  
  11.134  static void QZ_DoKey (int state, NSEvent *event) {
  11.135  
  11.136 -        NSString *chars;
  11.137 -        int i;
  11.138 -        SDL_keysym key;
  11.139 -        
  11.140 -        /* An event can contain multiple characters */
  11.141 -        /* I'll ignore this fact for now, since there is only one virtual key code per event */
  11.142 -        chars = [ event characters ];
  11.143 -        for (i =0; i < 1 /*[ chars length ] */; i++) {
  11.144 -                    
  11.145 -            key.scancode = [ event keyCode ];
  11.146 -            key.sym      = keymap [ key.scancode ];
  11.147 -            key.unicode  = [ chars characterAtIndex:i];
  11.148 -            key.mod      = KMOD_NONE;
  11.149 -                        
  11.150 -            SDL_PrivateKeyboard (state, &key);
  11.151 -        }
  11.152 +	NSString *chars;
  11.153 +	int i;
  11.154 +	SDL_keysym key;
  11.155 +	
  11.156 +	/* An event can contain multiple characters */
  11.157 +	/* I'll ignore this fact for now, since there is only one virtual key code per event */
  11.158 +	chars = [ event characters ];
  11.159 +	for (i =0; i < 1 /*[ chars length ] */; i++) {
  11.160 +				
  11.161 +		key.scancode = [ event keyCode ];
  11.162 +		key.sym		 = keymap [ key.scancode ];
  11.163 +		key.unicode	 = [ chars characterAtIndex:i];
  11.164 +		key.mod		 = KMOD_NONE;
  11.165 +					
  11.166 +		SDL_PrivateKeyboard (state, &key);
  11.167 +	}
  11.168  }
  11.169  
  11.170  static void QZ_DoModifiers (unsigned int newMods) {
  11.171  
  11.172 -    const int offset = 18;
  11.173 -    const int mapping[] = { SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, 0, SDLK_LMETA } ;
  11.174 +	const int mapping[] = { SDLK_CAPSLOCK, SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA } ;
  11.175  
  11.176 -    int bit;
  11.177 -    SDL_keysym key;
  11.178 -    key.scancode = 0;
  11.179 -    key.sym      = SDLK_UNKNOWN;
  11.180 -    key.unicode  = 0;
  11.181 -    key.mod      = KMOD_NONE;
  11.182 -    
  11.183 -    /* Iterate through the bits, testing each against the current modifiers */
  11.184 -    for (bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1) {
  11.185 -    
  11.186 -        unsigned int currentMask, newMask;
  11.187 -        
  11.188 -        currentMask = currentMods & bit;
  11.189 -        newMask     = newMods & bit;
  11.190 -        
  11.191 -        if ( currentMask && 
  11.192 -             currentMask != newMask ) {  /* modifier up event */
  11.193 +	int i;
  11.194 +	int bit;
  11.195 +	SDL_keysym key;
  11.196  
  11.197 -            key.sym = mapping[ currentMask >> offset ];
  11.198 -            SDL_PrivateKeyboard (SDL_RELEASED, &key);
  11.199 -        }
  11.200 -        else
  11.201 -        if ( newMask &&
  11.202 -             currentMask != newMask ) {  /* modifier down event */
  11.203 -         
  11.204 -            key.sym = mapping [ newMask >> offset ];
  11.205 -            SDL_PrivateKeyboard (SDL_PRESSED, &key);
  11.206 -        }
  11.207 -    }
  11.208 -    
  11.209 -    currentMods = newMods;
  11.210 +	key.scancode = 0;
  11.211 +	key.sym		 = SDLK_UNKNOWN;
  11.212 +	key.unicode	 = 0;
  11.213 +	key.mod		 = KMOD_NONE;
  11.214 +	
  11.215 +	/* Iterate through the bits, testing each against the current modifiers */
  11.216 +	for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
  11.217 +	
  11.218 +		unsigned int currentMask, newMask;
  11.219 +		
  11.220 +		currentMask = currentMods & bit;
  11.221 +		newMask		= newMods & bit;
  11.222 +		
  11.223 +		if ( currentMask &&
  11.224 +			 currentMask != newMask ) {	 /* modifier up event */
  11.225 +
  11.226 +			key.sym = mapping[i];
  11.227 +			/* If this was Caps Lock, we need some additional voodoo to make SDL happy */
  11.228 +			if (bit == NSAlphaShiftKeyMask)
  11.229 +				SDL_PrivateKeyboard (SDL_PRESSED, &key);
  11.230 +			SDL_PrivateKeyboard (SDL_RELEASED, &key);
  11.231 +		}
  11.232 +		else
  11.233 +		if ( newMask &&
  11.234 +			 currentMask != newMask ) {	 /* modifier down event */
  11.235 +		
  11.236 +			key.sym = mapping[i];
  11.237 +			SDL_PrivateKeyboard (SDL_PRESSED, &key);
  11.238 +			/* If this was Caps Lock, we need some additional voodoo to make SDL happy */
  11.239 +			if (bit == NSAlphaShiftKeyMask)
  11.240 +				SDL_PrivateKeyboard (SDL_RELEASED, &key);
  11.241 +		}
  11.242 +	}
  11.243 +	
  11.244 +	currentMods = newMods;
  11.245  }
  11.246  
  11.247  static void QZ_DoActivate (_THIS)
  11.248  {
  11.249 -    inForeground = YES;
  11.250 +	inForeground = YES;
  11.251  
  11.252 -    /* Regrab the mouse */
  11.253 -    if (currentGrabMode == SDL_GRAB_ON) {
  11.254 -        QZ_WarpWMCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2);
  11.255 -        CGAssociateMouseAndMouseCursorPosition (0);
  11.256 -    }
  11.257 +	/* Regrab the mouse */
  11.258 +	if (currentGrabMode == SDL_GRAB_ON) {
  11.259 +		QZ_WarpWMCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2);
  11.260 +		CGAssociateMouseAndMouseCursorPosition (0);
  11.261 +	}
  11.262  
  11.263 -    /* Hide the mouse cursor if inside the app window */
  11.264 -    // FIXME
  11.265 -    if (!QZ_cursor_visible) {
  11.266 -            HideCursor ();
  11.267 -    }
  11.268 -    
  11.269 -    SDL_PrivateAppActive (1, SDL_APPINPUTFOCUS);
  11.270 +	/* Hide the mouse cursor if inside the app window */
  11.271 +	if (!QZ_cursor_visible) {
  11.272 +		HideCursor ();
  11.273 +	}
  11.274 +	
  11.275 +	SDL_PrivateAppActive (1, SDL_APPINPUTFOCUS);
  11.276  }
  11.277  
  11.278  static void QZ_DoDeactivate (_THIS) {
  11.279 -    
  11.280 -    inForeground = NO;
  11.281 +	
  11.282 +	inForeground = NO;
  11.283  
  11.284 -    /* Ungrab mouse if it is grabbed */
  11.285 -    if (currentGrabMode == SDL_GRAB_ON) {
  11.286 -        CGAssociateMouseAndMouseCursorPosition (1);
  11.287 -    }
  11.288 +	/* Ungrab mouse if it is grabbed */
  11.289 +	if (currentGrabMode == SDL_GRAB_ON) {
  11.290 +		CGAssociateMouseAndMouseCursorPosition (1);
  11.291 +	}
  11.292  
  11.293 -    /* Show the mouse cursor */
  11.294 -    // FIXME
  11.295 -    if (!QZ_cursor_visible) {
  11.296 -            ShowCursor ();
  11.297 -    }
  11.298 -    
  11.299 -    SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS);
  11.300 +	/* Show the mouse cursor */
  11.301 +	if (!QZ_cursor_visible) {
  11.302 +		ShowCursor ();
  11.303 +	}
  11.304 +	
  11.305 +	SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS);
  11.306  }
  11.307  
  11.308  static void QZ_PumpEvents (_THIS)
  11.309  {
  11.310 -    NSDate *distantPast;
  11.311 -    NSEvent *event;
  11.312 -    NSRect winRect;
  11.313 -    NSRect titleBarRect;
  11.314 -    NSAutoreleasePool *pool;
  11.315 -    
  11.316 -    distantPast = [ [ NSDate distantPast ] retain ];
  11.317 -    
  11.318 -    pool = [ [ NSAutoreleasePool alloc ] init ];
  11.319 -    
  11.320 -    winRect = NSMakeRect (0, 0, SDL_VideoSurface->w + 1, SDL_VideoSurface->h + 1);
  11.321 -    titleBarRect = NSMakeRect ( 0, SDL_VideoSurface->h, SDL_VideoSurface->w,
  11.322 -        SDL_VideoSurface->h + 22 );
  11.323 -            
  11.324 -    do {
  11.325 -    
  11.326 -        /* Poll for an event. This will not block */
  11.327 -        event = [ NSApp nextEventMatchingMask:NSAnyEventMask
  11.328 -                    untilDate:distantPast
  11.329 -                    inMode: NSDefaultRunLoopMode dequeue:YES ];
  11.330 -    
  11.331 -        if (event != nil) {
  11.332 -            unsigned int type;
  11.333 -            BOOL isForGameWin;
  11.334 +	NSDate *distantPast;
  11.335 +	NSEvent *event;
  11.336 +	NSRect winRect;
  11.337 +	NSRect titleBarRect;
  11.338 +	NSAutoreleasePool *pool;
  11.339 +	
  11.340 +	pool = [ [ NSAutoreleasePool alloc ] init ];
  11.341 +	distantPast = [ NSDate distantPast ];
  11.342 +	
  11.343 +	winRect = NSMakeRect (0, 0, SDL_VideoSurface->w + 1, SDL_VideoSurface->h + 1);
  11.344 +	titleBarRect = NSMakeRect ( 0, SDL_VideoSurface->h, SDL_VideoSurface->w,
  11.345 +		SDL_VideoSurface->h + 22 );
  11.346 +			
  11.347 +	do {
  11.348 +	
  11.349 +		/* Poll for an event. This will not block */
  11.350 +		event = [ NSApp nextEventMatchingMask:NSAnyEventMask
  11.351 +					untilDate:distantPast
  11.352 +					inMode: NSDefaultRunLoopMode dequeue:YES ];
  11.353 +	
  11.354 +		if (event != nil) {
  11.355 +			unsigned int type;
  11.356 +			BOOL isForGameWin;
  11.357  
  11.358 -            #define DO_MOUSE_DOWN(button, sendToWindow) do {                 \
  11.359 -                if ( inForeground ) {                                        \
  11.360 -                    if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) ||       \
  11.361 -                         NSPointInRect([event locationInWindow], winRect) )  \
  11.362 -                        SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);  \
  11.363 -                }                                                            \
  11.364 -                else {                                                       \
  11.365 -                    QZ_DoActivate (this);                                    \
  11.366 -                }                                                            \
  11.367 -                [ NSApp sendEvent:event ];                                   \
  11.368 -                } while(0)
  11.369 -                
  11.370 -            #define DO_MOUSE_UP(button, sendToWindow) do {                   \
  11.371 -                if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) ||           \
  11.372 -                     !NSPointInRect([event locationInWindow], titleBarRect) )\
  11.373 -                    SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);     \
  11.374 -                [ NSApp sendEvent:event ];                                   \
  11.375 -                } while(0)
  11.376 +			#define DO_MOUSE_DOWN(button, sendToWindow) do {				 \
  11.377 +				if ( inForeground ) {										 \
  11.378 +					if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) ||		 \
  11.379 +						 NSPointInRect([event locationInWindow], winRect) )	 \
  11.380 +						SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);	 \
  11.381 +				}															 \
  11.382 +				else {														 \
  11.383 +					QZ_DoActivate (this);									 \
  11.384 +				}															 \
  11.385 +				[ NSApp sendEvent:event ];									 \
  11.386 +				} while(0)
  11.387 +				
  11.388 +			#define DO_MOUSE_UP(button, sendToWindow) do {					 \
  11.389 +				if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) ||			 \
  11.390 +					 !NSPointInRect([event locationInWindow], titleBarRect) )\
  11.391 +					SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);	 \
  11.392 +				[ NSApp sendEvent:event ];									 \
  11.393 +				} while(0)
  11.394  
  11.395 -            type = [ event type ];
  11.396 -            isForGameWin = (qz_window == [ event window ]);
  11.397 -            switch (type) {
  11.398 -            
  11.399 -            case NSLeftMouseDown:  
  11.400 -                if ( NSCommandKeyMask & currentMods ) {
  11.401 -                    last_virtual_button = 3;
  11.402 -                    DO_MOUSE_DOWN (3, 0);
  11.403 -                } 
  11.404 -                else if ( NSAlternateKeyMask & currentMods ) {
  11.405 -                    last_virtual_button = 2;
  11.406 -                    DO_MOUSE_DOWN (2, 0);
  11.407 -                } 
  11.408 -                else {
  11.409 -                    DO_MOUSE_DOWN (1, 1);
  11.410 -                }
  11.411 -                break;
  11.412 -            case 25:               DO_MOUSE_DOWN (2, 0); break;
  11.413 -            case NSRightMouseDown: DO_MOUSE_DOWN (3, 0); break;   
  11.414 -            case NSLeftMouseUp:    
  11.415 -            
  11.416 -                if ( last_virtual_button != 0 ) {
  11.417 -                    DO_MOUSE_UP (last_virtual_button, 0);
  11.418 -                    last_virtual_button = 0;
  11.419 -                }
  11.420 -                else {
  11.421 -                    DO_MOUSE_UP (1, 1);
  11.422 -                }
  11.423 -                break;
  11.424 -            case 26:               DO_MOUSE_UP (2, 0);   break;
  11.425 -            case NSRightMouseUp:   DO_MOUSE_UP (3, 0);   break;
  11.426 -            case NSSystemDefined:
  11.427 -                //if ([event subtype] == 7) {
  11.428 -                //    unsigned int buttons;   // up to 32 mouse button states!
  11.429 -                //    buttons = [ event data2 ];
  11.430 -                //}
  11.431 -                break;
  11.432 -            case NSLeftMouseDragged:
  11.433 -            case NSRightMouseDragged:
  11.434 -            case 27:
  11.435 -            case NSMouseMoved:
  11.436 -                if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN)
  11.437 -                	|| NSPointInRect([event locationInWindow], winRect) )
  11.438 -                {
  11.439 -                   static int moves = 0;
  11.440 -                   NSPoint p;
  11.441 -            
  11.442 -                   if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
  11.443 -                       p = [ NSEvent mouseLocation ];
  11.444 -                       p.y = [[NSScreen mainScreen] frame].size.height - p.y;
  11.445 -                   } else {
  11.446 -            	       p = [ event locationInWindow ];
  11.447 -                       p.y = SDL_VideoSurface->h - p.y;
  11.448 -                   }
  11.449 +			type = [ event type ];
  11.450 +			isForGameWin = (qz_window == [ event window ]);
  11.451 +			switch (type) {
  11.452 +			
  11.453 +			case NSLeftMouseDown:
  11.454 +				if ( NSCommandKeyMask & currentMods ) {
  11.455 +					last_virtual_button = 3;
  11.456 +					DO_MOUSE_DOWN (3, 0);
  11.457 +				}
  11.458 +				else if ( NSAlternateKeyMask & currentMods ) {
  11.459 +					last_virtual_button = 2;
  11.460 +					DO_MOUSE_DOWN (2, 0);
  11.461 +				}
  11.462 +				else {
  11.463 +					DO_MOUSE_DOWN (1, 1);
  11.464 +				}
  11.465 +				break;
  11.466 +			case 25:			   DO_MOUSE_DOWN (2, 0); break;
  11.467 +			case NSRightMouseDown: DO_MOUSE_DOWN (3, 0); break;	
  11.468 +			case NSLeftMouseUp:
  11.469 +			
  11.470 +				if ( last_virtual_button != 0 ) {
  11.471 +					DO_MOUSE_UP (last_virtual_button, 0);
  11.472 +					last_virtual_button = 0;
  11.473 +				}
  11.474 +				else {
  11.475 +					DO_MOUSE_UP (1, 1);
  11.476 +				}
  11.477 +				break;
  11.478 +			case 26:			   DO_MOUSE_UP (2, 0);	 break;
  11.479 +			case NSRightMouseUp:   DO_MOUSE_UP (3, 0);	 break;
  11.480 +			case NSSystemDefined:
  11.481 +				//if ([event subtype] == 7) {
  11.482 +				//	  unsigned int buttons;	  // up to 32 mouse button states!
  11.483 +				//	  buttons = [ event data2 ];
  11.484 +				//}
  11.485 +				break;
  11.486 +			case NSLeftMouseDragged:
  11.487 +			case NSRightMouseDragged:
  11.488 +			case 27:
  11.489 +			case NSMouseMoved:
  11.490 +				if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN)
  11.491 +					|| NSPointInRect([event locationInWindow], winRect) )
  11.492 +				{
  11.493 +				   static int moves = 0;
  11.494 +				   NSPoint p;
  11.495 +			
  11.496 +				   if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
  11.497 +					   p = [ NSEvent mouseLocation ];
  11.498 +					   p.y = [[NSScreen mainScreen] frame].size.height - p.y;
  11.499 +				   } else {
  11.500 +					   p = [ event locationInWindow ];
  11.501 +					   p.y = SDL_VideoSurface->h - p.y;
  11.502 +				   }
  11.503  
  11.504 -                   if ( (moves % 10) == 0 ) {
  11.505 -                        SDL_PrivateMouseMotion (0, 0, p.x, p.y);
  11.506 -                   }
  11.507 -                   else {
  11.508 -                        CGMouseDelta dx, dy;
  11.509 -                        CGGetLastMouseDelta (&dx, &dy);
  11.510 -                        SDL_PrivateMouseMotion (0, 1, dx, dy);
  11.511 -                   }
  11.512 -                   moves++;
  11.513 -                }
  11.514 -                break;
  11.515 -            case NSScrollWheel:
  11.516 -                {
  11.517 -                    if (NSPointInRect([ event locationInWindow ], winRect)) {
  11.518 -                        float dy;
  11.519 -                        dy = [ event deltaY ];
  11.520 -                        if ( dy > 0.0 ) /* Scroll up */
  11.521 -                            SDL_PrivateMouseButton (SDL_PRESSED, 4, 0, 0);
  11.522 -                        else /* Scroll down */
  11.523 -                            SDL_PrivateMouseButton (SDL_PRESSED, 5, 0, 0);
  11.524 -                    }
  11.525 -                }
  11.526 -                break;
  11.527 -            case NSKeyUp:
  11.528 -                QZ_DoKey (SDL_RELEASED, event);
  11.529 -                break;
  11.530 -            case NSKeyDown:
  11.531 -                QZ_DoKey (SDL_PRESSED, event);
  11.532 -                break;
  11.533 -            case NSFlagsChanged:
  11.534 -                QZ_DoModifiers( [ event modifierFlags ] );
  11.535 -                break;
  11.536 -//            case NSMouseEntered: break;
  11.537 -//            case NSMouseExited: break;
  11.538 -            case NSAppKitDefined:
  11.539 -                switch ( [ event subtype ] ) {
  11.540 -                case NSApplicationActivatedEventType:
  11.541 -                    QZ_DoActivate (this);
  11.542 -                    break;
  11.543 -                case NSApplicationDeactivatedEventType:
  11.544 -                    QZ_DoDeactivate (this);
  11.545 -                    break;
  11.546 -                }
  11.547 -                [ NSApp sendEvent:event ];
  11.548 -                break;
  11.549 -//            case NSApplicationDefined: break;
  11.550 -//            case NSPeriodic: break;
  11.551 -//            case NSCursorUpdate: break;
  11.552 -            default:
  11.553 -                [ NSApp sendEvent:event ];
  11.554 -            }
  11.555 -        }
  11.556 -      } while (event != nil);
  11.557 -      
  11.558 -      [ pool release ];
  11.559 -      [ distantPast release ];
  11.560 +				   if ( (moves % 10) == 0 ) {
  11.561 +						SDL_PrivateMouseMotion (0, 0, p.x, p.y);
  11.562 +				   }
  11.563 +				   else {
  11.564 +						CGMouseDelta dx, dy;
  11.565 +						CGGetLastMouseDelta (&dx, &dy);
  11.566 +						SDL_PrivateMouseMotion (0, 1, dx, dy);
  11.567 +				   }
  11.568 +				   moves++;
  11.569 +				}
  11.570 +				break;
  11.571 +			case NSScrollWheel:
  11.572 +				{
  11.573 +					if (NSPointInRect([ event locationInWindow ], winRect)) {
  11.574 +						float dy;
  11.575 +						dy = [ event deltaY ];
  11.576 +						if ( dy > 0.0 ) /* Scroll up */
  11.577 +							SDL_PrivateMouseButton (SDL_PRESSED, 4, 0, 0);
  11.578 +						else /* Scroll down */
  11.579 +							SDL_PrivateMouseButton (SDL_PRESSED, 5, 0, 0);
  11.580 +					}
  11.581 +				}
  11.582 +				break;
  11.583 +			case NSKeyUp:
  11.584 +				QZ_DoKey (SDL_RELEASED, event);
  11.585 +				break;
  11.586 +			case NSKeyDown:
  11.587 +				QZ_DoKey (SDL_PRESSED, event);
  11.588 +				break;
  11.589 +			case NSFlagsChanged:
  11.590 +				QZ_DoModifiers( [ event modifierFlags ] );
  11.591 +				break;
  11.592 +			/* case NSMouseEntered: break; */
  11.593 +			/* case NSMouseExited: break; */
  11.594 +			case NSAppKitDefined:
  11.595 +				switch ( [ event subtype ] ) {
  11.596 +				case NSApplicationActivatedEventType:
  11.597 +					QZ_DoActivate (this);
  11.598 +					break;
  11.599 +				case NSApplicationDeactivatedEventType:
  11.600 +					QZ_DoDeactivate (this);
  11.601 +					break;
  11.602 +				}
  11.603 +				[ NSApp sendEvent:event ];
  11.604 +				break;
  11.605 +			/* case NSApplicationDefined: break; */
  11.606 +			/* case NSPeriodic: break; */
  11.607 +			/* case NSCursorUpdate: break; */
  11.608 +			default:
  11.609 +				[ NSApp sendEvent:event ];
  11.610 +			}
  11.611 +		}
  11.612 +	  } while (event != nil);
  11.613 +	
  11.614 +	  [ pool release ];
  11.615  }
  11.616  
    12.1 --- a/src/video/quartz/SDL_QuartzVideo.m	Tue Sep 11 18:52:45 2001 +0000
    12.2 +++ b/src/video/quartz/SDL_QuartzVideo.m	Tue Sep 11 19:00:18 2001 +0000
    12.3 @@ -25,8 +25,6 @@
    12.4  /* Some variables to share among files, put in device structure eventually */
    12.5  static SDL_GrabMode currentGrabMode = SDL_GRAB_OFF;
    12.6  static BOOL   inForeground = YES;
    12.7 -static SDLKey keymap[256];
    12.8 -static unsigned int currentMods = 0; /* Current keyboard modifiers, to track modifier state */
    12.9  static char QZ_Error[255]; /* Global error buffer to temporarily store more informative error messages */
   12.10  
   12.11  /* Include files into one compile unit...break apart eventually */
    13.1 --- a/test/acinclude.m4	Tue Sep 11 18:52:45 2001 +0000
    13.2 +++ b/test/acinclude.m4	Tue Sep 11 19:00:18 2001 +0000
    13.3 @@ -32,6 +32,7 @@
    13.4       fi
    13.5    fi
    13.6  
    13.7 +  AC_REQUIRE([AC_CANONICAL_TARGET])
    13.8    AC_PATH_PROG(SDL_CONFIG, sdl-config, no)
    13.9    min_sdl_version=ifelse([$1], ,0.11.0,$1)
   13.10    AC_MSG_CHECKING(for SDL - version >= $min_sdl_version)