Fixing the "glutGetProcAddress" snafu -- thank you, Evan Felix, for finding this
[freeglut] / src / mswin / freeglut_joystick_mswin.c
1 /*\r
2  * freeglut_joystick_mswin.c\r
3  *\r
4  * The Windows-specific mouse cursor related stuff.\r
5  *\r
6  * Copyright (c) 2012 Stephen J. Baker. All Rights Reserved.\r
7  * Written by John F. Fay, <fayjf@sourceforge.net>\r
8  * Creation date: Sat Jan 28, 2012\r
9  *\r
10  * Permission is hereby granted, free of charge, to any person obtaining a\r
11  * copy of this software and associated documentation files (the "Software"),\r
12  * to deal in the Software without restriction, including without limitation\r
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
14  * and/or sell copies of the Software, and to permit persons to whom the\r
15  * Software is furnished to do so, subject to the following conditions:\r
16  *\r
17  * The above copyright notice and this permission notice shall be included\r
18  * in all copies or substantial portions of the Software.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\r
23  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
26  */\r
27 \r
28 #include <GL/freeglut.h>\r
29 #include "../Common/freeglut_internal.h"\r
30 \r
31 \r
32 #if !defined(_WIN32_WCE)\r
33 #    include <windows.h>\r
34 #    include <mmsystem.h>\r
35 #    include <regstr.h>\r
36 \r
37 \r
38 \r
39 \r
40 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )\r
41 {\r
42     MMRESULT status;\r
43 \r
44     status = joyGetPosEx( joy->pJoystick.js_id, &joy->pJoystick.js );\r
45 \r
46     if ( status != JOYERR_NOERROR )\r
47     {\r
48         joy->error = GL_TRUE;\r
49         return;\r
50     }\r
51 \r
52     if ( buttons )\r
53         *buttons = joy->pJoystick.js.dwButtons;\r
54 \r
55     if ( axes )\r
56     {\r
57         /*\r
58          * WARNING - Fall through case clauses!!\r
59          */\r
60         switch ( joy->num_axes )\r
61         {\r
62         case 8:\r
63             /* Generate two POV axes from the POV hat angle.\r
64              * Low 16 bits of js.dwPOV gives heading (clockwise from ahead) in\r
65              *   hundredths of a degree, or 0xFFFF when idle.\r
66              */\r
67             if ( ( joy->pJoystick.js.dwPOV & 0xFFFF ) == 0xFFFF )\r
68             {\r
69               axes [ 6 ] = 0.0;\r
70               axes [ 7 ] = 0.0;\r
71             }\r
72             else\r
73             {\r
74               /* This is the contentious bit: how to convert angle to X/Y.\r
75                *    wk: I know of no define for PI that we could use here:\r
76                *    SG_PI would pull in sg, M_PI is undefined for MSVC\r
77                * But the accuracy of the value of PI is very unimportant at\r
78                * this point.\r
79                */\r
80               float s = (float) sin ( ( joy->pJoystick.js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );\r
81               float c = (float) cos ( ( joy->pJoystick.js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );\r
82 \r
83               /* Convert to coordinates on a square so that North-East\r
84                * is (1,1) not (.7,.7), etc.\r
85                * s and c cannot both be zero so we won't divide by zero.\r
86                */\r
87               if ( fabs ( s ) < fabs ( c ) )\r
88               {\r
89                 axes [ 6 ] = ( c < 0.0 ) ? -s/c  : s/c ;\r
90                 axes [ 7 ] = ( c < 0.0 ) ? -1.0f : 1.0f;\r
91               }\r
92               else\r
93               {\r
94                 axes [ 6 ] = ( s < 0.0 ) ? -1.0f : 1.0f;\r
95                 axes [ 7 ] = ( s < 0.0 ) ? -c/s  : c/s ;\r
96               }\r
97             }\r
98 \r
99         case 6: axes[5] = (float) joy->pJoystick.js.dwVpos;\r
100         case 5: axes[4] = (float) joy->pJoystick.js.dwUpos;\r
101         case 4: axes[3] = (float) joy->pJoystick.js.dwRpos;\r
102         case 3: axes[2] = (float) joy->pJoystick.js.dwZpos;\r
103         case 2: axes[1] = (float) joy->pJoystick.js.dwYpos;\r
104         case 1: axes[0] = (float) joy->pJoystick.js.dwXpos;\r
105         }\r
106     }\r
107 }\r
108 \r
109 \r
110 \r
111 /* Inspired by\r
112    http://msdn.microsoft.com/archive/en-us/dnargame/html/msdn_sidewind3d.asp\r
113  */\r
114 #  if FREEGLUT_LIB_PRAGMAS\r
115 #      pragma comment (lib, "advapi32.lib")\r
116 #  endif\r
117 \r
118 static int fghJoystickGetOEMProductName ( SFG_Joystick* joy, char *buf, int buf_sz )\r
119 {\r
120     char buffer [ 256 ];\r
121 \r
122     char OEMKey [ 256 ];\r
123 \r
124     HKEY  hKey;\r
125     DWORD dwcb;\r
126     LONG  lr;\r
127 \r
128     if ( joy->error )\r
129         return 0;\r
130 \r
131     /* Open .. MediaResources\CurrentJoystickSettings */\r
132     _snprintf ( buffer, sizeof(buffer), "%s\\%s\\%s",\r
133                 REGSTR_PATH_JOYCONFIG, joy->pJoystick.jsCaps.szRegKey,\r
134                 REGSTR_KEY_JOYCURR );\r
135 \r
136     lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);\r
137 \r
138     if ( lr != ERROR_SUCCESS ) return 0;\r
139 \r
140     /* Get OEM Key name */\r
141     dwcb = sizeof(OEMKey);\r
142 \r
143     /* JOYSTICKID1-16 is zero-based; registry entries for VJOYD are 1-based. */\r
144     _snprintf ( buffer, sizeof(buffer), "Joystick%d%s", joy->pJoystick.js_id + 1, REGSTR_VAL_JOYOEMNAME );\r
145 \r
146     lr = RegQueryValueEx ( hKey, buffer, 0, 0, (LPBYTE) OEMKey, &dwcb);\r
147     RegCloseKey ( hKey );\r
148 \r
149     if ( lr != ERROR_SUCCESS ) return 0;\r
150 \r
151     /* Open OEM Key from ...MediaProperties */\r
152     _snprintf ( buffer, sizeof(buffer), "%s\\%s", REGSTR_PATH_JOYOEM, OEMKey );\r
153 \r
154     lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey );\r
155 \r
156     if ( lr != ERROR_SUCCESS ) return 0;\r
157 \r
158     /* Get OEM Name */\r
159     dwcb = buf_sz;\r
160 \r
161     lr = RegQueryValueEx ( hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buf,\r
162                              &dwcb );\r
163     RegCloseKey ( hKey );\r
164 \r
165     if ( lr != ERROR_SUCCESS ) return 0;\r
166 \r
167     return 1;\r
168 }\r
169 \r
170 \r
171 void fgPlatformJoystickOpen( SFG_Joystick* joy )\r
172 {\r
173         int i = 0;\r
174 \r
175     joy->pJoystick.js.dwFlags = JOY_RETURNALL;\r
176     joy->pJoystick.js.dwSize  = sizeof( joy->pJoystick.js );\r
177 \r
178     memset( &joy->pJoystick.jsCaps, 0, sizeof( joy->pJoystick.jsCaps ) );\r
179 \r
180     joy->error =\r
181         ( joyGetDevCaps( joy->pJoystick.js_id, &joy->pJoystick.jsCaps, sizeof( joy->pJoystick.jsCaps ) ) !=\r
182           JOYERR_NOERROR );\r
183 \r
184     if( joy->pJoystick.jsCaps.wNumAxes == 0 )\r
185     {\r
186         joy->num_axes = 0;\r
187         joy->error = GL_TRUE;\r
188     }\r
189     else\r
190     {\r
191         /* Device name from jsCaps is often "Microsoft PC-joystick driver",\r
192          * at least for USB.  Try to get the real name from the registry.\r
193          */\r
194         if ( ! fghJoystickGetOEMProductName( joy, joy->name,\r
195                                              sizeof( joy->name ) ) )\r
196         {\r
197             fgWarning( "JS: Failed to read joystick name from registry" );\r
198             strncpy( joy->name, joy->pJoystick.jsCaps.szPname, sizeof( joy->name ) );\r
199         }\r
200 \r
201         /* Windows joystick drivers may provide any combination of\r
202          * X,Y,Z,R,U,V,POV - not necessarily the first n of these.\r
203          */\r
204         if( joy->pJoystick.jsCaps.wCaps & JOYCAPS_HASPOV )\r
205         {\r
206             joy->num_axes = _JS_MAX_AXES;\r
207             joy->min[ 7 ] = -1.0; joy->max[ 7 ] = 1.0;  /* POV Y */\r
208             joy->min[ 6 ] = -1.0; joy->max[ 6 ] = 1.0;  /* POV X */\r
209         }\r
210         else\r
211             joy->num_axes = 6;\r
212 \r
213         joy->min[ 5 ] = ( float )joy->pJoystick.jsCaps.wVmin;\r
214         joy->max[ 5 ] = ( float )joy->pJoystick.jsCaps.wVmax;\r
215         joy->min[ 4 ] = ( float )joy->pJoystick.jsCaps.wUmin;\r
216         joy->max[ 4 ] = ( float )joy->pJoystick.jsCaps.wUmax;\r
217         joy->min[ 3 ] = ( float )joy->pJoystick.jsCaps.wRmin;\r
218         joy->max[ 3 ] = ( float )joy->pJoystick.jsCaps.wRmax;\r
219         joy->min[ 2 ] = ( float )joy->pJoystick.jsCaps.wZmin;\r
220         joy->max[ 2 ] = ( float )joy->pJoystick.jsCaps.wZmax;\r
221         joy->min[ 1 ] = ( float )joy->pJoystick.jsCaps.wYmin;\r
222         joy->max[ 1 ] = ( float )joy->pJoystick.jsCaps.wYmax;\r
223         joy->min[ 0 ] = ( float )joy->pJoystick.jsCaps.wXmin;\r
224         joy->max[ 0 ] = ( float )joy->pJoystick.jsCaps.wXmax;\r
225     }\r
226 \r
227     /* Guess all the rest judging on the axes extremals */\r
228     for( i = 0; i < joy->num_axes; i++ )\r
229     {\r
230         joy->center   [ i ] = ( joy->max[ i ] + joy->min[ i ] ) * 0.5f;\r
231         joy->dead_band[ i ] = 0.0f;\r
232         joy->saturate [ i ] = 1.0f;\r
233     }\r
234 }\r
235 \r
236 \r
237 \r
238 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )\r
239 {\r
240     switch( ident )\r
241     {\r
242     case 0:\r
243         fgJoystick[ ident ]->pJoystick.js_id = JOYSTICKID1;\r
244         fgJoystick[ ident ]->error = GL_FALSE;\r
245         break;\r
246     case 1:\r
247         fgJoystick[ ident ]->pJoystick.js_id = JOYSTICKID2;\r
248         fgJoystick[ ident ]->error = GL_FALSE;\r
249         break;\r
250     default:\r
251         fgJoystick[ ident ]->num_axes = 0;\r
252         fgJoystick[ ident ]->error = GL_TRUE;\r
253         return;\r
254     }\r
255 }\r
256 \r
257 \r
258 \r
259 void fgPlatformJoystickClose ( int ident )\r
260 {\r
261     /* Do nothing special */\r
262 }\r
263 #endif\r
264 \r