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