Blender V4.3
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/* -------------------------------------------------------------------- */
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
136/* -------------------------------------------------------------------- */
158
176
177/* This is the older SpacePilot (sans Pro). */
191
205/* -------------------------------------------------------------------- */
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
234/* -------------------------------------------------------------------- */
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
377/* -------------------------------------------------------------------- */
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
397/* -------------------------------------------------------------------- */
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
509void GHOST_NDOFManager::updateButton(int button_number, bool press, uint64_t time)
510{
511 GHOST_NDOF_ButtonT button = static_cast<GHOST_NDOF_ButtonT>(button_number);
512
513 /* For bit-mask devices button mapping isn't unified, therefore check the button map. */
514 if (std::find(bitmask_devices_.begin(), bitmask_devices_.end(), device_type_) !=
515 bitmask_devices_.end())
516 {
517 button = hid_map_[button_number];
518 }
519
520 if (button == GHOST_NDOF_BUTTON_INVALID) {
521 CLOG_INFO(
522 LOG, 2, "button=%d, press=%d (mapped to none, ignoring!)", button_number, int(press));
523 return;
524 }
525
527 2,
528 "button=%d, press=%d, name=%s",
529 button_number,
530 int(press),
531 ndof_button_names.at(button));
532
533#ifndef USE_3DCONNEXION_NONSTANDARD_KEYS
534 if (((button >= GHOST_NDOF_BUTTON_KBP_F1) && (button <= GHOST_NDOF_BUTTON_KBP_F12)) ||
535 ((button >= GHOST_NDOF_BUTTON_NP_F1) && (button <= GHOST_NDOF_BUTTON_NP_F4)))
536 {
537 return;
538 }
539#endif /* !USE_3DCONNEXION_NONSTANDARD_KEYS */
540
542
543 /* Delivery will fail, so don't bother sending. */
544 if (window != nullptr) {
546 if (key != GHOST_kKeyUnknown) {
547 sendKeyEvent(key, press, time, window);
548 }
549 else {
550 sendButtonEvent(button, press, time, window);
551 }
552 }
553}
554
556{
557 /* Some devices send two data packets: bitmask and number array.
558 * In this case, packet has to be ignored if it came from such a device. */
559 if (std::find(bitmask_devices_.begin(), bitmask_devices_.end(), device_type_) ==
560 bitmask_devices_.end())
561 {
562 return;
563 }
564
565 button_bits &= hid_map_button_mask_; /* Discard any "garbage" bits. */
566
567 int diff = button_depressed_ ^ button_bits;
568
569 for (int button_number = 0; button_number < hid_map_button_num_; ++button_number) {
570 int mask = 1 << button_number;
571
572 if (diff & mask) {
573 bool press = button_bits & mask;
574
575 if (press) {
576 button_depressed_ |= mask; /* Set this button's bit. */
577 }
578 else {
579 button_depressed_ &= ~mask; /* Clear this button's bit. */
580 }
581 updateButton(button_number, press, time);
582 }
583 }
584}
585
587 uint64_t time,
588 NDOF_Button_Type type)
589{
590 NDOF_Button_Array &cache = (type == NDOF_Button_Type::LongButton) ? pressed_long_buttons_cache_ :
591 pressed_buttons_cache_;
592
593 /* Find released buttons */
594 for (const auto &cached_button : cache) {
595 bool found = false;
596 for (const auto &button : buttons) {
597 if (button == cached_button) {
598 found = true;
599 break;
600 }
601 }
602
603 if (!found)
604 updateButton(cached_button, false, time);
605 }
606
607 /* Find pressed buttons */
608 for (const auto &button : buttons) {
609 bool found = false;
610 for (const auto &cached_button : cache) {
611 if (button == cached_button) {
612 found = true;
613 break;
614 }
615 }
616
617 if (!found)
618 updateButton(button, true, time);
619 }
620 cache = buttons;
621}
622#undef LOG
623
626/* -------------------------------------------------------------------- */
630static CLG_LogRef LOG_NDOF_MOTION = {"ghost.ndof.motion"};
631#define LOG (&LOG_NDOF_MOTION)
632
634{
635 if (dz < 0.0f) {
636 /* Negative values don't make sense, so clamp at zero. */
637 dz = 0.0f;
638 }
639 motion_dead_zone_ = dz;
640
641 /* Warn the rogue user/developer about high dead-zone, but allow it. */
642 CLOG_INFO(LOG, 2, "dead zone set to %.2f%s", dz, (dz > 0.5f) ? " (unexpectedly high)" : "");
643}
644
645static bool atHomePosition(const GHOST_TEventNDOFMotionData *ndof)
646{
647#define HOME(foo) (ndof->foo == 0.0f)
648 return HOME(tx) && HOME(ty) && HOME(tz) && HOME(rx) && HOME(ry) && HOME(rz);
649#undef HOME
650}
651
652static bool nearHomePosition(const GHOST_TEventNDOFMotionData *ndof, float threshold)
653{
654 if (threshold == 0.0f) {
655 return atHomePosition(ndof);
656 }
657#define HOME(foo) (fabsf(ndof->foo) < threshold)
658 return HOME(tx) && HOME(ty) && HOME(tz) && HOME(rx) && HOME(ry) && HOME(rz);
659#undef HOME
660}
661
663{
664 if (!motion_event_pending_) {
665 return false;
666 }
667
668 motion_event_pending_ = false; /* Any pending motion is handled right now. */
669
671
672 /* Delivery will fail, so don't bother sending. */
673 if (window == nullptr) {
674 /* Avoid large `dt` times when changing windows. */
675 motion_state_ = GHOST_kNotStarted;
676 return false;
677 }
678
679 const GHOST_EventNDOFMotion *event = new GHOST_EventNDOFMotion(motion_time_, window);
680 GHOST_TEventNDOFMotionData *data = (GHOST_TEventNDOFMotionData *)event->getData();
681
682 /* Scale axis values here to normalize them to around +/- 1
683 * they are scaled again for overall sensitivity in the WM based on user preferences. */
684
685 const float scale = 1.0f / 350.0f; /* 3Dconnexion devices send +/- 350 usually */
686
687 data->tx = scale * translation_[0];
688 data->ty = scale * translation_[1];
689 data->tz = scale * translation_[2];
690
691 data->rx = scale * rotation_[0];
692 data->ry = scale * rotation_[1];
693 data->rz = scale * rotation_[2];
694 data->dt = 0.001f * (motion_time_ - motion_time_prev_); /* In seconds. */
695 motion_time_prev_ = motion_time_;
696
697 bool weHaveMotion = !nearHomePosition(data, motion_dead_zone_);
698
699 /* Determine what kind of motion event to send `(Starting, InProgress, Finishing)`
700 * and where that leaves this NDOF manager `(NotStarted, InProgress, Finished)`. */
701 switch (motion_state_) {
703 case GHOST_kFinished: {
704 if (weHaveMotion) {
705 data->progress = GHOST_kStarting;
706 motion_state_ = GHOST_kInProgress;
707 /* Previous motion time will be ancient, so just make up a reasonable time delta. */
708 data->dt = 0.0125f;
709 }
710 else {
711 /* Send no event and keep current state. */
712 CLOG_INFO(LOG, 2, "motion ignored");
713 delete event;
714 return false;
715 }
716 break;
717 }
718 case GHOST_kInProgress: {
719 if (weHaveMotion) {
720 data->progress = GHOST_kInProgress;
721 /* Remain 'InProgress'. */
722 }
723 else {
724 data->progress = GHOST_kFinishing;
725 motion_state_ = GHOST_kFinished;
726 }
727 break;
728 }
729 default: {
730 /* Will always be one of the above. */
731 break;
732 }
733 }
734
735#if 1
737 2,
738 "motion sent, T=(%.2f,%.2f,%.2f), R=(%.2f,%.2f,%.2f) dt=%.3f, status=%s",
739 data->tx,
740 data->ty,
741 data->tz,
742 data->rx,
743 data->ry,
744 data->rz,
745 data->dt,
746 ndof_progress_string[data->progress]);
747#else
748 /* Raw values, may be useful for debugging. */
750 2,
751 "motion sent, T=(%d,%d,%d) R=(%d,%d,%d) status=%s",
752 translation_[0],
753 translation_[1],
754 translation_[2],
755 rotation_[0],
756 rotation_[1],
757 rotation_[2],
758 ndof_progress_string[data->progress]);
759#endif
760 system_.pushEvent(event);
761
762 return true;
763}
764
unsigned short ushort
unsigned int uint
#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 GHOST_TKey ghost_map_keyboard_from_ndof_buttom(const GHOST_NDOF_ButtonT button)
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 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
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
void updateButtonsBitmask(int button_bits, uint64_t time)
void updateButtonsArray(NDOF_Button_Array buttons, uint64_t time, NDOF_Button_Type type)
void updateButton(int button_number, bool press, uint64_t time)
void updateTranslation(const int t[3], uint64_t time)
GHOST_System & system_
GHOST_NDOFManager(GHOST_System &)
void updateRotation(const int r[3], uint64_t time)
bool setDevice(unsigned short vendor_id, unsigned short product_id)
GHOST_WindowManager * getWindowManager() const
GHOST_TSuccess pushEvent(const GHOST_IEvent *event)
GHOST_IWindow * getActiveWindow() const
double time
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
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:33
ccl_device_inline float4 mask(const int4 mask, const float4 a)
unsigned __int64 uint64_t
Definition stdint.h:90
@ 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