4 * Spaceball support for Windows
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
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
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:
21 * The above copyright notice and this permission notice shall be included
22 * in all copies or substantial portions of the Software.
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.
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.
39 #if(_WIN32_WINNT >= 0x0501)
41 #include <GL/freeglut.h>
43 #include "../fg_internal.h"
47 SPNAV_EVENT_MOTION_TRANSLATION,
48 SPNAV_EVENT_MOTION_ROTATION,
49 SPNAV_EVENT_BUTTON /* includes both press and release */
52 extern int fg_sball_initialized;
53 unsigned int __fgSpaceKeystate = 0;
54 RAWINPUTDEVICE __fgSpaceball = { 0x01, 0x08, 0x00, 0x00 };
56 void fgPlatformInitializeSpaceball(void)
59 fg_sball_initialized = 1;
60 if (!fgStructure.CurrentWindow)
62 fg_sball_initialized = 0;
65 hwnd = fgStructure.CurrentWindow->Window.Handle;
69 UINT cbSize = sizeof(__fgSpaceball);
70 __fgSpaceball.hwndTarget = hwnd;
71 ok = RegisterRawInputDevices(&__fgSpaceball, 1, cbSize);
74 __fgSpaceball.hwndTarget = NULL;
75 fg_sball_initialized = 0;
80 void fgPlatformSpaceballClose(void)
85 int fgPlatformHasSpaceball(void)
87 return __fgSpaceball.hwndTarget ? 1 : 0;
90 int fgPlatformSpaceballNumButtons(void)
95 void fgPlatformSpaceballSetWindow(SFG_Window *window)
100 int fgIsSpaceballWinEvent(HWND hwnd, WPARAM wParam, LPARAM lParam)
105 void fgSpaceballHandleWinEvent(HWND hwnd, WPARAM wParam, LPARAM lParam)
107 #define LOGITECH_VENDOR_ID 0x46d
108 HRAWINPUT hRawInput = (HRAWINPUT)lParam;
109 UINT inputCode = (UINT)wParam;
111 BYTE *rawInputBuffer;
114 RID_DEVICE_INFO sRidDeviceInfo;
116 if (!fg_sball_initialized)
118 fgPlatformInitializeSpaceball();
119 if (!fg_sball_initialized)
125 res = GetRawInputData(hRawInput, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
129 rawInputBuffer = malloc(size * sizeof *rawInputBuffer);
130 pRawInput = (PRAWINPUT)rawInputBuffer;
132 res = GetRawInputData(hRawInput, RID_INPUT, pRawInput, &size, sizeof(RAWINPUTHEADER));
135 if (pRawInput->header.dwType != RIM_TYPEHID)
138 sRidDeviceInfo.cbSize = sizeof(RID_DEVICE_INFO);
139 size = sizeof(RID_DEVICE_INFO);
140 res = GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICEINFO, &sRidDeviceInfo, &size);
144 SFG_Window* window = fgWindowByHandle(hwnd);
145 if ((window == NULL))
148 if (sRidDeviceInfo.hid.dwVendorId == LOGITECH_VENDOR_ID)
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]);
160 short Y = -pnData[2];
162 INVOKE_WCB(*window, SpaceMotion, (X, Y, Z));
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));
173 else if (pRawInput->data.hid.bRawData[0] ==
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))
181 for (i = 0; i < 32; i++)
183 unsigned long stateBefore = __fgSpaceKeystate&(1 << i);
184 unsigned long stateNow = dwKeystate&(1 << i);
186 if (stateBefore && !stateNow)
187 INVOKE_WCB(*window, SpaceButton, (stateBefore, GLUT_UP));
188 if (!stateBefore && stateNow)
189 INVOKE_WCB(*window, SpaceButton, (stateNow, GLUT_DOWN));
193 __fgSpaceKeystate = dwKeystate;