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