Blender V5.0
GHOST_NDOFManager.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2007-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6#include "GHOST_Debug.hh"
7#include "GHOST_EventKey.hh"
8#include "GHOST_EventNDOF.hh"
9#include "GHOST_Types.h"
11#include "GHOST_utildefines.hh"
12
13#include "CLG_log.h"
14
15#include <algorithm>
16#include <array>
17#include <climits>
18#include <cmath>
19#include <cstring> /* For memory functions. */
20#include <map>
21
22static CLG_LogRef LOG = {"ghost.ndof"};
23
28// #define USE_3DCONNEXION_NONSTANDARD_KEYS
29
30/* -------------------------------------------------------------------- */
33
34/* Printable values for #GHOST_TProgress enum (keep aligned). */
35static const char *ndof_progress_string[] = {
36 "not started",
37 "starting",
38 "in progress",
39 "finishing",
40 "finished",
41};
42
43/* Printable values for #NDOF_ButtonT enum (keep aligned) */
44#define MAP_ENTRY(button) {GHOST_##button, #button}
45static const std::map<GHOST_NDOF_ButtonT, const char *> ndof_button_names = {
46 /* Disable wrapping, it makes it difficult to read. */
47 /* clang-format off */
48 MAP_ENTRY(NDOF_BUTTON_INVALID),
77 MAP_ENTRY(NDOF_BUTTON_ESC),
78 MAP_ENTRY(NDOF_BUTTON_ALT),
79 MAP_ENTRY(NDOF_BUTTON_SHIFT),
80 MAP_ENTRY(NDOF_BUTTON_CTRL),
81 MAP_ENTRY(NDOF_BUTTON_ENTER),
82 MAP_ENTRY(NDOF_BUTTON_DELETE),
83 MAP_ENTRY(NDOF_BUTTON_TAB),
84 MAP_ENTRY(NDOF_BUTTON_SPACE),
96 MAP_ENTRY(NDOF_BUTTON_KBP_F1),
97 MAP_ENTRY(NDOF_BUTTON_KBP_F2),
98 MAP_ENTRY(NDOF_BUTTON_KBP_F3),
99 MAP_ENTRY(NDOF_BUTTON_KBP_F4),
100 MAP_ENTRY(NDOF_BUTTON_KBP_F5),
101 MAP_ENTRY(NDOF_BUTTON_KBP_F6),
102 MAP_ENTRY(NDOF_BUTTON_KBP_F7),
103 MAP_ENTRY(NDOF_BUTTON_KBP_F8),
104 MAP_ENTRY(NDOF_BUTTON_KBP_F9),
105 MAP_ENTRY(NDOF_BUTTON_KBP_F10),
106 MAP_ENTRY(NDOF_BUTTON_KBP_F11),
107 MAP_ENTRY(NDOF_BUTTON_KBP_F12),
108 MAP_ENTRY(NDOF_BUTTON_NP_F1),
109 MAP_ENTRY(NDOF_BUTTON_NP_F2),
110 MAP_ENTRY(NDOF_BUTTON_NP_F3),
111 MAP_ENTRY(NDOF_BUTTON_NP_F4),
112 /* clang-format on */
113};
114#undef MAP_ENTRY
115
116static const char *ndof_device_names[] = {
117 "UnknownDevice",
118 "SpaceNavigator",
119 "SpaceExplorer",
120 "SpacePilotPro",
121 "SpaceMousePro",
122 "SpaceMouseWireless",
123 "SpaceMouseProWireless",
124 "SpaceMouseEnterprise",
125 "SpacePilot",
126 "Spaceball5000",
127 "SpaceTraveler",
128 "Keyboard Pro",
129 "Numpad Pro",
130};
131
133
134/* -------------------------------------------------------------------- */
137
156
174
175/* This is the older SpacePilot (sans Pro). */
189
201
202
203/* -------------------------------------------------------------------- */
206
208
210 : system_(sys),
211 device_type_(NDOF_UnknownDevice), /* Each platform has its own device detection code. */
212 hid_map_button_num_(genericButtonCount),
213 hid_map_button_mask_(0),
214 hid_map_(ndof_HID_map_Generic),
215 button_depressed_(0),
216 pressed_buttons_cache_(),
217 pressed_long_buttons_cache_(),
218 motion_time_(0),
219 motion_time_prev_(0),
220 motion_state_(GHOST_kNotStarted),
221 motion_event_pending_(false),
222 motion_dead_zone_(0.0f)
223{
224 /* To avoid the rare situation where one triple is updated and
225 * the other is not, initialize them both here: */
226 memset(translation_, 0, sizeof(translation_));
227 memset(rotation_, 0, sizeof(rotation_));
228}
229
231
232/* -------------------------------------------------------------------- */
235
236bool GHOST_NDOFManager::setDevice(ushort vendor_id, ushort product_id)
237{
238 /* Call this function until it returns true
239 * it's a good idea to stop calling it after that, as it will "forget"
240 * whichever device it already found. */
241
242 /* Default to safe generic behavior for "unknown" devices
243 * unidentified devices will emit motion events like normal
244 * rogue buttons do nothing by default, but can be customized by the user. */
245
246 device_type_ = NDOF_UnknownDevice;
247 hid_map_ = ndof_HID_map_Generic;
248 hid_map_button_num_ = genericButtonCount;
249 hid_map_button_mask_ = 0;
250
251 /* "mystery device" owners can help build a HID_map for their hardware
252 * A few users have already contributed information about several older devices
253 * that I don't have access to. Thanks! */
254
255 switch (vendor_id) {
256 case 0x046D: /* Logitech (3Dconnexion was a subsidiary). */
257 switch (product_id) {
258 /* -- current devices -- */
259 case 0xC626: /* Full-size SpaceNavigator. */
260 case 0xC628: /* The "for Notebooks" one. */
261 {
262 device_type_ = NDOF_SpaceNavigator;
263 hid_map_button_num_ = 2;
264 hid_map_ = ndof_HID_map_Shared3Dx;
265 break;
266 }
267 case 0xC627: {
268 device_type_ = NDOF_SpaceExplorer;
269 hid_map_button_num_ = 15;
271 break;
272 }
273 case 0xC629: {
274 device_type_ = NDOF_SpacePilotPro;
275 hid_map_button_num_ = 31;
276 hid_map_ = ndof_HID_map_Shared3Dx;
277 break;
278 }
279 case 0xC62B: {
280 device_type_ = NDOF_SpaceMousePro;
281 hid_map_button_num_ = 27; /* 15 physical buttons, but HID codes range from 0 to 26. */
282 hid_map_button_mask_ = 0x07C0F137;
283 hid_map_ = ndof_HID_map_Shared3Dx;
284 break;
285 }
286
287 /* -- older devices -- */
288 case 0xC625: {
289 device_type_ = NDOF_SpacePilot;
290 hid_map_button_num_ = 21;
291 hid_map_ = ndof_HID_map_SpacePilot;
292 break;
293 }
294 case 0xC621: {
295 device_type_ = NDOF_Spaceball5000;
296 hid_map_button_num_ = 12;
297 break;
298 }
299 case 0xC623: {
300 device_type_ = NDOF_SpaceTraveler;
301 hid_map_button_num_ = 8;
302 break;
303 }
304 default: {
305 CLOG_INFO(&LOG, "Unknown Logitech product %04hx", product_id);
306 }
307 }
308 break;
309 case 0x256F: /* 3Dconnexion. */
310 switch (product_id) {
311 case 0xC62E: /* SpaceMouse Wireless (cabled). */
312 case 0xC62F: /* SpaceMouse Wireless Receiver. */
313 case 0xC658: /* Wireless (3DConnexion Universal Wireless Receiver in WIN32), see #82412. */
314 {
315 device_type_ = NDOF_SpaceMouseWireless;
316 hid_map_button_num_ = 2;
317 hid_map_ = ndof_HID_map_Shared3Dx;
318 break;
319 }
320 case 0xC631: /* SpaceMouse Pro Wireless (cabled). */
321 case 0xC632: /* SpaceMouse Pro Wireless Receiver. */
322 case 0xC638: /* SpaceMouse Pro Wireless BT (cabled), see #116393.
323 * 3Dconnexion docs describe this as "Wireless BT", but it is cabled. */
324 case 0xC652: /* Universal Receiver. */
325 {
326 device_type_ = NDOF_SpaceMouseProWireless;
327 hid_map_button_num_ = 27; /* 15 physical buttons, but HID codes range from 0 to 26. */
328 hid_map_button_mask_ = 0x07C0F137;
329 hid_map_ = ndof_HID_map_Shared3Dx;
330 break;
331 }
332 case 0xC633: /* Newer devices don't need to use button mappings. */
333 {
334 device_type_ = NDOF_SpaceMouseEnterprise;
335 break;
336 }
337 case 0xC664:
338 case 0xC668: {
339 device_type_ = NDOF_KeyboardPro;
340 break;
341 }
342 case 0xC665: {
343 device_type_ = NDOF_NumpadPro;
344 break;
345 }
346 default: {
347 CLOG_INFO(&LOG, "Unknown 3Dconnexion product %04hx", product_id);
348 }
349 }
350 break;
351 default:
352 CLOG_INFO(&LOG, "Unknown device %04hx:%04hx", vendor_id, product_id);
353 }
354
355 if (device_type_ != NDOF_UnknownDevice) {
356 CLOG_INFO(&LOG, "Using %s", ndof_device_names[device_type_]);
357 }
358
359 if (hid_map_button_mask_ == 0) {
360 hid_map_button_mask_ = int(~(UINT_MAX << hid_map_button_num_));
361 }
362
363 CLOG_DEBUG(&LOG, "Device %d buttons -> hex:%X", hid_map_button_num_, uint(hid_map_button_mask_));
364
365 return device_type_ != NDOF_UnknownDevice;
366}
367
369
370/* -------------------------------------------------------------------- */
373
375{
376 memcpy(translation_, t, sizeof(translation_));
377 motion_time_ = time;
378 motion_event_pending_ = true;
379}
380
382{
383 memcpy(rotation_, r, sizeof(rotation_));
384 motion_time_ = time;
385 motion_event_pending_ = true;
386}
387
389
390/* -------------------------------------------------------------------- */
393
395{
396 switch (button) {
398 return GHOST_kKeyEsc;
399 }
401 return GHOST_kKeyEnter;
402 }
404 return GHOST_kKeyDelete;
405 }
407 return GHOST_kKeyTab;
408 }
410 return GHOST_kKeySpace;
411 }
413 return GHOST_kKeyLeftAlt;
414 }
416 return GHOST_kKeyLeftShift;
417 }
420 }
421
422#ifdef USE_3DCONNEXION_NONSTANDARD_KEYS
425 return GHOST_kKeyF1;
426 }
429 return GHOST_kKeyF2;
430 }
433 return GHOST_kKeyF3;
434 }
437 return GHOST_kKeyF4;
438 }
440 return GHOST_kKeyF5;
441 }
443 return GHOST_kKeyF6;
444 }
446 return GHOST_kKeyF7;
447 }
449 return GHOST_kKeyF8;
450 }
452 return GHOST_kKeyF9;
453 }
455 return GHOST_kKeyF10;
456 }
458 return GHOST_kKeyF11;
459 }
461 return GHOST_kKeyF12;
462 }
463#endif /* !USE_3DCONNEXION_NONSTANDARD_KEYS */
464
465 default: {
466 return GHOST_kKeyUnknown;
467 }
468 }
469}
470
471void GHOST_NDOFManager::sendButtonEvent(GHOST_NDOF_ButtonT button,
472 bool press,
473 uint64_t time,
474 GHOST_IWindow *window)
475{
477 "rogue button trying to escape GHOST_NDOF manager");
478
479 const GHOST_EventNDOFButton *event = new GHOST_EventNDOFButton(time, window);
480 GHOST_TEventNDOFButtonData *data = (GHOST_TEventNDOFButtonData *)event->getData();
481
482 data->action = press ? GHOST_kPress : GHOST_kRelease;
483 data->button = button;
484
485 system_.pushEvent(event);
486}
487
488void GHOST_NDOFManager::sendKeyEvent(GHOST_TKey key,
489 bool press,
490 uint64_t time,
491 GHOST_IWindow *window)
492{
494 const GHOST_EventKey *event = new GHOST_EventKey(time, type, window, key, false);
495
496 system_.pushEvent(event);
497}
498
500{
501 if (button == GHOST_NDOF_BUTTON_INVALID) {
503 &LOG, "Update button=%d, press=%d (mapped to none, ignoring!)", int(button), int(press));
504 return;
505 }
506
508 "Update button=%d, press=%d, name=%s",
509 button,
510 int(press),
511 ndof_button_names.at(button));
512
513#ifndef USE_3DCONNEXION_NONSTANDARD_KEYS
514 if (((button >= GHOST_NDOF_BUTTON_KBP_F1) && (button <= GHOST_NDOF_BUTTON_KBP_F12)) ||
515 ((button >= GHOST_NDOF_BUTTON_NP_F1) && (button <= GHOST_NDOF_BUTTON_NP_F4)))
516 {
517 return;
518 }
519#endif /* !USE_3DCONNEXION_NONSTANDARD_KEYS */
520
521 GHOST_IWindow *window = system_.getWindowManager()->getActiveWindow();
522
523 /* Delivery will fail, so don't bother sending. */
524 if (window != nullptr) {
526 if (key != GHOST_kKeyUnknown) {
527 sendKeyEvent(key, press, time, window);
528 }
529 else {
530 sendButtonEvent(button, press, time, window);
531 }
532 }
533}
534
535void GHOST_NDOFManager::updateButtonRAW(int button_number, bool press, uint64_t time)
536{
537 GHOST_NDOF_ButtonT button;
538
539 /* For bit-mask devices button mapping isn't unified, therefore check the button map. */
540 if (std::find(bitmask_devices_.begin(), bitmask_devices_.end(), device_type_) !=
541 bitmask_devices_.end())
542 {
543 if (button_number >= hid_map_button_num_) {
545 &LOG, "Update button=%d, press=%d (out of range, ignoring!)", button_number, int(press));
546 return;
547 }
548 button = hid_map_[button_number];
549 }
550 else {
551 button = static_cast<GHOST_NDOF_ButtonT>(button_number);
552 }
553
554 GHOST_NDOFManager::updateButton(button, press, time);
555}
556
558{
559 /* Some devices send two data packets: bitmask and number array.
560 * In this case, packet has to be ignored if it came from such a device. */
561 if (std::find(bitmask_devices_.begin(), bitmask_devices_.end(), device_type_) ==
562 bitmask_devices_.end())
563 {
564 return;
565 }
566
567 button_bits &= hid_map_button_mask_; /* Discard any "garbage" bits. */
568
569 int diff = button_depressed_ ^ button_bits;
570
571 for (int button_number = 0; button_number < hid_map_button_num_; ++button_number) {
572 int mask = 1 << button_number;
573
574 if (diff & mask) {
575 bool press = button_bits & mask;
576
577 if (press) {
578 button_depressed_ |= mask; /* Set this button's bit. */
579 }
580 else {
581 button_depressed_ &= ~mask; /* Clear this button's bit. */
582 }
583
584 /* Bitmask devices don't have unified keymaps, so button numbers needs to be looked up in the
585 * map. */
586 const GHOST_NDOF_ButtonT button = hid_map_[button_number];
587 updateButton(button, press, time);
588 }
589 }
590}
591
593 uint64_t time,
594 NDOF_Button_Type type)
595{
596 NDOF_Button_Array &cache = (type == NDOF_Button_Type::LongButton) ? pressed_long_buttons_cache_ :
597 pressed_buttons_cache_;
598
599 /* Find released buttons */
600 for (const auto &cached_button : cache) {
601 bool found = false;
602 for (const auto &button : buttons) {
603 if (button == cached_button) {
604 found = true;
605 break;
606 }
607 }
608
609 if (!found) {
610 updateButton(cached_button, false, time);
611 }
612 }
613
614 /* Find pressed buttons */
615 for (const auto &button : buttons) {
616 bool found = false;
617 for (const auto &cached_button : cache) {
618 if (button == cached_button) {
619 found = true;
620 break;
621 }
622 }
623
624 if (!found) {
625 updateButton(button, true, time);
626 }
627 }
628 cache = buttons;
629}
630
632
633/* -------------------------------------------------------------------- */
636
638{
639 /* Negative values don't make sense, so clamp at zero. */
640 dz = std::max(dz, 0.0f);
641 motion_dead_zone_ = dz;
642
643 /* Warn the rogue user/developer about high dead-zone, but allow it. */
644 CLOG_INFO(&LOG, "Dead zone set to %.2f%s", dz, (dz > 0.5f) ? " (unexpectedly high)" : "");
645}
646
647static bool atHomePosition(const GHOST_TEventNDOFMotionData *ndof)
648{
649#define HOME(foo) (ndof->foo == 0.0f)
650 return HOME(tx) && HOME(ty) && HOME(tz) && HOME(rx) && HOME(ry) && HOME(rz);
651#undef HOME
652}
653
654static bool nearHomePosition(const GHOST_TEventNDOFMotionData *ndof, float threshold)
655{
656 if (threshold == 0.0f) {
657 return atHomePosition(ndof);
658 }
659#define HOME(foo) (fabsf(ndof->foo) < threshold)
660 return HOME(tx) && HOME(ty) && HOME(tz) && HOME(rx) && HOME(ry) && HOME(rz);
661#undef HOME
662}
663
665{
666 if (!motion_event_pending_) {
667 if (motion_state_ != GHOST_kNotStarted) {
668 /* Detect window de-activation and change the `motion_state_` even when no motion is pending.
669 * Without this check it's possible the window is de-activated before the NDOF
670 * motion callbacks have run, while the `motion_state_` is active.
671 * In this case, activating the window again would create an event
672 * with a large time-delta, see: #134733. */
673 if (system_.getWindowManager()->getActiveWindow() == nullptr) {
674 /* Avoid large `dt` times when changing windows. */
675 motion_state_ = GHOST_kNotStarted;
676 }
677 }
678 return false;
679 }
680
681 motion_event_pending_ = false; /* Any pending motion is handled right now. */
682
683 GHOST_IWindow *window = system_.getWindowManager()->getActiveWindow();
684
685 /* Delivery will fail, so don't bother sending. */
686 if (window == nullptr) {
687 /* Avoid large `dt` times when changing windows. */
688 motion_state_ = GHOST_kNotStarted;
689 return false;
690 }
691
692 const GHOST_EventNDOFMotion *event = new GHOST_EventNDOFMotion(motion_time_, window);
693 GHOST_TEventNDOFMotionData *data = (GHOST_TEventNDOFMotionData *)event->getData();
694
695 /* Scale axis values here to normalize them to around +/- 1
696 * they are scaled again for overall sensitivity in the WM based on user preferences. */
697
698 const float scale = 1.0f / 350.0f; /* 3Dconnexion devices send +/- 350 usually */
699
700 data->tx = scale * translation_[0];
701 data->ty = scale * translation_[1];
702 data->tz = scale * translation_[2];
703
704 data->rx = scale * rotation_[0];
705 data->ry = scale * rotation_[1];
706 data->rz = scale * rotation_[2];
707 data->dt = 0.001f * (motion_time_ - motion_time_prev_); /* In seconds. */
708 motion_time_prev_ = motion_time_;
709
710 bool weHaveMotion = !nearHomePosition(data, motion_dead_zone_);
711
712 /* Determine what kind of motion event to send `(Starting, InProgress, Finishing)`
713 * and where that leaves this NDOF manager `(NotStarted, InProgress, Finished)`. */
714 switch (motion_state_) {
716 case GHOST_kFinished: {
717 if (weHaveMotion) {
718 data->progress = GHOST_kStarting;
719 motion_state_ = GHOST_kInProgress;
720 /* Previous motion time will be ancient, so just make up a reasonable time delta. */
722 }
723 else {
724 /* Send no event and keep current state. */
725 CLOG_DEBUG(&LOG, "Motion ignored");
726 delete event;
727 return false;
728 }
729 break;
730 }
731 case GHOST_kInProgress: {
732 if (weHaveMotion) {
733 data->progress = GHOST_kInProgress;
734 /* Remain 'InProgress'. */
735 }
736 else {
737 data->progress = GHOST_kFinishing;
738 motion_state_ = GHOST_kFinished;
739 }
740 break;
741 }
742 default: {
743 /* Will always be one of the above. */
744 break;
745 }
746 }
747
748#if 1
750 "Motion sent, T=(%.2f,%.2f,%.2f), R=(%.2f,%.2f,%.2f) dt=%.3f, status=%s",
751 data->tx,
752 data->ty,
753 data->tz,
754 data->rx,
755 data->ry,
756 data->rz,
757 data->dt,
758 ndof_progress_string[data->progress]);
759#else
760 /* Raw values, may be useful for debugging. */
762 "Motion sent, T=(%d,%d,%d) R=(%d,%d,%d) status=%s",
763 translation_[0],
764 translation_[1],
765 translation_[2],
766 rotation_[0],
767 rotation_[1],
768 rotation_[2],
769 ndof_progress_string[data->progress]);
770#endif
771 system_.pushEvent(event);
772
773 return true;
774}
775
unsigned int uint
unsigned short ushort
#define ARRAY_SIZE(arr)
#define CLOG_DEBUG(clg_ref,...)
Definition CLG_log.h:191
#define CLOG_INFO(clg_ref,...)
Definition CLG_log.h:190
#define GHOST_ASSERT(x, info)
static const GHOST_NDOF_ButtonT ndof_HID_map_SpaceExplorer[]
static const int genericButtonCount
static const std::map< GHOST_NDOF_ButtonT, const char * > ndof_button_names
static bool atHomePosition(const GHOST_TEventNDOFMotionData *ndof)
#define HOME(foo)
static const GHOST_NDOF_ButtonT ndof_HID_map_Generic[]
static bool nearHomePosition(const GHOST_TEventNDOFMotionData *ndof, float threshold)
static const GHOST_NDOF_ButtonT ndof_HID_map_Shared3Dx[]
static const char * ndof_progress_string[]
static GHOST_TKey ghost_map_keyboard_from_ndof_button(const GHOST_NDOF_ButtonT button)
static const char * ndof_device_names[]
#define MAP_ENTRY(button)
static const GHOST_NDOF_ButtonT ndof_HID_map_SpacePilot[]
@ NDOF_KeyboardPro
@ NDOF_SpaceMousePro
@ NDOF_SpaceMouseProWireless
@ NDOF_SpaceMouseWireless
@ NDOF_SpacePilotPro
@ NDOF_NumpadPro
@ NDOF_SpaceExplorer
@ NDOF_SpaceMouseEnterprise
@ NDOF_SpacePilot
@ NDOF_UnknownDevice
@ NDOF_SpaceNavigator
@ NDOF_Spaceball5000
@ NDOF_SpaceTraveler
#define NDOF_TIME_DELTA_STARTING
std::array< GHOST_NDOF_ButtonT, 6 > NDOF_Button_Array
NDOF_Button_Type
@ LongButton
GHOST_NDOF_ButtonT
@ GHOST_NDOF_BUTTON_KBP_F11
@ GHOST_NDOF_BUTTON_FRONT
@ GHOST_NDOF_BUTTON_CTRL
@ GHOST_NDOF_BUTTON_NONE
@ GHOST_NDOF_BUTTON_KBP_F7
@ GHOST_NDOF_BUTTON_FIT
@ GHOST_NDOF_BUTTON_DOMINANT
@ GHOST_NDOF_BUTTON_SPACE
@ GHOST_NDOF_BUTTON_DELETE
@ GHOST_NDOF_BUTTON_1
@ GHOST_NDOF_BUTTON_NP_F2
@ GHOST_NDOF_BUTTON_RIGHT
@ GHOST_NDOF_BUTTON_INVALID
@ GHOST_NDOF_BUTTON_KBP_F9
@ GHOST_NDOF_BUTTON_MINUS
@ GHOST_NDOF_BUTTON_ISO1
@ GHOST_NDOF_BUTTON_9
@ GHOST_NDOF_BUTTON_PANZOOM
@ GHOST_NDOF_BUTTON_MENU
@ GHOST_NDOF_BUTTON_ROLL_CW
@ GHOST_NDOF_BUTTON_KBP_F1
@ GHOST_NDOF_BUTTON_ROLL_CCW
@ GHOST_NDOF_BUTTON_BACK
@ GHOST_NDOF_BUTTON_ISO2
@ GHOST_NDOF_BUTTON_KBP_F12
@ GHOST_NDOF_BUTTON_3
@ GHOST_NDOF_BUTTON_TOP
@ GHOST_NDOF_BUTTON_PLUS
@ GHOST_NDOF_BUTTON_2
@ GHOST_NDOF_BUTTON_8
@ GHOST_NDOF_BUTTON_TAB
@ GHOST_NDOF_BUTTON_10
@ GHOST_NDOF_BUTTON_ALT
@ GHOST_NDOF_BUTTON_USER
@ GHOST_NDOF_BUTTON_KBP_F8
@ GHOST_NDOF_BUTTON_KBP_F5
@ GHOST_NDOF_BUTTON_KBP_F6
@ GHOST_NDOF_BUTTON_NP_F1
@ GHOST_NDOF_BUTTON_KBP_F2
@ GHOST_NDOF_BUTTON_4
@ GHOST_NDOF_BUTTON_7
@ GHOST_NDOF_BUTTON_ESC
@ GHOST_NDOF_BUTTON_NP_F4
@ GHOST_NDOF_BUTTON_NP_F3
@ GHOST_NDOF_BUTTON_KBP_F3
@ GHOST_NDOF_BUTTON_5
@ GHOST_NDOF_BUTTON_BOTTOM
@ GHOST_NDOF_BUTTON_ROTATE
@ GHOST_NDOF_BUTTON_KBP_F10
@ GHOST_NDOF_BUTTON_ENTER
@ GHOST_NDOF_BUTTON_KBP_F4
@ GHOST_NDOF_BUTTON_6
@ GHOST_NDOF_BUTTON_SHIFT
@ GHOST_NDOF_BUTTON_LEFT
GHOST_TEventType
@ GHOST_kEventKeyDown
@ GHOST_kEventKeyUp
GHOST_TKey
@ GHOST_kKeyLeftAlt
@ GHOST_kKeyF9
@ GHOST_kKeyEnter
@ GHOST_kKeyF6
@ GHOST_kKeyF11
@ GHOST_kKeyF5
@ GHOST_kKeyF12
@ GHOST_kKeyF1
@ GHOST_kKeyLeftControl
@ GHOST_kKeyTab
@ GHOST_kKeyF8
@ GHOST_kKeyDelete
@ GHOST_kKeyEsc
@ GHOST_kKeyUnknown
@ GHOST_kKeyF7
@ GHOST_kKeyF10
@ GHOST_kKeyLeftShift
@ GHOST_kKeyF3
@ GHOST_kKeyF2
@ GHOST_kKeyF4
@ GHOST_kKeySpace
@ GHOST_kStarting
@ GHOST_kNotStarted
@ GHOST_kFinishing
@ GHOST_kFinished
@ GHOST_kInProgress
BMesh const char void * data
unsigned long long int uint64_t
void updateButtonsBitmask(int button_bits, uint64_t time)
void updateButton(GHOST_NDOF_ButtonT button, bool press, uint64_t time)
void updateButtonsArray(NDOF_Button_Array buttons, uint64_t time, NDOF_Button_Type type)
void updateTranslation(const int t[3], uint64_t time)
GHOST_NDOFManager(GHOST_System &)
void updateButtonRAW(int button_number, bool press, uint64_t time)
void updateRotation(const int r[3], uint64_t time)
bool setDevice(unsigned short vendor_id, unsigned short product_id)
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt)
Definition frames.inl:1166
#define UINT_MAX
Definition hash_md5.cc:44
#define LOG(level)
Definition log.h:97
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
@ NDOF_BUTTON_SPIN_CW
@ NDOF_BUTTON_TILT_CCW
@ NDOF_BUTTON_7
@ NDOF_BUTTON_V2
@ NDOF_BUTTON_2
@ NDOF_BUTTON_8
@ NDOF_BUTTON_MENU
@ NDOF_BUTTON_1
@ NDOF_BUTTON_BOTTOM
@ NDOF_BUTTON_V1
@ NDOF_BUTTON_BACK
@ NDOF_BUTTON_5
@ NDOF_BUTTON_SAVE_V2
@ NDOF_BUTTON_RIGHT
@ NDOF_BUTTON_ROLL_CW
@ NDOF_BUTTON_10
@ NDOF_BUTTON_3
@ NDOF_BUTTON_PLUS
@ NDOF_BUTTON_ISO2
@ NDOF_BUTTON_PANZOOM
@ NDOF_BUTTON_MINUS
@ NDOF_BUTTON_DOMINANT
@ NDOF_BUTTON_TILT_CW
@ NDOF_BUTTON_9
@ NDOF_BUTTON_LEFT
@ NDOF_BUTTON_FIT
@ NDOF_BUTTON_V3
@ NDOF_BUTTON_SAVE_V3
@ NDOF_BUTTON_4
@ NDOF_BUTTON_12
@ NDOF_BUTTON_FRONT
@ NDOF_BUTTON_SAVE_V1
@ NDOF_BUTTON_11
@ NDOF_BUTTON_SPIN_CCW
@ NDOF_BUTTON_ISO1
@ NDOF_BUTTON_6
@ NDOF_BUTTON_TOP
@ NDOF_BUTTON_ROTATE
@ NDOF_BUTTON_ROLL_CCW