9dc55fb5d416c19b879a0634dc2854e9c1b1e311
[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