update CMake file so that it will generate proper _WIN32_WINNT and WINVER definitions...
[freeglut] / src / mswin / fg_spaceball_mswin.c
1 /*
2  * fg_spaceball_mswin.c
3  *
4  * Spaceball support for Windows
5  * 
6  * Copyright (c) 2012 Stephen J. Baker. All Rights Reserved.
7  * Written by Evan Felix <karcaw at gmail.com>
8  * Creation date: Sat Feb 4, 2012
9  *
10  * Copyright (c) 2014 Jinrong Xie. All Rights Reserved.
11  * Written by Jinrong Xie <stonexjr at gmail.com>
12  * Modification date: Wed Dec 24, 2014
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the "Software"),
16  * to deal in the Software without restriction, including without limitation
17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  * and/or sell copies of the Software, and to permit persons to whom the
19  * Software is furnished to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice shall be included
22  * in all copies or substantial portions of the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
27  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
28  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30  */
31
32 /*
33  * Modified by Jinrong Xie <stonexjr at gmail.com> 12/24/2014
34  * for Space Navigator support on Windows.
35  * This code is enhanced by at least supporting 3Dconnexion's 
36  * six degree of freedom navigator.
37  */
38
39 #if(_WIN32_WINNT >= 0x0501)
40
41 #include <GL/freeglut.h>
42 #include <stdlib.h>
43 #include "../fg_internal.h"
44
45 enum {
46     SPNAV_EVENT_ANY,  
47     SPNAV_EVENT_MOTION_TRANSLATION,
48     SPNAV_EVENT_MOTION_ROTATION,
49     SPNAV_EVENT_BUTTON  /* includes both press and release */
50 };
51
52 extern int sball_initialized;
53 unsigned int __fgSpaceKeystate = 0;
54 RAWINPUTDEVICE __fgSpaceball = { 0x01, 0x08, 0x00, 0x00 };
55
56 void fgPlatformInitializeSpaceball(void)
57 {
58         HWND hwnd;
59         sball_initialized = 1;
60         if (!fgStructure.CurrentWindow)
61         {
62                 sball_initialized = 0;
63                 return;
64         }
65         hwnd = fgStructure.CurrentWindow->Window.Handle;
66
67         BOOL ok;
68         UINT cbSize = sizeof(__fgSpaceball);
69         __fgSpaceball.hwndTarget = hwnd;
70         ok = RegisterRawInputDevices(&__fgSpaceball, 1, cbSize);
71
72         if (!ok){
73                 __fgSpaceball.hwndTarget = NULL;
74                 sball_initialized = 0;
75         }
76 }
77
78 void fgPlatformSpaceballClose(void)
79 {
80         return;
81 }
82
83 int fgPlatformHasSpaceball(void)
84 {
85         return __fgSpaceball.hwndTarget ? 1 : 0;
86 }
87
88 int fgPlatformSpaceballNumButtons(void)
89 {
90         return 0;
91 }
92
93 void fgPlatformSpaceballSetWindow(SFG_Window *window)
94 {
95         return;
96 }
97
98 int fgIsSpaceballWinEvent(HWND hwnd, WPARAM wParam, LPARAM lParam)
99 {
100         return 0;
101 }
102
103 void fgSpaceballHandleWinEvent(HWND hwnd, WPARAM wParam, LPARAM lParam)
104 {
105         #define LOGITECH_VENDOR_ID 0x46d
106         HRAWINPUT hRawInput = (HRAWINPUT)lParam;
107         UINT inputCode = (UINT)wParam;
108         UINT size;
109         BYTE *rawInputBuffer;
110         PRAWINPUT pRawInput;
111         UINT res;
112         RID_DEVICE_INFO sRidDeviceInfo;
113
114         if (!sball_initialized)
115         {
116                 fgPlatformInitializeSpaceball();
117                 if (!sball_initialized)
118                 {
119                         return;
120                 }
121         }
122
123         res = GetRawInputData(hRawInput, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
124         if (res == -1)
125                 return;
126
127         rawInputBuffer = malloc(size * sizeof *rawInputBuffer);
128         pRawInput = (PRAWINPUT)rawInputBuffer;
129
130         res = GetRawInputData(hRawInput, RID_INPUT, pRawInput, &size, sizeof(RAWINPUTHEADER));
131         if (res == -1)
132                 return;
133         if (pRawInput->header.dwType != RIM_TYPEHID)
134                 return;
135
136         sRidDeviceInfo.cbSize = sizeof(RID_DEVICE_INFO);
137         size = sizeof(RID_DEVICE_INFO);
138         res = GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICEINFO, &sRidDeviceInfo, &size);
139         if (res == -1)
140                 return;
141
142         SFG_Window* window = fgWindowByHandle(hwnd);
143         if ((window == NULL))
144                 return;
145
146         if (sRidDeviceInfo.hid.dwVendorId == LOGITECH_VENDOR_ID)
147         {
148                 // Motion data comes in two parts: motion type and 
149                 // displacement/rotation along three axis.
150                 // Orientation is a right handed coordinate system with 
151                 // X goes right, Y goes up and Z goes towards viewer, e.g.
152                 // the one used in OpenGL
153                 if (pRawInput->data.hid.bRawData[0] == 
154                         SPNAV_EVENT_MOTION_TRANSLATION)
155                 { // Translation vector
156                         short* pnData = (short*)(&pRawInput->data.hid.bRawData[1]);
157                         short X =  pnData[0];
158                         short Y = -pnData[2];
159                         short Z =  pnData[1];
160                         INVOKE_WCB(*window, SpaceMotion, (X, Y, Z));
161                 }
162                 else if (pRawInput->data.hid.bRawData[0] == 
163                                 SPNAV_EVENT_MOTION_ROTATION)
164                 { // Axis aligned rotation vector
165                         short* pnData = (short*)(&pRawInput->data.hid.bRawData[1]);
166                         short rX =  pnData[0];
167                         short rY = -pnData[2];
168                         short rZ =  pnData[1];
169                         INVOKE_WCB(*window, SpaceRotation, (rX, rY, rZ));
170                 }
171                 else if (pRawInput->data.hid.bRawData[0] == 
172                                  SPNAV_EVENT_BUTTON)
173                 { // State of the keys
174                         unsigned long dwKeystate = *(unsigned long*)(&pRawInput->data.hid.bRawData[1]);
175                         unsigned int state = GLUT_UP;
176                         if (FETCH_WCB(*window, SpaceButton))
177                         {
178                                 int i;
179                                 for (i = 0; i < 32; i++)
180                                 {
181                                         unsigned long stateBefore = __fgSpaceKeystate&(1 << i);
182                                         unsigned long stateNow = dwKeystate&(1 << i);
183
184                                         if (stateBefore && !stateNow)
185                                                 INVOKE_WCB(*window, SpaceButton, (stateBefore, GLUT_DOWN));
186                                         if (!stateBefore && stateNow)
187                                                 INVOKE_WCB(*window, SpaceButton, (stateNow, GLUT_UP));
188
189                                 }
190                         }
191                         __fgSpaceKeystate = dwKeystate;
192                 }
193         }
194 }
195
196 #endif