Blender V4.5
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/* Logging, use `ghost.ndof.*` prefix. */
14#include "CLG_log.h"
15
16#include <algorithm>
17#include <array>
18#include <climits>
19#include <cmath>
20#include <cstring> /* For memory functions. */
21#include <map>
22
27// #define USE_3DCONNEXION_NONSTANDARD_KEYS
28
29/* -------------------------------------------------------------------- */
32
33/* Printable values for #GHOST_TProgress enum (keep aligned). */
34static const char *ndof_progress_string[] = {
35 "not started",
36 "starting",
37 "in progress",
38 "finishing",
39 "finished",
40};
41
42/* Printable values for #NDOF_ButtonT enum (keep aligned) */
43#define MAP_ENTRY(button) \
44 { \
45 GHOST_##button, #button \
46 }
47static const std::map<GHOST_NDOF_ButtonT, const char *> ndof_button_names = {
48 /* Disable wrapping, it makes it difficult to read. */
49 /* clang-format off */
50 MAP_ENTRY(NDOF_BUTTON_INVALID),
79 MAP_ENTRY(NDOF_BUTTON_ESC),
80 MAP_ENTRY(NDOF_BUTTON_ALT),
81 MAP_ENTRY(NDOF_BUTTON_SHIFT),
82 MAP_ENTRY(NDOF_BUTTON_CTRL),
83 MAP_ENTRY(NDOF_BUTTON_ENTER),
84 MAP_ENTRY(NDOF_BUTTON_DELETE),
85 MAP_ENTRY(NDOF_BUTTON_TAB),
86 MAP_ENTRY(NDOF_BUTTON_SPACE),
98 MAP_ENTRY(NDOF_BUTTON_KBP_F1),
99 MAP_ENTRY(NDOF_BUTTON_KBP_F2),
100 MAP_ENTRY(NDOF_BUTTON_KBP_F3),
101 MAP_ENTRY(NDOF_BUTTON_KBP_F4),
102 MAP_ENTRY(NDOF_BUTTON_KBP_F5),
103 MAP_ENTRY(NDOF_BUTTON_KBP_F6),
104 MAP_ENTRY(NDOF_BUTTON_KBP_F7),
105 MAP_ENTRY(NDOF_BUTTON_KBP_F8),
106 MAP_ENTRY(NDOF_BUTTON_KBP_F9),
107 MAP_ENTRY(NDOF_BUTTON_KBP_F10),
108 MAP_ENTRY(NDOF_BUTTON_KBP_F11),
109 MAP_ENTRY(NDOF_BUTTON_KBP_F12),
110 MAP_ENTRY(NDOF_BUTTON_NP_F1),
111 MAP_ENTRY(NDOF_BUTTON_NP_F2),
112 MAP_ENTRY(NDOF_BUTTON_NP_F3),
113 MAP_ENTRY(NDOF_BUTTON_NP_F4),
114 /* clang-format on */
115};
116#undef MAP_ENTRY
117
118static const char *ndof_device_names[] = {
119 "UnknownDevice",
120 "SpaceNavigator",
121 "SpaceExplorer",
122 "SpacePilotPro",
123 "SpaceMousePro",
124 "SpaceMouseWireless",
125 "SpaceMouseProWireless",
126 "SpaceMouseEnterprise",
127 "SpacePilot",
128 "Spaceball5000",
129 "SpaceTraveler",
130 "Keyboard Pro",
131 "Numpad Pro",
132};
133
135
136/* -------------------------------------------------------------------- */
139
158
176
177/* This is the older SpacePilot (sans Pro). */
191
203
204
205/* -------------------------------------------------------------------- */
208
210
212 : system_(sys),
213 device_type_(NDOF_UnknownDevice), /* Each platform has its own device detection code. */
214 hid_map_button_num_(genericButtonCount),
215 hid_map_button_mask_(0),
216 hid_map_(ndof_HID_map_Generic),
217 button_depressed_(0),
218 pressed_buttons_cache_(),
219 pressed_long_buttons_cache_(),
220 motion_time_(0),
221 motion_time_prev_(0),
222 motion_state_(GHOST_kNotStarted),
223 motion_event_pending_(false),
224 motion_dead_zone_(0.0f)
225{
226 /* To avoid the rare situation where one triple is updated and
227 * the other is not, initialize them both here: */
228 memset(translation_, 0, sizeof(translation_));
229 memset(rotation_, 0, sizeof(rotation_));
230}
231
233
234/* -------------------------------------------------------------------- */
237
238static CLG_LogRef LOG_NDOF_DEVICE = {"ghost.ndof.device"};
239#define LOG (&LOG_NDOF_DEVICE)
240
241bool GHOST_NDOFManager::setDevice(ushort vendor_id, ushort product_id)
242{
243 /* Call this function until it returns true
244 * it's a good idea to stop calling it after that, as it will "forget"
245 * whichever device it already found. */
246
247 /* Default to safe generic behavior for "unknown" devices
248 * unidentified devices will emit motion events like normal
249 * rogue buttons do nothing by default, but can be customized by the user. */
250
251 device_type_ = NDOF_UnknownDevice;
252 hid_map_ = ndof_HID_map_Generic;
253 hid_map_button_num_ = genericButtonCount;
254 hid_map_button_mask_ = 0;
255
256 /* "mystery device" owners can help build a HID_map for their hardware
257 * A few users have already contributed information about several older devices
258 * that I don't have access to. Thanks! */
259
260 switch (vendor_id) {
261 case 0x046D: /* Logitech (3Dconnexion was a subsidiary). */
262 switch (product_id) {
263 /* -- current devices -- */
264 case 0xC626: /* Full-size SpaceNavigator. */
265 case 0xC628: /* The "for Notebooks" one. */
266 {
267 device_type_ = NDOF_SpaceNavigator;
268 hid_map_button_num_ = 2;
269 hid_map_ = ndof_HID_map_Shared3Dx;
270 break;
271 }
272 case 0xC627: {
273 device_type_ = NDOF_SpaceExplorer;
274 hid_map_button_num_ = 15;
276 break;
277 }
278 case 0xC629: {
279 device_type_ = NDOF_SpacePilotPro;
280 hid_map_button_num_ = 31;
281 hid_map_ = ndof_HID_map_Shared3Dx;
282 break;
283 }
284 case 0xC62B: {
285 device_type_ = NDOF_SpaceMousePro;
286 hid_map_button_num_ = 27; /* 15 physical buttons, but HID codes range from 0 to 26. */
287 hid_map_button_mask_ = 0x07C0F137;
288 hid_map_ = ndof_HID_map_Shared3Dx;
289 break;
290 }
291
292 /* -- older devices -- */
293 case 0xC625: {
294 device_type_ = NDOF_SpacePilot;
295 hid_map_button_num_ = 21;
296 hid_map_ = ndof_HID_map_SpacePilot;
297 break;
298 }
299 case 0xC621: {
300 device_type_ = NDOF_Spaceball5000;
301 hid_map_button_num_ = 12;
302 break;
303 }
304 case 0xC623: {
305 device_type_ = NDOF_SpaceTraveler;
306 hid_map_button_num_ = 8;
307 break;
308 }
309 default: {
310 CLOG_INFO(LOG, 2, "unknown Logitech product %04hx", product_id);
311 }
312 }
313 break;
314 case 0x256F: /* 3Dconnexion. */
315 switch (product_id) {
316 case 0xC62E: /* SpaceMouse Wireless (cabled). */
317 case 0xC62F: /* SpaceMouse Wireless Receiver. */
318 case 0xC658: /* Wireless (3DConnexion Universal Wireless Receiver in WIN32), see #82412. */
319 {
320 device_type_ = NDOF_SpaceMouseWireless;
321 hid_map_button_num_ = 2;
322 hid_map_ = ndof_HID_map_Shared3Dx;
323 break;
324 }
325 case 0xC631: /* SpaceMouse Pro Wireless (cabled). */
326 case 0xC632: /* SpaceMouse Pro Wireless Receiver. */
327 case 0xC638: /* SpaceMouse Pro Wireless BT (cabled), see #116393.
328 * 3Dconnexion docs describe this as "Wireless BT", but it is cabled. */
329 case 0xC652: /* Universal Receiver. */
330 {
331 device_type_ = NDOF_SpaceMouseProWireless;
332 hid_map_button_num_ = 27; /* 15 physical buttons, but HID codes range from 0 to 26. */
333 hid_map_button_mask_ = 0x07C0F137;
334 hid_map_ = ndof_HID_map_Shared3Dx;
335 break;
336 }
337 case 0xC633: /* Newer devices don't need to use button mappings. */
338 {
339 device_type_ = NDOF_SpaceMouseEnterprise;
340 break;
341 }
342 case 0xC664:
343 case 0xC668: {
344 device_type_ = NDOF_KeyboardPro;
345 break;
346 }
347 case 0xC665: {
348 device_type_ = NDOF_NumpadPro;
349 break;
350 }
351 default: {
352 CLOG_INFO(LOG, 2, "unknown 3Dconnexion product %04hx", product_id);
353 }
354 }
355 break;
356 default:
357 CLOG_INFO(LOG, 2, "unknown device %04hx:%04hx", vendor_id, product_id);
358 }
359
360 if (device_type_ != NDOF_UnknownDevice) {
361 CLOG_INFO(LOG, 2, "using %s", ndof_device_names[device_type_]);
362 }
363
364 if (hid_map_button_mask_ == 0) {
365 hid_map_button_mask_ = int(~(UINT_MAX << hid_map_button_num_));
366 }
367
368 CLOG_INFO(LOG, 2, "%d buttons -> hex:%X", hid_map_button_num_, uint(hid_map_button_mask_));
369
370 return device_type_ != NDOF_UnknownDevice;
371}
372
373#undef LOG
374
376
377/* -------------------------------------------------------------------- */
380
382{
383 memcpy(translation_, t, sizeof(translation_));
384 motion_time_ = time;
385 motion_event_pending_ = true;
386}
387
389{
390 memcpy(rotation_, r, sizeof(rotation_));
391 motion_time_ = time;
392 motion_event_pending_ = true;
393}
394
396
397/* -------------------------------------------------------------------- */
400
401static CLG_LogRef LOG_NDOF_BUTTONS = {"ghost.ndof.buttons"};
402#define LOG (&LOG_NDOF_BUTTONS)
403
405{
406 switch (button) {
408 return GHOST_kKeyEsc;
409 }
411 return GHOST_kKeyEnter;
412 }
414 return GHOST_kKeyDelete;
415 }
417 return GHOST_kKeyTab;
418 }
420 return GHOST_kKeySpace;
421 }
423 return GHOST_kKeyLeftAlt;
424 }
426 return GHOST_kKeyLeftShift;
427 }
430 }
431
432#ifdef USE_3DCONNEXION_NONSTANDARD_KEYS
435 return GHOST_kKeyF1;
436 }
439 return GHOST_kKeyF2;
440 }
443 return GHOST_kKeyF3;
444 }
447 return GHOST_kKeyF4;
448 }
450 return GHOST_kKeyF5;
451 }
453 return GHOST_kKeyF6;
454 }
456 return GHOST_kKeyF7;
457 }
459 return GHOST_kKeyF8;
460 }
462 return GHOST_kKeyF9;
463 }
465 return GHOST_kKeyF10;
466 }
468 return GHOST_kKeyF11;
469 }
471 return GHOST_kKeyF12;
472 }
473#endif /* !USE_3DCONNEXION_NONSTANDARD_KEYS */
474
475 default: {
476 return GHOST_kKeyUnknown;
477 }
478 }
479}
480
481void GHOST_NDOFManager::sendButtonEvent(GHOST_NDOF_ButtonT button,
482 bool press,
483 uint64_t time,
484 GHOST_IWindow *window)
485{
487 "rogue button trying to escape GHOST_NDOF manager");
488
489 const GHOST_EventNDOFButton *event = new GHOST_EventNDOFButton(time, window);
490 GHOST_TEventNDOFButtonData *data = (GHOST_TEventNDOFButtonData *)event->getData();
491
492 data->action = press ? GHOST_kPress : GHOST_kRelease;
493 data->button = button;
494
495 system_.pushEvent(event);
496}
497
498void GHOST_NDOFManager::sendKeyEvent(GHOST_TKey key,
499 bool press,
500 uint64_t time,
501 GHOST_IWindow *window)
502{
504 const GHOST_EventKey *event = new GHOST_EventKey(time, type, window, key, false);
505
506 system_.pushEvent(event);
507}
508
510{
511 if (button == GHOST_NDOF_BUTTON_INVALID) {
512 CLOG_INFO(LOG, 2, "button=%d, press=%d (mapped to none, ignoring!)", int(button), int(press));
513 return;
514 }
515
516 CLOG_INFO(
517 LOG, 2, "button=%d, press=%d, name=%s", button, int(press), ndof_button_names.at(button));
518
519#ifndef USE_3DCONNEXION_NONSTANDARD_KEYS
520 if (((button >= GHOST_NDOF_BUTTON_KBP_F1) && (button <= GHOST_NDOF_BUTTON_KBP_F12)) ||
521 ((button >= GHOST_NDOF_BUTTON_NP_F1) && (button <= GHOST_NDOF_BUTTON_NP_F4)))
522 {
523 return;
524 }
525#endif /* !USE_3DCONNEXION_NONSTANDARD_KEYS */
526
527 GHOST_IWindow *window = system_.getWindowManager()->getActiveWindow();
528
529 /* Delivery will fail, so don't bother sending. */
530 if (window != nullptr) {
532 if (key != GHOST_kKeyUnknown) {
533 sendKeyEvent(key, press, time, window);
534 }
535 else {
536 sendButtonEvent(button, press, time, window);
537 }
538 }
539}
540
541void GHOST_NDOFManager::updateButtonRAW(int button_number, bool press, uint64_t time)
542{
543 GHOST_NDOF_ButtonT button;
544
545 /* For bit-mask devices button mapping isn't unified, therefore check the button map. */
546 if (std::find(bitmask_devices_.begin(), bitmask_devices_.end(), device_type_) !=
547 bitmask_devices_.end())
548 {
549 if (button_number >= hid_map_button_num_) {
550 CLOG_INFO(
551 LOG, 2, "button=%d, press=%d (out of range, ignoring!)", button_number, int(press));
552 return;
553 }
554 button = hid_map_[button_number];
555 }
556 else {
557 button = static_cast<GHOST_NDOF_ButtonT>(button_number);
558 }
559
560 GHOST_NDOFManager::updateButton(button, press, time);
561}
562
564{
565 /* Some devices send two data packets: bitmask and number array.
566 * In this case, packet has to be ignored if it came from such a device. */
567 if (std::find(bitmask_devices_.begin(), bitmask_devices_.end(), device_type_) ==
568 bitmask_devices_.end())
569 {
570 return;
571 }
572
573 button_bits &= hid_map_button_mask_; /* Discard any "garbage" bits. */
574
575 int diff = button_depressed_ ^ button_bits;
576
577 for (int button_number = 0; button_number < hid_map_button_num_; ++button_number) {
578 int mask = 1 << button_number;
579
580 if (diff & mask) {
581 bool press = button_bits & mask;
582
583 if (press) {
584 button_depressed_ |= mask; /* Set this button's bit. */
585 }
586 else {
587 button_depressed_ &= ~mask; /* Clear this button's bit. */
588 }
589
590 /* Bitmask devices don't have unified keymaps, so button numbers needs to be looked up in the
591 * map. */
592 const GHOST_NDOF_ButtonT button = hid_map_[button_number];
593 updateButton(button, press, time);
594 }
595 }
596}
597
599 uint64_t time,
600 NDOF_Button_Type type)
601{
602 NDOF_Button_Array &cache = (type == NDOF_Button_Type::LongButton) ? pressed_long_buttons_cache_ :
603 pressed_buttons_cache_;
604
605 /* Find released buttons */
606 for (const auto &cached_button : cache) {
607 bool found = false;
608 for (const auto &button : buttons) {
609 if (button == cached_button) {
610 found = true;
611 break;
612 }
613 }
614
615 if (!found) {
616 updateButton(cached_button, false, time);
617 }
618 }
619
620 /* Find pressed buttons */
621 for (const auto &button : buttons) {
622 bool found = false;
623 for (const auto &cached_button : cache) {
624 if (button == cached_button) {
625 found = true;
626 break;
627 }
628 }
629
630 if (!found) {
631 updateButton(button, true, time);
632 }
633 }
634 cache = buttons;
635}
636#undef LOG
637
639
640/* -------------------------------------------------------------------- */
643
644static CLG_LogRef LOG_NDOF_MOTION = {"ghost.ndof.motion"};
645#define LOG (&LOG_NDOF_MOTION)
646
648{
649 /* Negative values don't make sense, so clamp at zero. */
650 dz = std::max(dz, 0.0f);
651 motion_dead_zone_ = dz;
652
653 /* Warn the rogue user/developer about high dead-zone, but allow it. */
654 CLOG_INFO(LOG, 2, "dead zone set to %.2f%s", dz, (dz > 0.5f) ? " (unexpectedly high)" : "");
655}
656
657static bool atHomePosition(const GHOST_TEventNDOFMotionData *ndof)
658{
659#define HOME(foo) (ndof->foo == 0.0f)
660 return HOME(tx) && HOME(ty) && HOME(tz) && HOME(rx) && HOME(ry) && HOME(rz);
661#undef HOME
662}
663
664static bool nearHomePosition(const GHOST_TEventNDOFMotionData *ndof, float threshold)
665{
666 if (threshold == 0.0f) {
667 return atHomePosition(ndof);
668 }
669#define HOME(foo) (fabsf(ndof->foo) < threshold)
670 return HOME(tx) && HOME(ty) && HOME(tz) && HOME(rx) && HOME(ry) && HOME(rz);
671#undef HOME
672}
673
675{
676 if (!motion_event_pending_) {
677 if (motion_state_ != GHOST_kNotStarted) {
678 /* Detect window de-activation and change the `motion_state_` even when no motion is pending.
679 * Without this check it's possible the window is de-activated before the NDOF
680 * motion callbacks have run, while the `motion_state_` is active.
681 * In this case, activating the window again would create an event
682 * with a large time-delta, see: #134733. */
683 if (system_.getWindowManager()->getActiveWindow() == nullptr) {
684 /* Avoid large `dt` times when changing windows. */
685 motion_state_ = GHOST_kNotStarted;
686 }
687 }
688 return false;
689 }
690
691 motion_event_pending_ = false; /* Any pending motion is handled right now. */
692
693 GHOST_IWindow *window = system_.getWindowManager()->getActiveWindow();
694
695 /* Delivery will fail, so don't bother sending. */
696 if (window == nullptr) {
697 /* Avoid large `dt` times when changing windows. */
698 motion_state_ = GHOST_kNotStarted;
699 return false;
700 }
701
702 const GHOST_EventNDOFMotion *event = new GHOST_EventNDOFMotion(motion_time_, window);
703 GHOST_TEventNDOFMotionData *data = (GHOST_TEventNDOFMotionData *)event->getData();
704
705 /* Scale axis values here to normalize them to around +/- 1
706 * they are scaled again for overall sensitivity in the WM based on user preferences. */
707
708 const float scale = 1.0f / 350.0f; /* 3Dconnexion devices send +/- 350 usually */
709
710 data->tx = scale * translation_[0];
711 data->ty = scale * translation_[1];
712 data->tz = scale * translation_[2];
713
714 data->rx = scale * rotation_[0];
715 data->ry = scale * rotation_[1];
716 data->rz = scale * rotation_[2];
717 data->dt = 0.001f * (motion_time_ - motion_time_prev_); /* In seconds. */
718 motion_time_prev_ = motion_time_;
719
720 bool weHaveMotion = !nearHomePosition(data, motion_dead_zone_);
721
722 /* Determine what kind of motion event to send `(Starting, InProgress, Finishing)`
723 * and where that leaves this NDOF manager `(NotStarted, InProgress, Finished)`. */
724 switch (motion_state_) {
726 case GHOST_kFinished: {
727 if (weHaveMotion) {
728 data->progress = GHOST_kStarting;
729 motion_state_ = GHOST_kInProgress;
730 /* Previous motion time will be ancient, so just make up a reasonable time delta. */
732 }
733 else {
734 /* Send no event and keep current state. */
735 CLOG_INFO(LOG, 2, "motion ignored");
736 delete event;
737 return false;
738 }
739 break;
740 }
741 case GHOST_kInProgress: {
742 if (weHaveMotion) {
743 data->progress = GHOST_kInProgress;
744 /* Remain 'InProgress'. */
745 }
746 else {
747 data->progress = GHOST_kFinishing;
748 motion_state_ = GHOST_kFinished;
749 }
750 break;
751 }
752 default: {
753 /* Will always be one of the above. */
754 break;
755 }
756 }
757
758#if 1
760 2,
761 "motion sent, T=(%.2f,%.2f,%.2f), R=(%.2f,%.2f,%.2f) dt=%.3f, status=%s",
762 data->tx,
763 data->ty,
764 data->tz,
765 data->rx,
766 data->ry,
767 data->rz,
768 data->dt,
769 ndof_progress_string[data->progress]);
770#else
771 /* Raw values, may be useful for debugging. */
773 2,
774 "motion sent, T=(%d,%d,%d) R=(%d,%d,%d) status=%s",
775 translation_[0],
776 translation_[1],
777 translation_[2],
778 rotation_[0],
779 rotation_[1],
780 rotation_[2],
781 ndof_progress_string[data->progress]);
782#endif
783 system_.pushEvent(event);
784
785 return true;
786}
787
unsigned int uint
unsigned short ushort
#define ARRAY_SIZE(arr)
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
#define GHOST_ASSERT(x, info)
static const GHOST_NDOF_ButtonT ndof_HID_map_SpaceExplorer[]
static CLG_LogRef LOG_NDOF_DEVICE
static const int genericButtonCount
static const std::map< GHOST_NDOF_ButtonT, const char * > ndof_button_names
static bool atHomePosition(const GHOST_TEventNDOFMotionData *ndof)
static CLG_LogRef LOG_NDOF_MOTION
#define HOME(foo)
static CLG_LogRef LOG_NDOF_BUTTONS
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(severity)
Definition log.h:32
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