0dfa3e932837dc37649a0ed9900f292df26e6fd6
[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         {
68                 BOOL ok;
69                 UINT cbSize = sizeof(__fgSpaceball);
70                 __fgSpaceball.hwndTarget = hwnd;
71                 ok = RegisterRawInputDevices(&__fgSpaceball, 1, cbSize);
72
73                 if (!ok){
74                         __fgSpaceball.hwndTarget = NULL;
75                         sball_initialized = 0;
76                 }
77         }
78 }
79
80 void fgPlatformSpaceballClose(void)
81 {
82         return;
83 }
84
85 int fgPlatformHasSpaceball(void)
86 {
87         return __fgSpaceball.hwndTarget ? 1 : 0;
88 }
89
90 int fgPlatformSpaceballNumButtons(void)
91 {
92         return 0;
93 }
94
95 void fgPlatformSpaceballSetWindow(SFG_Window *window)
96 {
97         return;
98 }
99
100 int fgIsSpaceballWinEvent(HWND hwnd, WPARAM wParam, LPARAM lParam)
101 {
102         return 0;
103 }
104
105 void fgSpaceballHandleWinEvent(HWND hwnd, WPARAM wParam, LPARAM lParam)
106 {
107         #define LOGITECH_VENDOR_ID 0x46d
108         HRAWINPUT hRawInput = (HRAWINPUT)lParam;
109         UINT inputCode = (UINT)wParam;
110         UINT size;
111         BYTE *rawInputBuffer;
112         PRAWINPUT pRawInput;
113         UINT res;
114         RID_DEVICE_INFO sRidDeviceInfo;
115
116         if (!sball_initialized)
117         {
118                 fgPlatformInitializeSpaceball();
119                 if (!sball_initialized)
120                 {
121                         return;
122                 }
123         }
124
125         res = GetRawInputData(hRawInput, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
126         if (res == -1)
127                 return;
128
129         rawInputBuffer = malloc(size * sizeof *rawInputBuffer);
130         pRawInput = (PRAWINPUT)rawInputBuffer;
131
132         res = GetRawInputData(hRawInput, RID_INPUT, pRawInput, &size, sizeof(RAWINPUTHEADER));
133         if (res == -1)
134                 return;
135         if (pRawInput->header.dwType != RIM_TYPEHID)
136                 return;
137
138         sRidDeviceInfo.cbSize = sizeof(RID_DEVICE_INFO);
139         size = sizeof(RID_DEVICE_INFO);
140         res = GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICEINFO, &sRidDeviceInfo, &size);
141         if (res == -1)
142                 return;
143         {
144                 SFG_Window* window = fgWindowByHandle(hwnd);
145                 if ((window == NULL))
146                         return;
147
148                 if (sRidDeviceInfo.hid.dwVendorId == LOGITECH_VENDOR_ID)
149                 {
150                         // Motion data comes in two parts: motion type and 
151                         // displacement/rotation along three axis.
152                         // Orientation is a right handed coordinate system with 
153                         // X goes right, Y goes up and Z goes towards viewer, e.g.
154                         // the one used in OpenGL
155                         if (pRawInput->data.hid.bRawData[0] ==
156                                 SPNAV_EVENT_MOTION_TRANSLATION)
157                         { // Translation vector
158                                 short* pnData = (short*)(&pRawInput->data.hid.bRawData[1]);
159                                 short X = pnData[0];
160                                 short Y = -pnData[2];
161                                 short Z = pnData[1];
162                                 INVOKE_WCB(*window, SpaceMotion, (X, Y, Z));
163                         }
164                         else if (pRawInput->data.hid.bRawData[0] ==
165                                 SPNAV_EVENT_MOTION_ROTATION)
166                         { // Axis aligned rotation vector
167                                 short* pnData = (short*)(&pRawInput->data.hid.bRawData[1]);
168                                 short rX = pnData[0];
169                                 short rY = -pnData[2];
170                                 short rZ = pnData[1];
171                                 INVOKE_WCB(*window, SpaceRotation, (rX, rY, rZ));
172                         }
173                         else if (pRawInput->data.hid.bRawData[0] ==
174                                 SPNAV_EVENT_BUTTON)
175                         { // State of the keys
176                                 unsigned long dwKeystate = *(unsigned long*)(&pRawInput->data.hid.bRawData[1]);
177                                 unsigned int state = GLUT_UP;
178                                 if (FETCH_WCB(*window, SpaceButton))
179                                 {
180                                         int i;
181                                         for (i = 0; i < 32; i++)
182                                         {
183                                                 unsigned long stateBefore = __fgSpaceKeystate&(1 << i);
184                                                 unsigned long stateNow = dwKeystate&(1 << i);
185
186                                                 if (stateBefore && !stateNow)
187                                                         INVOKE_WCB(*window, SpaceButton, (stateBefore, GLUT_UP));
188                                                 if (!stateBefore && stateNow)
189                                                         INVOKE_WCB(*window, SpaceButton, (stateNow, GLUT_DOWN));
190
191                                         }
192                                 }
193                                 __fgSpaceKeystate = dwKeystate;
194                         }
195                 }
196         }
197 }
198
199 #endif