From 9b27b6e5098aee7a050d4c3f3f14050c509f74ec Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 14 Dec 2022 19:41:07 +0200 Subject: SL-13610 [MAC] WIP List HID available devices in joystick selection Doesn't filter the list yet, just shows full list of usb devices Selecting visible devices doesn't work yet --- indra/llwindow/llwindow.h | 8 +- indra/llwindow/llwindowmacosx-objc.mm | 1 + indra/llwindow/llwindowmacosx.cpp | 315 +++++++++++++++++++++++++++++++++- indra/llwindow/llwindowmacosx.h | 5 + indra/llwindow/llwindowwin32.cpp | 5 +- indra/llwindow/llwindowwin32.h | 5 +- 6 files changed, 330 insertions(+), 9 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index ac4848579f..2d27092e0a 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -196,7 +196,13 @@ public: // windows only DirectInput8 for joysticks virtual void* getDirectInput8() { return NULL; }; - virtual bool getInputDevices(U32 device_type_filter, void * devices_callback, void* userdata) { return false; }; + virtual bool getInputDevices(U32 device_type_filter, + std::function osx_callback, + void* win_callback, + void* userdata) + { + return false; + }; virtual S32 getRefreshRate() { return mRefreshRate; } protected: diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm index 690fe058db..2e75d309ea 100644 --- a/indra/llwindow/llwindowmacosx-objc.mm +++ b/indra/llwindow/llwindowmacosx-objc.mm @@ -27,6 +27,7 @@ #include #include +#include #include "llopenglview-objc.h" #include "llwindowmacosx-objc.h" #include "llappdelegate-objc.h" diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 2c841d4703..bd13138a7d 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -43,6 +43,13 @@ #include #include +#include +#include +#include +#include +#include +#include + extern BOOL gDebugWindowProc; BOOL gHiDPISupport = TRUE; @@ -212,13 +219,16 @@ bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask) bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wchar_t character) { - if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y')) - { - key = gKeyboard->inverseTranslateKey('Y'); - } - else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z')) + //if (mask!=MASK_NONE) { - key = gKeyboard->inverseTranslateKey('Z'); + if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y')) + { + key = gKeyboard->inverseTranslateKey('Y'); + } + else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z')) + { + key = gKeyboard->inverseTranslateKey('Z'); + } } mRawKeyEvent = event; @@ -1803,6 +1813,299 @@ void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async) } } + +// Device and Element Interfaces + +typedef enum HIDElementTypeMask +{ + kHIDElementTypeInput = 1 << 1, + kHIDElementTypeOutput = 1 << 2, + kHIDElementTypeFeature = 1 << 3, + kHIDElementTypeCollection = 1 << 4, + kHIDElementTypeIO = kHIDElementTypeInput | kHIDElementTypeOutput | kHIDElementTypeFeature, + kHIDElementTypeAll = kHIDElementTypeIO | kHIDElementTypeCollection +}HIDElementTypeMask; + +struct hu_element_t +{ + unsigned long type; // the type defined by IOHIDElementType in IOHIDKeys.h + long usage; // usage within above page from IOUSBHIDParser.h which defines specific usage + long usagePage; // usage page from IOUSBHIDParser.h which defines general usage + void* cookie; // unique value( within device of specific vendorID and productID ) which identifies element, will NOT change + long min; // reported min value possible + long max; // reported max value possible + long scaledMin; // reported scaled min value possible + long scaledMax; // reported scaled max value possible + long size; // size in bits of data return from element + unsigned char relative; // are reports relative to last report( deltas ) + unsigned char wrapping; // does element wrap around( one value higher than max is min ) + unsigned char nonLinear; // are the values reported non-linear relative to element movement + unsigned char preferredState; // does element have a preferred state( such as a button ) + unsigned char nullState; // does element have null state + long units; // units value is reported in( not used very often ) + long unitExp; // exponent for units( also not used very often ) + char name[256]; // name of element( c string ) + + // runtime variables + long initialCenter; // center value at start up + unsigned char hasCenter; // whether or not to use center for calibration + long minReport; // min returned value + long maxReport; // max returned value( calibrate call ) + long userMin; // user set value to scale to( scale call ) + long userMax; + + struct hu_element_t* pPrevious; // previous element( NULL at list head ) + struct hu_element_t* pChild; // next child( only of collections ) + struct hu_element_t* pSibling; // next sibling( for elements and collections ) + + long depth; +}; + +struct HidDevice +{ // interface to device, NULL = no interface + char mProduct[256]; // name of product + long mlocalID; // long representing location in USB( or other I/O ) chain which device is pluged into, can identify specific device on machine + long mUsage; // usage page from IOUSBHID Parser.h which defines general usage + long mUsagePage; // usage within above page from IOUSBHID Parser.h which defines specific usage +}; + +/************************************************************************* +* +* hu_BuildDevice( inHIDDevice ) +* +* Purpose: given a IO device object build a flat device record including device info and all elements +* +* Notes: handles NULL lists properly +* +* Inputs: inHIDDevice - the I/O device object +* +* Returns: hu_device_t* - the address of the new device record +*/ + + +static void populate_device_info( io_object_t io_obj_p, CFDictionaryRef device_dic, HidDevice* devicep ) +{ + CFMutableDictionaryRef io_properties = nil; + io_registry_entry_t entry1; + io_registry_entry_t entry2; + kern_return_t rc; + + // Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also + // get dictionary for usb properties: step up two levels and get CF dictionary for USB properties + // try to get parent1 + rc = IORegistryEntryGetParentEntry( io_obj_p, kIOServicePlane, &entry1 ); + if ( KERN_SUCCESS == rc ) + { + rc = IORegistryEntryGetParentEntry( entry1, kIOServicePlane, &entry2 ); + + IOObjectRelease( entry1 ); + + if ( KERN_SUCCESS == rc ) + { + rc = IORegistryEntryCreateCFProperties( entry2, &io_properties, kCFAllocatorDefault, kNilOptions ); + // either way, release parent2 + IOObjectRelease( entry2 ); + } + } + if ( KERN_SUCCESS == rc ) + { + // IORegistryEntryCreateCFProperties() succeeded + if ( io_properties != nil ) + { + CFTypeRef dict_element = 0; + // get device info + // try hid dictionary first, if fail then go to usb dictionary + + + dict_element = CFDictionaryGetValue( device_dic, CFSTR(kIOHIDProductKey) ); + if ( !dict_element ) + { + dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Product Name" ) ); + } + if ( dict_element ) + { + bool res = CFStringGetCString((CFStringRef)dict_element, devicep->mProduct, 256, kCFStringEncodingUTF8); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mProduct" << LL_ENDL; + } + } + + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDLocationIDKey ) ); + if ( !dict_element ) + { + dict_element = CFDictionaryGetValue( io_properties, CFSTR( "locationID" ) ); + } + if ( dict_element ) + { + bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mlocalID ); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mLocalID" << LL_ENDL; + } + } + + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsagePageKey ) ); + if ( dict_element ) + { + bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsagePage ); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mUsagePage" << LL_ENDL; + } + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsageKey ) ); + if ( dict_element ) + { + if ( !CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsage ) ) + { + LL_WARNS("Joystick") << "Failed to populate mUsage" << LL_ENDL; + } + } + } + CFRelease(io_properties); + } + else + { + LL_WARNS("Joystick") << "Failed to populate fields" << LL_ENDL; + } + } +} + +HidDevice populate_device( io_object_t io_obj ) +{ + void* interfacep = nullptr; + HidDevice device; + memset( &device, 0, sizeof( HidDevice ) ); + CFMutableDictionaryRef device_dic = 0; + kern_return_t result = IORegistryEntryCreateCFProperties( io_obj, &device_dic, kCFAllocatorDefault, kNilOptions ); + + if ( KERN_SUCCESS == result + && device_dic ) + { + IOReturn io_result = kIOReturnSuccess; + HRESULT query_result = S_OK; + SInt32 the_score = 0; + IOCFPlugInInterface **the_interface = NULL; + + + io_result = IOCreatePlugInInterfaceForService( io_obj, kIOHIDDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, &the_interface, &the_score ); + if ( io_result == kIOReturnSuccess ) + { + query_result = ( *the_interface )->QueryInterface( the_interface, CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID ), ( LPVOID * ) & ( interfacep ) ); + if ( query_result != S_OK ) + { + LL_WARNS("Joystick") << "QueryInterface failed" << LL_ENDL; + } + IODestroyPlugInInterface( the_interface ); + } + else + { + LL_WARNS("Joystick") << "IOCreatePlugInInterfaceForService failed" << LL_ENDL; + } + + if ( interfacep ) + { + result = ( *( IOHIDDeviceInterface** )interfacep )->open( interfacep, 0 ); + + if ( result != kIOReturnSuccess) + { + LL_WARNS("Joystick") << "open failed" << LL_ENDL; + } + } + // extract needed fields + populate_device_info( io_obj, device_dic, &device ); + + // Release interface + if ( interfacep ) + { + ( *( IOHIDDeviceInterface** ) interfacep )->close( interfacep ); + + ( *( IOHIDDeviceInterface** ) interfacep )->Release( interfacep ); + + interfacep = NULL; + } + + CFRelease( device_dic ); + } + else + { + LL_WARNS("Joystick") << "populate_device failed" << LL_ENDL; + } + + return device; +} + +static void get_devices(std::list &list_of_devices, + io_iterator_t inIODeviceIterator) +{ + IOReturn result = kIOReturnSuccess; // assume success( optimist! ) + io_object_t io_obj = 0; + + while ( 0 != (io_obj = IOIteratorNext( inIODeviceIterator ) ) ) + { + HidDevice device = populate_device( io_obj ); + + list_of_devices.push_back(device); + + // release the device object, it is no longer needed + result = IOObjectRelease( io_obj ); + if ( KERN_SUCCESS != result ) + { + LL_WARNS("Joystick") << "IOObjectRelease failed" << LL_ENDL; + } + } +} + +bool LLWindowMacOSX::getInputDevices(U32 device_type_filter, + std::function osx_callback, + void* win_callback, + void* userdata) +{ + CFMutableDictionaryRef device_dict_ref; + IOReturn result = kIOReturnSuccess; // assume success( optimist! ) + + // Set up matching dictionary to search the I/O Registry for HID devices we are interested in. Dictionary reference is NULL if error. + + // A dictionary to match devices to? + device_dict_ref = IOServiceMatching( kIOHIDDeviceKey ); + + // BUG FIX! one reference is consumed by IOServiceGetMatchingServices + CFRetain( device_dict_ref ); + io_iterator_t io_iter = 0; + + // create an IO object iterator + result = IOServiceGetMatchingServices( kIOMasterPortDefault, device_dict_ref, &io_iter ); + if ( kIOReturnSuccess != result ) + { + LL_WARNS("Joystick") << "IOServiceGetMatchingServices failed" << LL_ENDL; + } + + if ( io_iter ) + { + // add all existing devices + std::list device_list; + + get_devices(device_list, io_iter); + + std::list::iterator iter; + + for (iter = device_list.begin(); iter != device_list.end(); ++iter) + { + S32 size = sizeof(long); + LLSD::Binary data; //just an std::vector + data.resize(size); + memcpy(&data[0], &iter->mlocalID, size); + std::string label(iter->mProduct); + + osx_callback(label, data, userdata); + } + } + + CFRelease( device_dict_ref ); + return false; // todo: should be true once UI part gets done +} + LLSD LLWindowMacOSX::getNativeKeyData() { LLSD result = LLSD::emptyMap(); diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 851c860017..cec4f86b25 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -112,6 +112,11 @@ public: void interruptLanguageTextInput() override; void spawnWebBrowser(const std::string& escaped_url, bool async) override; F32 getSystemUISize() override; + + bool getInputDevices(U32 device_type_filter, + std::function osx_callback, + void* win_callback, + void* userdata) override; static std::vector getDisplaysResolutionList(); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 2e560ddb0a..b959c03406 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -4495,7 +4495,10 @@ void* LLWindowWin32::getDirectInput8() return &gDirectInput8; } -bool LLWindowWin32::getInputDevices(U32 device_type_filter, void * di8_devices_callback, void* userdata) +bool LLWindowWin32::getInputDevices(U32 device_type_filter + std::function osx_callback, + void * di8_devices_callback, + void* userdata) { if (gDirectInput8 != NULL) { diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index b391acc12d..6fbb956539 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -129,7 +129,10 @@ public: static void setDPIAwareness(); /*virtual*/ void* getDirectInput8(); - /*virtual*/ bool getInputDevices(U32 device_type_filter, void * di8_devices_callback, void* userdata); + /*virtual*/ bool getInputDevices(U32 device_type_filter, + std::function osx_callback, + void* win_callback, + void* userdata); U32 getRawWParam() { return mRawWParam; } -- cgit v1.3 From 453a4a13f87d5cbfa6150a4f76f9e976692b54e6 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 20 Dec 2022 17:44:08 +0200 Subject: SL-13610 [MAC] WIP enable initing devices by local id --- autobuild.xml | 6 +- indra/llwindow/llwindow.h | 2 +- indra/llwindow/llwindowmacosx.cpp | 11 ++- indra/llwindow/llwindowmacosx.h | 2 +- indra/llwindow/llwindowwin32.cpp | 2 +- indra/llwindow/llwindowwin32.h | 2 +- indra/newview/llfloaterjoystick.cpp | 3 +- indra/newview/llfloaterjoystick.h | 2 +- indra/newview/llviewerjoystick.cpp | 166 +++++++++++++++++++++++++++++------- indra/newview/llviewerjoystick.h | 4 + 10 files changed, 155 insertions(+), 45 deletions(-) (limited to 'indra/llwindow') diff --git a/autobuild.xml b/autobuild.xml index 9785884a40..e07e92421b 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1384,9 +1384,9 @@ archive hash - a487fff84208a45844602c4a1f68c974 + 69c3e7c8cbf47d6f840011d1fa34cd8b url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76356/727333/libndofdev-0.1.555523-darwin64-555523.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/108791/947410/libndofdev-0.1.577357-darwin64-577357.tar.bz2 name darwin64 @@ -1417,7 +1417,7 @@ version - 0.1.555523 + 0.1.577357 libpng diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 2d27092e0a..8ee06a2cc1 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -197,7 +197,7 @@ public: // windows only DirectInput8 for joysticks virtual void* getDirectInput8() { return NULL; }; virtual bool getInputDevices(U32 device_type_filter, - std::function osx_callback, + std::function osx_callback, void* win_callback, void* userdata) { diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index bd13138a7d..914e590ae9 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -2058,10 +2058,11 @@ static void get_devices(std::list &list_of_devices, } bool LLWindowMacOSX::getInputDevices(U32 device_type_filter, - std::function osx_callback, + std::function osx_callback, void* win_callback, void* userdata) { + bool return_value = false; CFMutableDictionaryRef device_dict_ref; IOReturn result = kIOReturnSuccess; // assume success( optimist! ) @@ -2098,12 +2099,16 @@ bool LLWindowMacOSX::getInputDevices(U32 device_type_filter, memcpy(&data[0], &iter->mlocalID, size); std::string label(iter->mProduct); - osx_callback(label, data, userdata); + if (osx_callback(label, data, userdata)) + { + break; //found device + } } + return_value = true; } CFRelease( device_dict_ref ); - return false; // todo: should be true once UI part gets done + return return_value; } LLSD LLWindowMacOSX::getNativeKeyData() diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index cec4f86b25..679bb13335 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -114,7 +114,7 @@ public: F32 getSystemUISize() override; bool getInputDevices(U32 device_type_filter, - std::function osx_callback, + std::function osx_callback, void* win_callback, void* userdata) override; diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index b959c03406..3c7922648b 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -4496,7 +4496,7 @@ void* LLWindowWin32::getDirectInput8() } bool LLWindowWin32::getInputDevices(U32 device_type_filter - std::function osx_callback, + std::function osx_callback, void * di8_devices_callback, void* userdata) { diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 6fbb956539..dcefe6dab2 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -130,7 +130,7 @@ public: /*virtual*/ void* getDirectInput8(); /*virtual*/ bool getInputDevices(U32 device_type_filter, - std::function osx_callback, + std::function osx_callback, void* win_callback, void* userdata); diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp index 5265411e54..18e5858e8d 100644 --- a/indra/newview/llfloaterjoystick.cpp +++ b/indra/newview/llfloaterjoystick.cpp @@ -250,10 +250,11 @@ void LLFloaterJoystick::refresh() initFromSettings(); } -void LLFloaterJoystick::addDeviceCallback(std::string &name, LLSD::Binary& value, void* userdata) +bool LLFloaterJoystick::addDeviceCallback(std::string &name, LLSD::Binary& value, void* userdata) { LLFloaterJoystick * floater = (LLFloaterJoystick*)userdata; floater->mJoysticksCombo->add(name, value, ADD_BOTTOM, 1); + return false; // keep searching } void LLFloaterJoystick::addDevice(std::string &name, LLSD& value) diff --git a/indra/newview/llfloaterjoystick.h b/indra/newview/llfloaterjoystick.h index 912d9b5310..e7049ab906 100644 --- a/indra/newview/llfloaterjoystick.h +++ b/indra/newview/llfloaterjoystick.h @@ -46,7 +46,7 @@ public: virtual void draw(); static void setSNDefaults(); - static void addDeviceCallback(std::string &name, LLSD::Binary& value, void* userdata); + static bool addDeviceCallback(std::string &name, LLSD::Binary& value, void* userdata); void addDevice(std::string &name, LLSD& value); protected: diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index 26a626f60f..e182b31ed2 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -229,9 +229,17 @@ std::string string_from_guid(const GUID &guid) } #elif LL_DARWIN -bool macos_devices_callback(std::string &product, LLSD::Binary &data, void* userdata) +bool macos_devices_callback(std::string &product_name, LLSD::Binary &data, void* userdata) { - //LLViewerJoystick::getInstance()->initDevice(&device, product_name, data); + S32 size = sizeof(long); + long id; + memcpy(&id, &data[0], size); + + NDOF_Device *device = ndof_idsearch(id); + if (device) + { + return LLViewerJoystick::getInstance()->initDevice(device, data); + } return false; } @@ -374,27 +382,50 @@ void LLViewerJoystick::init(bool autoenable) { if (mNdofDev) { + U32 device_type = 0; void* win_callback = nullptr; - std::function osx_callback; + std::function osx_callback; // di8_devices_callback callback is immediate and happens in scope of getInputDevices() #if LL_WINDOWS && !LL_MESA_HEADLESS // space navigator is marked as DI8DEVCLASS_GAMECTRL in ndof lib - U32 device_type = DI8DEVCLASS_GAMECTRL; + device_type = DI8DEVCLASS_GAMECTRL; win_callback = &di8_devices_callback; -#else - // MAC doesn't support device search yet - // On MAC there is an ndof_idsearch and it is possible to specify product - // and manufacturer in NDOF_Device for ndof_init_first to pick specific one - U32 device_type = 0; +#elif LL_DARWIN osx_callback = macos_devices_callback; + + if (mLastDeviceUUID.isBinary()) + { + S32 size = sizeof(long); + long id; + memcpy(&id, &mLastDeviceUUID[0], size); + + NDOF_Device *device = ndof_idsearch(id); + if (device) + { + if (ndof_init_first(device, nullptr)) + { + mDriverState = JDS_INITIALIZING; + // Saved device no longer exist + LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; + } + else + { + mNdofDev = device; + mDriverState = JDS_INITIALIZED; + } + } + } #endif - if (!gViewerWindow->getWindow()->getInputDevices(device_type, osx_callback, win_callback, NULL)) + if (mDriverState != JDS_INITIALIZED) { - LL_INFOS("Joystick") << "Failed to gather devices from window. Falling back to ndof's init" << LL_ENDL; - // Failed to gather devices from windows, init first suitable one - mLastDeviceUUID = LLSD(); - void *preffered_device = NULL; - initDevice(preffered_device); + if (!gViewerWindow->getWindow()->getInputDevices(device_type, osx_callback, win_callback, NULL)) + { + LL_INFOS("Joystick") << "Failed to gather input devices. Falling back to ndof's init" << LL_ENDL; + // Failed to gather devices, init first suitable one + mLastDeviceUUID = LLSD(); + void *preffered_device = NULL; + initDevice(preffered_device); + } } if (mDriverState == JDS_INITIALIZING) @@ -449,29 +480,51 @@ void LLViewerJoystick::initDevice(LLSD &guid) { #if LIB_NDOF mLastDeviceUUID = guid; + U32 device_type = 0; void* win_callback = nullptr; - std::function osx_callback; - + std::function osx_callback; + mDriverState = JDS_INITIALIZING; + #if LL_WINDOWS && !LL_MESA_HEADLESS // space navigator is marked as DI8DEVCLASS_GAMECTRL in ndof lib - U32 device_type = DI8DEVCLASS_GAMECTRL; + device_type = DI8DEVCLASS_GAMECTRL; win_callback = &di8_devices_callback; -#else - // MAC doesn't support device search yet - // On MAC there is an ndof_idsearch and it is possible to specify product - // and manufacturer in NDOF_Device for ndof_init_first to pick specific one - U32 device_type = 0; +#elif LL_DARWIN osx_callback = macos_devices_callback; + if (mLastDeviceUUID.isBinary()) + { + S32 size = sizeof(long); + long id; + memcpy(&id, &mLastDeviceUUID[0], size); + + NDOF_Device *device = ndof_idsearch(id); + if (device) + { + if (ndof_init_first(device, nullptr)) + { + mDriverState = JDS_INITIALIZING; + // Saved device no longer exist + LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; + } + else + { + mNdofDev = device; + mDriverState = JDS_INITIALIZED; + } + } + } #endif - mDriverState = JDS_INITIALIZING; - if (!gViewerWindow->getWindow()->getInputDevices(device_type, osx_callback, win_callback, NULL)) + if (mDriverState != JDS_INITIALIZED) { - LL_INFOS("Joystick") << "Failed to gather devices from window. Falling back to ndof's init" << LL_ENDL; - // Failed to gather devices from windows, init first suitable one - void *preffered_device = NULL; - mLastDeviceUUID = LLSD(); - initDevice(preffered_device); + if (!gViewerWindow->getWindow()->getInputDevices(device_type, osx_callback, win_callback, NULL)) + { + LL_INFOS("Joystick") << "Failed to gather input devices. Falling back to ndof's init" << LL_ENDL; + // Failed to gather devices from windows, init first suitable one + void *preffered_device = NULL; + mLastDeviceUUID = LLSD(); + initDevice(preffered_device); + } } if (mDriverState == JDS_INITIALIZING) @@ -528,6 +581,25 @@ void LLViewerJoystick::initDevice(void * preffered_device /* LPDIRECTINPUTDEVICE #endif } +bool LLViewerJoystick::initDevice(NDOF_Device * ndof_device, LLSD::Binary &data) +{ + mLastDeviceUUID = data; +#if LIB_NDOF + if (ndof_init_first(ndof_device, nullptr)) + { + mDriverState = JDS_UNINITIALIZED; + LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; + } + else + { + mNdofDev = ndof_device; + mDriverState = JDS_INITIALIZED; + return true; + } +#endif + return false; +} + // ----------------------------------------------------------------------------- void LLViewerJoystick::terminate() { @@ -1359,9 +1431,21 @@ std::string LLViewerJoystick::getDeviceUUIDString() { return std::string(); } +#elif LL_DARWIN + if (mLastDeviceUUID.isBinary()) + { + S32 size = sizeof(long); + LLSD::Binary data = mLastDeviceUUID.asBinary(); + long id; + memcpy(&id, &data[0], size); + return std::to_string(id); + } + else + { + return std::string(); + } #else return std::string(); - // return mLastDeviceUUID; #endif } @@ -1385,8 +1469,24 @@ void LLViewerJoystick::loadDeviceIdFromSettings() LLSD::Binary data; //just an std::vector data.resize(size); memcpy(&data[0], &guid /*POD _GUID*/, size); - // We store this data in LLSD since LLSD is versatile and will be able to handle both GUID2 - // and any data MAC will need for device selection + // We store this data in LLSD since it can handle both GUID2 and long + mLastDeviceUUID = LLSD(data); + } +#elif LL_DARWIN + std::string device_string = gSavedSettings.getString("JoystickDeviceUUID"); + if (device_string.empty()) + { + mLastDeviceUUID = LLSD(); + } + else + { + LL_DEBUGS("Joystick") << "Looking for device by id: " << device_string << LL_ENDL; + long id = std::stol(device_string); + S32 size = sizeof(long); + LLSD::Binary data; //just an std::vector + data.resize(size); + memcpy(&data[0], &id, size); + // We store this data in LLSD since it can handle both GUID2 and long mLastDeviceUUID = LLSD(data); } #else diff --git a/indra/newview/llviewerjoystick.h b/indra/newview/llviewerjoystick.h index 49f8c8eabf..0e5629497d 100644 --- a/indra/newview/llviewerjoystick.h +++ b/indra/newview/llviewerjoystick.h @@ -30,6 +30,9 @@ #include "stdtypes.h" #if LIB_NDOF +#if LL_DARWIN +#define TARGET_OS_MAC 1 +#endif #include "ndofdev_external.h" #else #define NDOF_Device void @@ -54,6 +57,7 @@ public: void initDevice(LLSD &guid); void initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/); void initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/, std::string &name, LLSD &guid); + bool initDevice(NDOF_Device * ndof_device, LLSD::Binary &guid); void terminate(); void updateStatus(); -- cgit v1.3 From 6481d36c69dbcafdb23cb27dc07aa047b3d7d64e Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 27 Dec 2022 15:27:29 +0200 Subject: SL-13610 [MAC] WIP filter out incompatible devices --- indra/llwindow/llwindowmacosx.cpp | 95 ++++++++++++++++++++++++++++++++++---- indra/newview/llviewerjoystick.cpp | 2 + 2 files changed, 89 insertions(+), 8 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 914e590ae9..3cb5939dc9 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -1862,11 +1862,13 @@ struct hu_element_t }; struct HidDevice -{ // interface to device, NULL = no interface - char mProduct[256]; // name of product - long mlocalID; // long representing location in USB( or other I/O ) chain which device is pluged into, can identify specific device on machine - long mUsage; // usage page from IOUSBHID Parser.h which defines general usage - long mUsagePage; // usage within above page from IOUSBHID Parser.h which defines specific usage +{ + long mAxis; + long mLocalID; + char mProduct[256]; + char mManufacturer[256]; + long mUsage; + long mUsagePage; }; /************************************************************************* @@ -1931,6 +1933,20 @@ static void populate_device_info( io_object_t io_obj_p, CFDictionaryRef device_d } } + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDManufacturerKey ) ); + if ( !dict_element ) + { + dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Vendor Name" ) ); + } + if ( dict_element ) + { + bool res = CFStringGetCString( (CFStringRef)dict_element, devicep->mManufacturer, 256, kCFStringEncodingUTF8 ); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mManufacturer" << LL_ENDL; + } + } + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDLocationIDKey ) ); if ( !dict_element ) { @@ -1938,7 +1954,7 @@ static void populate_device_info( io_object_t io_obj_p, CFDictionaryRef device_d } if ( dict_element ) { - bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mlocalID ); + bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mLocalID ); if ( !res ) { LL_WARNS("Joystick") << "Failed to populate mLocalID" << LL_ENDL; @@ -1962,6 +1978,59 @@ static void populate_device_info( io_object_t io_obj_p, CFDictionaryRef device_d } } } + + //Add axis, because ndof lib checks sutability by axises as well as other elements + devicep->mAxis = 0; + CFTypeRef hid_elements = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDElementKey ) ); + if ( hid_elements && CFGetTypeID( hid_elements ) == CFArrayGetTypeID( ) ) + { + long count = CFArrayGetCount( (CFArrayRef) hid_elements ); + for (int i = 0; i < count; ++i) + { + CFTypeRef element = CFArrayGetValueAtIndex((CFArrayRef) hid_elements, i); + if (element && CFGetTypeID( element ) == CFDictionaryGetTypeID( )) + { + long type = 0, usage_page = 0, usage = 0; + + CFTypeRef ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementTypeKey ) ); + if ( ref_value ) + { + CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &type ); + } + + ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsagePageKey ) ); + if ( ref_value ) + { + CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage_page ); + } + + ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsageKey ) ); + if ( ref_value ) + { + CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage ); + } + if ( type != 0 + && type != kIOHIDElementTypeCollection + && usage_page == kHIDPage_GenericDesktop) + { + switch( usage ) + { + case kHIDUsage_GD_X: + case kHIDUsage_GD_Y: + case kHIDUsage_GD_Z: + case kHIDUsage_GD_Rx: + case kHIDUsage_GD_Ry: + case kHIDUsage_GD_Rz: + devicep->mAxis++; + break; + default: + break; + } + } + } + } + } + CFRelease(io_properties); } else @@ -2046,7 +2115,17 @@ static void get_devices(std::list &list_of_devices, { HidDevice device = populate_device( io_obj ); - list_of_devices.push_back(device); + if (device.mAxis >= 3 + || (device.mUsagePage == kHIDPage_GenericDesktop + && (device.mUsage == kHIDUsage_GD_MultiAxisController + || device.mUsage == kHIDUsage_GD_GamePad + || device.mUsage == kHIDUsage_GD_Joystick)) + || (device.mUsagePage == kHIDPage_Game + && (device.mUsage == kHIDUsage_Game_3DGameController)) + || strstr(device.mManufacturer, "3Dconnexion")) + { + list_of_devices.push_back(device); + } // release the device object, it is no longer needed result = IOObjectRelease( io_obj ); @@ -2096,7 +2175,7 @@ bool LLWindowMacOSX::getInputDevices(U32 device_type_filter, S32 size = sizeof(long); LLSD::Binary data; //just an std::vector data.resize(size); - memcpy(&data[0], &iter->mlocalID, size); + memcpy(&data[0], &iter->mLocalID, size); std::string label(iter->mProduct); if (osx_callback(label, data, userdata)) diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index e182b31ed2..95cfa5cd78 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -399,6 +399,7 @@ void LLViewerJoystick::init(bool autoenable) long id; memcpy(&id, &mLastDeviceUUID[0], size); + // todo: search by manufcturer instead, locid might have changed NDOF_Device *device = ndof_idsearch(id); if (device) { @@ -500,6 +501,7 @@ void LLViewerJoystick::initDevice(LLSD &guid) NDOF_Device *device = ndof_idsearch(id); if (device) { + // todo: search by manufcturer instead, locid might have changed if (ndof_init_first(device, nullptr)) { mDriverState = JDS_INITIALIZING; -- cgit v1.3 From 3084f864176dffbc5da19e6f958a55513f63e795 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 29 Dec 2022 19:16:15 +0200 Subject: SL-13610 [MAC] Manufacturer based search --- autobuild.xml | 6 +- indra/llwindow/llwindow.h | 2 +- indra/llwindow/llwindowmacosx.cpp | 251 ++++++++++++++++++++++---------- indra/llwindow/llwindowmacosx.h | 2 +- indra/llwindow/llwindowwin32.cpp | 2 +- indra/llwindow/llwindowwin32.h | 2 +- indra/newview/app_settings/settings.xml | 2 +- indra/newview/llfloaterjoystick.cpp | 17 ++- indra/newview/llfloaterjoystick.h | 2 +- indra/newview/llviewerjoystick.cpp | 175 +++++++++++----------- indra/newview/llviewerjoystick.h | 6 +- 11 files changed, 288 insertions(+), 179 deletions(-) (limited to 'indra/llwindow') diff --git a/autobuild.xml b/autobuild.xml index e07e92421b..9785884a40 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1384,9 +1384,9 @@ archive hash - 69c3e7c8cbf47d6f840011d1fa34cd8b + a487fff84208a45844602c4a1f68c974 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/108791/947410/libndofdev-0.1.577357-darwin64-577357.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76356/727333/libndofdev-0.1.555523-darwin64-555523.tar.bz2 name darwin64 @@ -1417,7 +1417,7 @@ version - 0.1.577357 + 0.1.555523 libpng diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 8ee06a2cc1..45049e1539 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -197,7 +197,7 @@ public: // windows only DirectInput8 for joysticks virtual void* getDirectInput8() { return NULL; }; virtual bool getInputDevices(U32 device_type_filter, - std::function osx_callback, + std::function osx_callback, void* win_callback, void* userdata) { diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 3cb5939dc9..aa87a6803f 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -1813,53 +1813,158 @@ void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async) } } +// String should match ndof, so string mapping code was copied as is +static char mapChar( char c ) +{ + unsigned char uc = ( unsigned char ) c; + + switch( uc ) + { + case '/': return '-'; // use dash instead of slash + + case 0x7F: return ' '; + case 0x80: return 'A'; + case 0x81: return 'A'; + case 0x82: return 'C'; + case 0x83: return 'E'; + case 0x84: return 'N'; + case 0x85: return 'O'; + case 0x86: return 'U'; + case 0x87: return 'a'; + case 0x88: return 'a'; + case 0x89: return 'a'; + case 0x8A: return 'a'; + case 0x8B: return 'a'; + case 0x8C: return 'a'; + case 0x8D: return 'c'; + case 0x8E: return 'e'; + case 0x8F: return 'e'; + case 0x90: return ' '; + case 0x91: return ' '; // ? ' + case 0x92: return ' '; // ? ' + case 0x93: return ' '; // ? " + case 0x94: return ' '; // ? " + case 0x95: return ' '; + case 0x96: return ' '; + case 0x97: return ' '; + case 0x98: return ' '; + case 0x99: return ' '; + case 0x9A: return ' '; + case 0x9B: return 0x27; + case 0x9C: return 0x22; + case 0x9D: return ' '; + case 0x9E: return ' '; + case 0x9F: return ' '; + case 0xA0: return ' '; + case 0xA1: return ' '; + case 0xA2: return ' '; + case 0xA3: return ' '; + case 0xA4: return ' '; + case 0xA5: return ' '; + case 0xA6: return ' '; + case 0xA7: return ' '; + case 0xA8: return ' '; + case 0xA9: return ' '; + case 0xAA: return ' '; + case 0xAB: return ' '; + case 0xAC: return ' '; + case 0xAD: return ' '; + case 0xAE: return ' '; + case 0xAF: return ' '; + case 0xB0: return ' '; + case 0xB1: return ' '; + case 0xB2: return ' '; + case 0xB3: return ' '; + case 0xB4: return ' '; + case 0xB5: return ' '; + case 0xB6: return ' '; + case 0xB7: return ' '; + case 0xB8: return ' '; + case 0xB9: return ' '; + case 0xBA: return ' '; + case 0xBB: return ' '; + case 0xBC: return ' '; + case 0xBD: return ' '; + case 0xBE: return ' '; + case 0xBF: return ' '; + case 0xC0: return ' '; + case 0xC1: return ' '; + case 0xC2: return ' '; + case 0xC3: return ' '; + case 0xC4: return ' '; + case 0xC5: return ' '; + case 0xC6: return ' '; + case 0xC7: return ' '; + case 0xC8: return ' '; + case 0xC9: return ' '; + case 0xCA: return ' '; + case 0xCB: return 'A'; + case 0xCC: return 'A'; + case 0xCD: return 'O'; + case 0xCE: return ' '; + case 0xCF: return ' '; + case 0xD0: return '-'; + case 0xD1: return '-'; + case 0xD2: return 0x22; + case 0xD3: return 0x22; + case 0xD4: return 0x27; + case 0xD5: return 0x27; + case 0xD6: return '-'; // use dash instead of slash + case 0xD7: return ' '; + case 0xD8: return 'y'; + case 0xD9: return 'Y'; + case 0xDA: return '-'; // use dash instead of slash + case 0xDB: return ' '; + case 0xDC: return '<'; + case 0xDD: return '>'; + case 0xDE: return ' '; + case 0xDF: return ' '; + case 0xE0: return ' '; + case 0xE1: return ' '; + case 0xE2: return ','; + case 0xE3: return ','; + case 0xE4: return ' '; + case 0xE5: return 'A'; + case 0xE6: return 'E'; + case 0xE7: return 'A'; + case 0xE8: return 'E'; + case 0xE9: return 'E'; + case 0xEA: return 'I'; + case 0xEB: return 'I'; + case 0xEC: return 'I'; + case 0xED: return 'I'; + case 0xEE: return 'O'; + case 0xEF: return 'O'; + case 0xF0: return ' '; + case 0xF1: return 'O'; + case 0xF2: return 'U'; + case 0xF3: return 'U'; + case 0xF4: return 'U'; + case 0xF5: return '|'; + case 0xF6: return ' '; + case 0xF7: return ' '; + case 0xF8: return ' '; + case 0xF9: return ' '; + case 0xFA: return '.'; + case 0xFB: return ' '; + case 0xFC: return ' '; + case 0xFD: return 0x22; + case 0xFE: return ' '; + case 0xFF: return ' '; + } + return c; +} -// Device and Element Interfaces - -typedef enum HIDElementTypeMask -{ - kHIDElementTypeInput = 1 << 1, - kHIDElementTypeOutput = 1 << 2, - kHIDElementTypeFeature = 1 << 3, - kHIDElementTypeCollection = 1 << 4, - kHIDElementTypeIO = kHIDElementTypeInput | kHIDElementTypeOutput | kHIDElementTypeFeature, - kHIDElementTypeAll = kHIDElementTypeIO | kHIDElementTypeCollection -}HIDElementTypeMask; - -struct hu_element_t -{ - unsigned long type; // the type defined by IOHIDElementType in IOHIDKeys.h - long usage; // usage within above page from IOUSBHIDParser.h which defines specific usage - long usagePage; // usage page from IOUSBHIDParser.h which defines general usage - void* cookie; // unique value( within device of specific vendorID and productID ) which identifies element, will NOT change - long min; // reported min value possible - long max; // reported max value possible - long scaledMin; // reported scaled min value possible - long scaledMax; // reported scaled max value possible - long size; // size in bits of data return from element - unsigned char relative; // are reports relative to last report( deltas ) - unsigned char wrapping; // does element wrap around( one value higher than max is min ) - unsigned char nonLinear; // are the values reported non-linear relative to element movement - unsigned char preferredState; // does element have a preferred state( such as a button ) - unsigned char nullState; // does element have null state - long units; // units value is reported in( not used very often ) - long unitExp; // exponent for units( also not used very often ) - char name[256]; // name of element( c string ) - - // runtime variables - long initialCenter; // center value at start up - unsigned char hasCenter; // whether or not to use center for calibration - long minReport; // min returned value - long maxReport; // max returned value( calibrate call ) - long userMin; // user set value to scale to( scale call ) - long userMax; - - struct hu_element_t* pPrevious; // previous element( NULL at list head ) - struct hu_element_t* pChild; // next child( only of collections ) - struct hu_element_t* pSibling; // next sibling( for elements and collections ) - - long depth; -}; +// String should match ndof for manufacturer based search to work +static void sanitizeString( char* inCStr ) +{ + char* charIt = inCStr; + while ( *charIt ) + { + *charIt = mapChar( *charIt ); + charIt++; + } +} struct HidDevice { @@ -1871,20 +1976,6 @@ struct HidDevice long mUsagePage; }; -/************************************************************************* -* -* hu_BuildDevice( inHIDDevice ) -* -* Purpose: given a IO device object build a flat device record including device info and all elements -* -* Notes: handles NULL lists properly -* -* Inputs: inHIDDevice - the I/O device object -* -* Returns: hu_device_t* - the address of the new device record -*/ - - static void populate_device_info( io_object_t io_obj_p, CFDictionaryRef device_dic, HidDevice* devicep ) { CFMutableDictionaryRef io_properties = nil; @@ -1927,6 +2018,7 @@ static void populate_device_info( io_object_t io_obj_p, CFDictionaryRef device_d if ( dict_element ) { bool res = CFStringGetCString((CFStringRef)dict_element, devicep->mProduct, 256, kCFStringEncodingUTF8); + sanitizeString(devicep->mProduct); if ( !res ) { LL_WARNS("Joystick") << "Failed to populate mProduct" << LL_ENDL; @@ -1941,6 +2033,7 @@ static void populate_device_info( io_object_t io_obj_p, CFDictionaryRef device_d if ( dict_element ) { bool res = CFStringGetCString( (CFStringRef)dict_element, devicep->mManufacturer, 256, kCFStringEncodingUTF8 ); + sanitizeString(devicep->mManufacturer); if ( !res ) { LL_WARNS("Joystick") << "Failed to populate mManufacturer" << LL_ENDL; @@ -2115,18 +2208,31 @@ static void get_devices(std::list &list_of_devices, { HidDevice device = populate_device( io_obj ); - if (device.mAxis >= 3 - || (device.mUsagePage == kHIDPage_GenericDesktop - && (device.mUsage == kHIDUsage_GD_MultiAxisController - || device.mUsage == kHIDUsage_GD_GamePad - || device.mUsage == kHIDUsage_GD_Joystick)) - || (device.mUsagePage == kHIDPage_Game - && (device.mUsage == kHIDUsage_Game_3DGameController)) - || strstr(device.mManufacturer, "3Dconnexion")) + if (debugLoggingEnabled("Joystick")) { list_of_devices.push_back(device); + LL_DEBUGS("Joystick") << "Device axises: " << (S32)device.mAxis + << "Device HIDUsepage: " << (S32)device.mUsagePage + << "Device HIDUsage: " << (S32)device.mUsage + << LL_ENDL; + } + else + { + // Should match ndof + if (device.mAxis >= 3 + || (device.mUsagePage == kHIDPage_GenericDesktop + && (device.mUsage == kHIDUsage_GD_MultiAxisController + || device.mUsage == kHIDUsage_GD_GamePad + || device.mUsage == kHIDUsage_GD_Joystick)) + || (device.mUsagePage == kHIDPage_Game + && device.mUsage == kHIDUsage_Game_3DGameController) + || strstr(device.mManufacturer, "3Dconnexion")) + { + list_of_devices.push_back(device); + } } + // release the device object, it is no longer needed result = IOObjectRelease( io_obj ); if ( KERN_SUCCESS != result ) @@ -2137,7 +2243,7 @@ static void get_devices(std::list &list_of_devices, } bool LLWindowMacOSX::getInputDevices(U32 device_type_filter, - std::function osx_callback, + std::function osx_callback, void* win_callback, void* userdata) { @@ -2172,11 +2278,10 @@ bool LLWindowMacOSX::getInputDevices(U32 device_type_filter, for (iter = device_list.begin(); iter != device_list.end(); ++iter) { - S32 size = sizeof(long); - LLSD::Binary data; //just an std::vector - data.resize(size); - memcpy(&data[0], &iter->mLocalID, size); std::string label(iter->mProduct); + LLSD data; + data["manufacturer"] = std::string(iter->mManufacturer); + data["product"] = label; if (osx_callback(label, data, userdata)) { diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 679bb13335..19136aa3de 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -114,7 +114,7 @@ public: F32 getSystemUISize() override; bool getInputDevices(U32 device_type_filter, - std::function osx_callback, + std::function osx_callback, void* win_callback, void* userdata) override; diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 3c7922648b..60bd3b080d 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -4496,7 +4496,7 @@ void* LLWindowWin32::getDirectInput8() } bool LLWindowWin32::getInputDevices(U32 device_type_filter - std::function osx_callback, + std::function osx_callback, void * di8_devices_callback, void* userdata) { diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index dcefe6dab2..b0d5c557b8 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -130,7 +130,7 @@ public: /*virtual*/ void* getDirectInput8(); /*virtual*/ bool getInputDevices(U32 device_type_filter, - std::function osx_callback, + std::function osx_callback, void* win_callback, void* userdata); diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index ff7232830b..3e17c434a3 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3770,7 +3770,7 @@ Persist 1 Type - String + LLSD Value diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp index 18e5858e8d..d3add020cf 100644 --- a/indra/newview/llfloaterjoystick.cpp +++ b/indra/newview/llfloaterjoystick.cpp @@ -250,7 +250,7 @@ void LLFloaterJoystick::refresh() initFromSettings(); } -bool LLFloaterJoystick::addDeviceCallback(std::string &name, LLSD::Binary& value, void* userdata) +bool LLFloaterJoystick::addDeviceCallback(std::string &name, LLSD& value, void* userdata) { LLFloaterJoystick * floater = (LLFloaterJoystick*)userdata; floater->mJoysticksCombo->add(name, value, ADD_BOTTOM, 1); @@ -280,9 +280,9 @@ void LLFloaterJoystick::refreshListOfDevices() #elif LL_DARWIN U32 device_type = 0; #else - // MAC doesn't support device search yet - // On MAC there is an ndof_idsearch and it is possible to specify product - // and manufacturer in NDOF_Device for ndof_init_first to pick specific one + // On MAC it is possible to specify product + // and manufacturer in NDOF_Device for + // ndof_init_first to pick specific device U32 device_type = 0; #endif if (gViewerWindow->getWindow()->getInputDevices(device_type, addDeviceCallback, win_calback, this)) @@ -427,10 +427,11 @@ void LLFloaterJoystick::onCommitJoystickEnabled(LLUICtrl*, void *joy_panel) joystick->toggleFlycam(); } } - - std::string device_id = LLViewerJoystick::getInstance()->getDeviceUUIDString(); - gSavedSettings.setString("JoystickDeviceUUID", device_id); - LL_DEBUGS("Joystick") << "Selected " << device_id << " as joystick." << LL_ENDL; + + LLViewerJoystick::getInstance()->saveDeviceIdToSettings(); + + std::string device_string = LLViewerJoystick::getInstance()->getDeviceUUIDString(); + LL_DEBUGS("Joystick") << "Selected " << device_string << " as joystick." << LL_ENDL; self->refreshListOfDevices(); } diff --git a/indra/newview/llfloaterjoystick.h b/indra/newview/llfloaterjoystick.h index e7049ab906..ff889c804b 100644 --- a/indra/newview/llfloaterjoystick.h +++ b/indra/newview/llfloaterjoystick.h @@ -46,7 +46,7 @@ public: virtual void draw(); static void setSNDefaults(); - static bool addDeviceCallback(std::string &name, LLSD::Binary& value, void* userdata); + static bool addDeviceCallback(std::string &name, LLSD& value, void* userdata); void addDevice(std::string &name, LLSD& value); protected: diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index 95cfa5cd78..ef96ea4493 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -229,18 +229,11 @@ std::string string_from_guid(const GUID &guid) } #elif LL_DARWIN -bool macos_devices_callback(std::string &product_name, LLSD::Binary &data, void* userdata) +bool macos_devices_callback(std::string &product_name, LLSD &data, void* userdata) { - S32 size = sizeof(long); - long id; - memcpy(&id, &data[0], size); + std::string product = data["product"].asString(); - NDOF_Device *device = ndof_idsearch(id); - if (device) - { - return LLViewerJoystick::getInstance()->initDevice(device, data); - } - return false; + return LLViewerJoystick::getInstance()->initDevice(nullptr, product, data); } #endif @@ -384,7 +377,7 @@ void LLViewerJoystick::init(bool autoenable) { U32 device_type = 0; void* win_callback = nullptr; - std::function osx_callback; + std::function osx_callback; // di8_devices_callback callback is immediate and happens in scope of getInputDevices() #if LL_WINDOWS && !LL_MESA_HEADLESS // space navigator is marked as DI8DEVCLASS_GAMECTRL in ndof lib @@ -393,27 +386,24 @@ void LLViewerJoystick::init(bool autoenable) #elif LL_DARWIN osx_callback = macos_devices_callback; - if (mLastDeviceUUID.isBinary()) + if (mLastDeviceUUID.isMap()) { - S32 size = sizeof(long); - long id; - memcpy(&id, &mLastDeviceUUID[0], size); + std::string manufacturer = mLastDeviceUUID["manufacturer"].asString(); + std::string product = mLastDeviceUUID["product"].asString(); + + strncpy(mNdofDev->manufacturer, manufacturer.c_str(), sizeof(mNdofDev->manufacturer)); + strncpy(mNdofDev->product, product.c_str(), sizeof(mNdofDev->product)); - // todo: search by manufcturer instead, locid might have changed - NDOF_Device *device = ndof_idsearch(id); - if (device) + if (ndof_init_first(mNdofDev, nullptr)) { - if (ndof_init_first(device, nullptr)) - { - mDriverState = JDS_INITIALIZING; - // Saved device no longer exist - LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; - } - else - { - mNdofDev = device; - mDriverState = JDS_INITIALIZED; - } + mDriverState = JDS_INITIALIZING; + // Saved device no longer exist + // No device found + LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; + } + else + { + mDriverState = JDS_INITIALIZED; } } #endif @@ -483,7 +473,7 @@ void LLViewerJoystick::initDevice(LLSD &guid) mLastDeviceUUID = guid; U32 device_type = 0; void* win_callback = nullptr; - std::function osx_callback; + std::function osx_callback; mDriverState = JDS_INITIALIZING; #if LL_WINDOWS && !LL_MESA_HEADLESS @@ -492,27 +482,24 @@ void LLViewerJoystick::initDevice(LLSD &guid) win_callback = &di8_devices_callback; #elif LL_DARWIN osx_callback = macos_devices_callback; - if (mLastDeviceUUID.isBinary()) + if (mLastDeviceUUID.isMap()) { - S32 size = sizeof(long); - long id; - memcpy(&id, &mLastDeviceUUID[0], size); + std::string manufacturer = mLastDeviceUUID["manufacturer"].asString(); + std::string product = mLastDeviceUUID["product"].asString(); - NDOF_Device *device = ndof_idsearch(id); - if (device) + strncpy(mNdofDev->manufacturer, manufacturer.c_str(), sizeof(mNdofDev->manufacturer)); + strncpy(mNdofDev->product, product.c_str(), sizeof(mNdofDev->product)); + + if (ndof_init_first(mNdofDev, nullptr)) { - // todo: search by manufcturer instead, locid might have changed - if (ndof_init_first(device, nullptr)) - { - mDriverState = JDS_INITIALIZING; - // Saved device no longer exist - LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; - } - else - { - mNdofDev = device; - mDriverState = JDS_INITIALIZED; - } + mDriverState = JDS_INITIALIZING; + // Saved device no longer exist + // Np other device present + LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; + } + else + { + mDriverState = JDS_INITIALIZED; } } #endif @@ -522,7 +509,7 @@ void LLViewerJoystick::initDevice(LLSD &guid) if (!gViewerWindow->getWindow()->getInputDevices(device_type, osx_callback, win_callback, NULL)) { LL_INFOS("Joystick") << "Failed to gather input devices. Falling back to ndof's init" << LL_ENDL; - // Failed to gather devices from windows, init first suitable one + // Failed to gather devices from window, init first suitable one void *preffered_device = NULL; mLastDeviceUUID = LLSD(); initDevice(preffered_device); @@ -537,19 +524,37 @@ void LLViewerJoystick::initDevice(LLSD &guid) #endif } -void LLViewerJoystick::initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/, std::string &name, LLSD &guid) +bool LLViewerJoystick::initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/, std::string &name, LLSD &guid) { #if LIB_NDOF mLastDeviceUUID = guid; - + +#if LL_DARWIN + if (guid.isMap()) + { + std::string manufacturer = mLastDeviceUUID["manufacturer"].asString(); + std::string product = mLastDeviceUUID["product"].asString(); + + strncpy(mNdofDev->manufacturer, manufacturer.c_str(), sizeof(mNdofDev->manufacturer)); + strncpy(mNdofDev->product, product.c_str(), sizeof(mNdofDev->product)); + } + else + { + mNdofDev->product[0] = '\0'; + mNdofDev->manufacturer[0] = '\0'; + } +#else strncpy(mNdofDev->product, name.c_str(), sizeof(mNdofDev->product)); mNdofDev->manufacturer[0] = '\0'; +#endif - initDevice(preffered_device); + return initDevice(preffered_device); +#else + return false; #endif } -void LLViewerJoystick::initDevice(void * preffered_device /* LPDIRECTINPUTDEVICE8* */) +bool LLViewerJoystick::initDevice(void * preffered_device /* LPDIRECTINPUTDEVICE8* */) { #if LIB_NDOF // Different joysticks will return different ranges of raw values. @@ -579,23 +584,6 @@ void LLViewerJoystick::initDevice(void * preffered_device /* LPDIRECTINPUTDEVICE else { mDriverState = JDS_INITIALIZED; - } -#endif -} - -bool LLViewerJoystick::initDevice(NDOF_Device * ndof_device, LLSD::Binary &data) -{ - mLastDeviceUUID = data; -#if LIB_NDOF - if (ndof_init_first(ndof_device, nullptr)) - { - mDriverState = JDS_UNINITIALIZED; - LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; - } - else - { - mNdofDev = ndof_device; - mDriverState = JDS_INITIALIZED; return true; } #endif @@ -1407,6 +1395,8 @@ bool LLViewerJoystick::isDeviceUUIDSet() #if LL_WINDOWS && !LL_MESA_HEADLESS // for ease of comparison and to dial less with platform specific variables, we store id as LLSD binary return mLastDeviceUUID.isBinary(); +#elif LL_DARWIN + return mLastDeviceUUID.isMap(); #else return false; #endif @@ -1434,13 +1424,11 @@ std::string LLViewerJoystick::getDeviceUUIDString() return std::string(); } #elif LL_DARWIN - if (mLastDeviceUUID.isBinary()) + if (mLastDeviceUUID.isMap()) { - S32 size = sizeof(long); - LLSD::Binary data = mLastDeviceUUID.asBinary(); - long id; - memcpy(&id, &data[0], size); - return std::to_string(id); + std::string manufacturer = mLastDeviceUUID["manufacturer"].asString(); + std::string product = mLastDeviceUUID["product"].asString(); + return manufacturer + ":" + product; } else { @@ -1451,13 +1439,32 @@ std::string LLViewerJoystick::getDeviceUUIDString() #endif } +void LLViewerJoystick::saveDeviceIdToSettings() +{ +#if LL_WINDOWS && !LL_MESA_HEADLESS + // can't save as binary directly, + // someone editing the xml will corrupt it + // so convert to string first + std::string device_string = getDeviceUUIDString(); + gSavedSettings.setLLSD("JoystickDeviceUUID", LLSD(device_string); +#else + LLSD device_id = getDeviceUUID(); + gSavedSettings.setLLSD("JoystickDeviceUUID", device_id); +#endif +} + void LLViewerJoystick::loadDeviceIdFromSettings() { + LLSD dev_id = gSavedSettings.getLLSD("JoystickDeviceUUID"); #if LL_WINDOWS && !LL_MESA_HEADLESS // We can't save binary data to gSavedSettings, somebody editing the file will corrupt it, // so _GUID data gets converted to string (we probably can convert it to LLUUID with memcpy) // and here we need to convert it back to binary from string - std::string device_string = gSavedSettings.getString("JoystickDeviceUUID"); + std::string device_string; + if (dev_id.isString()) + { + device_string = dev_id.asString(); + } if (device_string.empty()) { mLastDeviceUUID = LLSD(); @@ -1475,21 +1482,17 @@ void LLViewerJoystick::loadDeviceIdFromSettings() mLastDeviceUUID = LLSD(data); } #elif LL_DARWIN - std::string device_string = gSavedSettings.getString("JoystickDeviceUUID"); - if (device_string.empty()) + if (!dev_id.isMap()) { mLastDeviceUUID = LLSD(); } else { - LL_DEBUGS("Joystick") << "Looking for device by id: " << device_string << LL_ENDL; - long id = std::stol(device_string); - S32 size = sizeof(long); - LLSD::Binary data; //just an std::vector - data.resize(size); - memcpy(&data[0], &id, size); + std::string manufacturer = mLastDeviceUUID["manufacturer"].asString(); + std::string product = mLastDeviceUUID["product"].asString(); + LL_DEBUGS("Joystick") << "Looking for device by manufacturer: " << manufacturer << " and product: " << product << LL_ENDL; // We store this data in LLSD since it can handle both GUID2 and long - mLastDeviceUUID = LLSD(data); + mLastDeviceUUID = dev_id; } #else mLastDeviceUUID = LLSD(); diff --git a/indra/newview/llviewerjoystick.h b/indra/newview/llviewerjoystick.h index 0e5629497d..33579f544c 100644 --- a/indra/newview/llviewerjoystick.h +++ b/indra/newview/llviewerjoystick.h @@ -55,9 +55,8 @@ class LLViewerJoystick : public LLSingleton public: void init(bool autoenable); void initDevice(LLSD &guid); - void initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/); - void initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/, std::string &name, LLSD &guid); - bool initDevice(NDOF_Device * ndof_device, LLSD::Binary &guid); + bool initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/); + bool initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/, std::string &name, LLSD &guid); void terminate(); void updateStatus(); @@ -80,6 +79,7 @@ public: LLSD getDeviceUUID(); //unconverted, OS dependent value wrapped into LLSD, for comparison/search std::string getDeviceUUIDString(); // converted readable value for settings std::string getDescription(); + void saveDeviceIdToSettings(); protected: void updateEnabled(bool autoenable); -- cgit v1.3 From 92f2cf60896e0beb65ab5faaf6894b683121cdbe Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 23 Oct 2023 16:08:46 +0300 Subject: SL-13610 build fix --- indra/llwindow/llwindowwin32.cpp | 2 +- indra/newview/llviewerjoystick.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 60bd3b080d..694f010ef3 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -4495,7 +4495,7 @@ void* LLWindowWin32::getDirectInput8() return &gDirectInput8; } -bool LLWindowWin32::getInputDevices(U32 device_type_filter +bool LLWindowWin32::getInputDevices(U32 device_type_filter, std::function osx_callback, void * di8_devices_callback, void* userdata) diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index ef96ea4493..4577f71061 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -1446,7 +1446,7 @@ void LLViewerJoystick::saveDeviceIdToSettings() // someone editing the xml will corrupt it // so convert to string first std::string device_string = getDeviceUUIDString(); - gSavedSettings.setLLSD("JoystickDeviceUUID", LLSD(device_string); + gSavedSettings.setLLSD("JoystickDeviceUUID", LLSD(device_string)); #else LLSD device_id = getDeviceUUID(); gSavedSettings.setLLSD("JoystickDeviceUUID", device_id); -- cgit v1.3 From 8b9c44b2155785ead99c7e99a21348a0712ccb15 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Thu, 30 Nov 2023 13:54:39 +0200 Subject: Mac buildfix --- indra/llwindow/llwindowmacosx.cpp | 34 ++++++++++++++++----------------- indra/newview/llviewerparceloverlay.cpp | 2 -- 2 files changed, 16 insertions(+), 20 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 66b9a5d060..41665419aa 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -2246,29 +2246,27 @@ static void get_devices(std::list &list_of_devices, { HidDevice device = populate_device( io_obj ); - if (debugLoggingEnabled("Joystick")) + // Should match ndof + if (device.mAxis >= 3 + || (device.mUsagePage == kHIDPage_GenericDesktop + && (device.mUsage == kHIDUsage_GD_MultiAxisController + || device.mUsage == kHIDUsage_GD_GamePad + || device.mUsage == kHIDUsage_GD_Joystick)) + || (device.mUsagePage == kHIDPage_Game + && device.mUsage == kHIDUsage_Game_3DGameController) + || strstr(device.mManufacturer, "3Dconnexion")) { list_of_devices.push_back(device); - LL_DEBUGS("Joystick") << "Device axises: " << (S32)device.mAxis - << "Device HIDUsepage: " << (S32)device.mUsagePage - << "Device HIDUsage: " << (S32)device.mUsage - << LL_ENDL; } else { - // Should match ndof - if (device.mAxis >= 3 - || (device.mUsagePage == kHIDPage_GenericDesktop - && (device.mUsage == kHIDUsage_GD_MultiAxisController - || device.mUsage == kHIDUsage_GD_GamePad - || device.mUsage == kHIDUsage_GD_Joystick)) - || (device.mUsagePage == kHIDPage_Game - && device.mUsage == kHIDUsage_Game_3DGameController) - || strstr(device.mManufacturer, "3Dconnexion")) - { - list_of_devices.push_back(device); - } - } + LL_DEBUGS("Joystick"); + list_of_devices.push_back(device); + LL_CONT << "Device axes: " << (S32)device.mAxis + << " Device HIDUsepage: " << (S32)device.mUsagePage + << " Device HIDUsage: " << (S32)device.mUsage; + LL_ENDL; + } // release the device object, it is no longer needed diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index d924bdb5fc..5a2b7e4c2f 100755 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -51,8 +51,6 @@ static const U8 OVERLAY_IMG_COMPONENTS = 4; -static const S32 FLOATS_PER_VERTEX = LENGTHOFVECTOR3; -static const S32 BYTES_PER_COLOR = LENGTHOFCOLOR4U; static const F32 LINE_WIDTH = 0.0625f; LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_width_meters) -- cgit v1.3 From 5c7903bfdc4b37bac04631b921273c5e4c0d297a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 25 Jan 2024 01:31:44 +0200 Subject: Crash in switch context Looks like a crash at SetWindowLongPtr due to handle being zero --- indra/llwindow/llwindowwin32.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 99a11f772b..721dadc923 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -1671,7 +1671,9 @@ const S32 max_format = (S32)num_formats - 1; } else { - LL_WARNS("Window") << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << LL_ENDL; + LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBVideoDrvErr")); + // mWindowHandle is 0, going to crash either way + LL_ERRS("Window") << "No wgl_ARB_pixel_format extension!" << LL_ENDL; } // Verify what pixel format we actually received. @@ -1924,12 +1926,16 @@ void LLWindowWin32::destroySharedContext(void* contextPtr) void LLWindowWin32::toggleVSync(bool enable_vsync) { - if (!enable_vsync && wglSwapIntervalEXT) + if (wglSwapIntervalEXT == nullptr) + { + LL_INFOS("Window") << "VSync: wglSwapIntervalEXT not initialized" << LL_ENDL; + } + else if (!enable_vsync) { LL_INFOS("Window") << "Disabling vertical sync" << LL_ENDL; wglSwapIntervalEXT(0); } - else if (wglSwapIntervalEXT) + else { LL_INFOS("Window") << "Enabling vertical sync" << LL_ENDL; wglSwapIntervalEXT(1); -- cgit v1.3