Atlas - hid.cpp
Home / ext / SDL / src / hidapi / android Lines: 17 | Size: 41423 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 2022 Valve Corporation 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23// Purpose: A wrapper implementing "HID" API for Android 24// 25// This layer glues the hidapi API to Android's USB and BLE stack. 26 27#include "hid.h" 28 29// Common to stub version and non-stub version of functions 30#include <jni.h> 31#include <android/log.h> 32 33#define TAG "hidapi" 34 35// Have error log always available 36#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) 37 38#ifdef DEBUG 39#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) 40#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) 41#else 42#define LOGV(...) 43#define LOGD(...) 44#endif 45 46#define SDL_JAVA_PREFIX org_libsdl_app 47#define CONCAT1(prefix, class, function) CONCAT2(prefix, class, function) 48#define CONCAT2(prefix, class, function) Java_ ## prefix ## _ ## class ## _ ## function 49#define HID_DEVICE_MANAGER_JAVA_INTERFACE(function) CONCAT1(SDL_JAVA_PREFIX, HIDDeviceManager, function) 50 51 52#ifndef SDL_HIDAPI_DISABLED 53 54extern "C" { 55#include "../SDL_hidapi_c.h" 56} 57#include "../../core/android/SDL_android.h" 58 59#define hid_close PLATFORM_hid_close 60#define hid_device PLATFORM_hid_device 61#define hid_device_ PLATFORM_hid_device_ 62#define hid_enumerate PLATFORM_hid_enumerate 63#define hid_error PLATFORM_hid_error 64#define hid_exit PLATFORM_hid_exit 65#define hid_free_enumeration PLATFORM_hid_free_enumeration 66#define hid_get_device_info PLATFORM_hid_get_device_info 67#define hid_get_feature_report PLATFORM_hid_get_feature_report 68#define hid_get_indexed_string PLATFORM_hid_get_indexed_string 69#define hid_get_input_report PLATFORM_hid_get_input_report 70#define hid_get_manufacturer_string PLATFORM_hid_get_manufacturer_string 71#define hid_get_product_string PLATFORM_hid_get_product_string 72#define hid_get_report_descriptor PLATFORM_hid_get_report_descriptor 73#define hid_get_serial_number_string PLATFORM_hid_get_serial_number_string 74#define hid_init PLATFORM_hid_init 75#define hid_open_path PLATFORM_hid_open_path 76#define hid_open PLATFORM_hid_open 77#define hid_read PLATFORM_hid_read 78#define hid_read_timeout PLATFORM_hid_read_timeout 79#define hid_send_feature_report PLATFORM_hid_send_feature_report 80#define hid_set_nonblocking PLATFORM_hid_set_nonblocking 81#define hid_version PLATFORM_hid_version 82#define hid_version_str PLATFORM_hid_version_str 83#define hid_write PLATFORM_hid_write 84 85#include <pthread.h> 86#include <errno.h> // For ETIMEDOUT and ECONNRESET 87#include <stdlib.h> // For malloc() and free() 88 89#include "../hidapi/hidapi.h" 90 91typedef uint32_t uint32; 92typedef uint64_t uint64; 93 94 95struct hid_device_ 96{ 97 int m_nId; 98 int m_nDeviceRefCount; 99}; 100 101template<class T> 102class hid_device_ref 103{ 104public: 105 hid_device_ref( T *pObject = nullptr ) : m_pObject( nullptr ) 106 { 107 SetObject( pObject ); 108 } 109 110 hid_device_ref( const hid_device_ref &rhs ) : m_pObject( nullptr ) 111 { 112 SetObject( rhs.GetObject() ); 113 } 114 115 ~hid_device_ref() 116 { 117 SetObject( nullptr ); 118 } 119 120 void SetObject( T *pObject ) 121 { 122 if ( m_pObject && m_pObject->DecrementRefCount() == 0 ) 123 { 124 delete m_pObject; 125 } 126 127 m_pObject = pObject; 128 129 if ( m_pObject ) 130 { 131 m_pObject->IncrementRefCount(); 132 } 133 } 134 135 hid_device_ref &operator =( T *pObject ) 136 { 137 SetObject( pObject ); 138 return *this; 139 } 140 141 hid_device_ref &operator =( const hid_device_ref &rhs ) 142 { 143 SetObject( rhs.GetObject() ); 144 return *this; 145 } 146 147 T *GetObject() const 148 { 149 return m_pObject; 150 } 151 152 T* operator->() const 153 { 154 return m_pObject; 155 } 156 157 operator bool() const 158 { 159 return ( m_pObject != nullptr ); 160 } 161 162private: 163 T *m_pObject; 164}; 165 166class hid_mutex_guard 167{ 168public: 169 hid_mutex_guard( pthread_mutex_t *pMutex ) : m_pMutex( pMutex ) 170 { 171 pthread_mutex_lock( m_pMutex ); 172 } 173 ~hid_mutex_guard() 174 { 175 pthread_mutex_unlock( m_pMutex ); 176 } 177 178private: 179 pthread_mutex_t *m_pMutex; 180}; 181 182class hid_buffer 183{ 184public: 185 hid_buffer() : m_pData( nullptr ), m_nSize( 0 ), m_nAllocated( 0 ) 186 { 187 } 188 189 hid_buffer( const uint8_t *pData, size_t nSize ) : m_pData( nullptr ), m_nSize( 0 ), m_nAllocated( 0 ) 190 { 191 assign( pData, nSize ); 192 } 193 194 ~hid_buffer() 195 { 196 delete[] m_pData; 197 } 198 199 void assign( const uint8_t *pData, size_t nSize ) 200 { 201 if ( nSize > m_nAllocated ) 202 { 203 delete[] m_pData; 204 m_pData = new uint8_t[ nSize ]; 205 m_nAllocated = nSize; 206 } 207 208 m_nSize = nSize; 209 SDL_memcpy( m_pData, pData, nSize ); 210 } 211 212 void clear() 213 { 214 m_nSize = 0; 215 } 216 217 size_t size() const 218 { 219 return m_nSize; 220 } 221 222 const uint8_t *data() const 223 { 224 return m_pData; 225 } 226 227private: 228 uint8_t *m_pData; 229 size_t m_nSize; 230 size_t m_nAllocated; 231}; 232 233class hid_buffer_pool 234{ 235public: 236 hid_buffer_pool() : m_nSize( 0 ), m_pHead( nullptr ), m_pTail( nullptr ), m_pFree( nullptr ) 237 { 238 } 239 240 ~hid_buffer_pool() 241 { 242 clear(); 243 244 while ( m_pFree ) 245 { 246 hid_buffer_entry *pEntry = m_pFree; 247 m_pFree = m_pFree->m_pNext; 248 delete pEntry; 249 } 250 } 251 252 size_t size() const { return m_nSize; } 253 254 const hid_buffer &front() const { return m_pHead->m_buffer; } 255 256 void pop_front() 257 { 258 hid_buffer_entry *pEntry = m_pHead; 259 if ( pEntry ) 260 { 261 m_pHead = pEntry->m_pNext; 262 if ( !m_pHead ) 263 { 264 m_pTail = nullptr; 265 } 266 pEntry->m_pNext = m_pFree; 267 m_pFree = pEntry; 268 --m_nSize; 269 } 270 } 271 272 void emplace_back( const uint8_t *pData, size_t nSize ) 273 { 274 hid_buffer_entry *pEntry; 275 276 if ( m_pFree ) 277 { 278 pEntry = m_pFree; 279 m_pFree = m_pFree->m_pNext; 280 } 281 else 282 { 283 pEntry = new hid_buffer_entry; 284 } 285 pEntry->m_pNext = nullptr; 286 287 if ( m_pTail ) 288 { 289 m_pTail->m_pNext = pEntry; 290 } 291 else 292 { 293 m_pHead = pEntry; 294 } 295 m_pTail = pEntry; 296 297 pEntry->m_buffer.assign( pData, nSize ); 298 ++m_nSize; 299 } 300 301 void clear() 302 { 303 while ( size() > 0 ) 304 { 305 pop_front(); 306 } 307 } 308 309private: 310 struct hid_buffer_entry 311 { 312 hid_buffer m_buffer; 313 hid_buffer_entry *m_pNext; 314 }; 315 316 size_t m_nSize; 317 hid_buffer_entry *m_pHead; 318 hid_buffer_entry *m_pTail; 319 hid_buffer_entry *m_pFree; 320}; 321 322static jbyteArray NewByteArray( JNIEnv *env, const uint8_t *pData, size_t nDataLen ) 323{ 324 jbyteArray array = env->NewByteArray( (jsize)nDataLen ); 325 jbyte *pBuf = env->GetByteArrayElements( array, NULL ); 326 SDL_memcpy( pBuf, pData, nDataLen ); 327 env->ReleaseByteArrayElements( array, pBuf, 0 ); 328 329 return array; 330} 331 332static char *CreateStringFromJString( JNIEnv *env, const jstring &sString ) 333{ 334 size_t nLength = env->GetStringUTFLength( sString ); 335 const char *pjChars = env->GetStringUTFChars( sString, NULL ); 336 char *psString = (char *)malloc( nLength + 1 ); 337 SDL_memcpy( psString, pjChars, nLength ); 338 psString[ nLength ] = '\0'; 339 env->ReleaseStringUTFChars( sString, pjChars ); 340 return psString; 341} 342 343static wchar_t *CreateWStringFromJString( JNIEnv *env, const jstring &sString ) 344{ 345 size_t nLength = env->GetStringLength( sString ); 346 const jchar *pjChars = env->GetStringChars( sString, NULL ); 347 wchar_t *pwString = (wchar_t *)malloc( ( nLength + 1 ) * sizeof( wchar_t ) ); 348 wchar_t *pwChars = pwString; 349 for ( size_t iIndex = 0; iIndex < nLength; ++iIndex ) 350 { 351 pwChars[ iIndex ] = pjChars[ iIndex ]; 352 } 353 pwString[ nLength ] = '\0'; 354 env->ReleaseStringChars( sString, pjChars ); 355 return pwString; 356} 357 358static wchar_t *CreateWStringFromWString( const wchar_t *pwSrc ) 359{ 360 size_t nLength = SDL_wcslen( pwSrc ); 361 wchar_t *pwString = (wchar_t *)malloc( ( nLength + 1 ) * sizeof( wchar_t ) ); 362 SDL_memcpy( pwString, pwSrc, nLength * sizeof( wchar_t ) ); 363 pwString[ nLength ] = '\0'; 364 return pwString; 365} 366 367static hid_device_info *CopyHIDDeviceInfo( const hid_device_info *pInfo ) 368{ 369 hid_device_info *pCopy = new hid_device_info; 370 *pCopy = *pInfo; 371 pCopy->path = SDL_strdup( pInfo->path ); 372 pCopy->product_string = CreateWStringFromWString( pInfo->product_string ); 373 pCopy->manufacturer_string = CreateWStringFromWString( pInfo->manufacturer_string ); 374 pCopy->serial_number = CreateWStringFromWString( pInfo->serial_number ); 375 return pCopy; 376} 377 378static void FreeHIDDeviceInfo( hid_device_info *pInfo ) 379{ 380 free( pInfo->path ); 381 free( pInfo->serial_number ); 382 free( pInfo->manufacturer_string ); 383 free( pInfo->product_string ); 384 delete pInfo; 385} 386 387static jclass g_HIDDeviceManagerCallbackClass; 388static jobject g_HIDDeviceManagerCallbackHandler; 389static jmethodID g_midHIDDeviceManagerInitialize; 390static jmethodID g_midHIDDeviceManagerOpen; 391static jmethodID g_midHIDDeviceManagerWriteReport; 392static jmethodID g_midHIDDeviceManagerReadReport; 393static jmethodID g_midHIDDeviceManagerClose; 394static bool g_initialized = false; 395 396static uint64_t get_timespec_ms( const struct timespec &ts ) 397{ 398 return (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; 399} 400 401static void ExceptionCheck( JNIEnv *env, const char *pszClassName, const char *pszMethodName ) 402{ 403 if ( env->ExceptionCheck() ) 404 { 405 // Get our exception 406 jthrowable jExcept = env->ExceptionOccurred(); 407 408 // Clear the exception so we can call JNI again 409 env->ExceptionClear(); 410 411 // Get our exception message 412 jclass jExceptClass = env->GetObjectClass( jExcept ); 413 jmethodID jMessageMethod = env->GetMethodID( jExceptClass, "getMessage", "()Ljava/lang/String;" ); 414 jstring jMessage = (jstring)( env->CallObjectMethod( jExcept, jMessageMethod ) ); 415 const char *pszMessage = env->GetStringUTFChars( jMessage, NULL ); 416 417 // ...and log it. 418 LOGE( "%s%s%s threw an exception: %s", 419 pszClassName ? pszClassName : "", 420 pszClassName ? "::" : "", 421 pszMethodName, pszMessage ); 422 423 // Cleanup 424 env->ReleaseStringUTFChars( jMessage, pszMessage ); 425 env->DeleteLocalRef( jMessage ); 426 env->DeleteLocalRef( jExceptClass ); 427 env->DeleteLocalRef( jExcept ); 428 } 429} 430 431class CHIDDevice 432{ 433public: 434 CHIDDevice( int nDeviceID, hid_device_info *pInfo ) 435 { 436 m_nId = nDeviceID; 437 m_pInfo = pInfo; 438 439 // The Bluetooth Steam Controller needs special handling 440 const int VALVE_USB_VID = 0x28DE; 441 const int D0G_BLE2_PID = 0x1106; 442 if ( pInfo->vendor_id == VALVE_USB_VID && pInfo->product_id == D0G_BLE2_PID ) 443 { 444 m_bIsBLESteamController = true; 445 } 446 } 447 448 ~CHIDDevice() 449 { 450 FreeHIDDeviceInfo( m_pInfo ); 451 452 // Note that we don't delete m_pDevice, as the app may still have a reference to it 453 } 454 455 int IncrementRefCount() 456 { 457 int nValue; 458 pthread_mutex_lock( &m_refCountLock ); 459 nValue = ++m_nRefCount; 460 pthread_mutex_unlock( &m_refCountLock ); 461 return nValue; 462 } 463 464 int DecrementRefCount() 465 { 466 int nValue; 467 pthread_mutex_lock( &m_refCountLock ); 468 nValue = --m_nRefCount; 469 pthread_mutex_unlock( &m_refCountLock ); 470 return nValue; 471 } 472 473 int GetId() 474 { 475 return m_nId; 476 } 477 478 hid_device_info *GetDeviceInfo() 479 { 480 return m_pInfo; 481 } 482 483 hid_device *GetDevice() 484 { 485 return m_pDevice; 486 } 487 488 void ExceptionCheck( JNIEnv *env, const char *pszMethodName ) 489 { 490 ::ExceptionCheck( env, "CHIDDevice", pszMethodName ); 491 } 492 493 bool BOpen() 494 { 495 JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); 496 497 if ( !g_HIDDeviceManagerCallbackHandler ) 498 { 499 LOGV( "Device open without callback handler" ); 500 return false; 501 } 502 503 if ( m_bIsWaitingForOpen ) 504 { 505 SDL_SetError( "Waiting for permission" ); 506 return false; 507 } 508 509 if ( !m_bOpenResult ) 510 { 511 m_bOpenResult = env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerOpen, m_nId ); 512 ExceptionCheck( env, "BOpen" ); 513 514 if ( m_bIsWaitingForOpen ) 515 { 516 LOGV( "Device open waiting for permission" ); 517 SDL_SetError( "Waiting for permission" ); 518 m_bWasOpenPending = true; 519 return false; 520 } 521 522 if ( !m_bOpenResult ) 523 { 524 LOGV( "Device open failed" ); 525 SDL_SetError( "Device open failed" ); 526 return false; 527 } 528 } 529 530 m_pDevice = new hid_device; 531 m_pDevice->m_nId = m_nId; 532 m_pDevice->m_nDeviceRefCount = 1; 533 LOGD("Creating device %d (%p), refCount = 1\n", m_pDevice->m_nId, m_pDevice); 534 535 return true; 536 } 537 538 void SetOpenPending() 539 { 540 m_bIsWaitingForOpen = true; 541 } 542 543 bool BOpenPending() const 544 { 545 return m_bIsWaitingForOpen; 546 } 547 548 void SetWasOpenPending( bool bState ) 549 { 550 m_bWasOpenPending = bState; 551 } 552 553 bool BWasOpenPending() const 554 { 555 return m_bWasOpenPending; 556 } 557 558 void SetOpenResult( bool bResult ) 559 { 560 if ( m_bIsWaitingForOpen ) 561 { 562 m_bOpenResult = bResult; 563 m_bIsWaitingForOpen = false; 564 565 if ( m_bOpenResult ) 566 { 567 LOGV( "Device open succeeded" ); 568 } 569 else 570 { 571 LOGV( "Device open failed" ); 572 } 573 } 574 } 575 576 bool BOpenResult() const 577 { 578 return m_bOpenResult; 579 } 580 581 void ProcessInput( const uint8_t *pBuf, size_t nBufSize ) 582 { 583 hid_mutex_guard l( &m_dataLock ); 584 585 size_t MAX_REPORT_QUEUE_SIZE = 16; 586 if ( m_vecData.size() >= MAX_REPORT_QUEUE_SIZE ) 587 { 588 m_vecData.pop_front(); 589 } 590 m_vecData.emplace_back( pBuf, nBufSize ); 591 } 592 593 int GetInput( unsigned char *data, size_t length ) 594 { 595 hid_mutex_guard l( &m_dataLock ); 596 597 if ( m_vecData.size() == 0 ) 598 { 599// LOGV( "hid_read_timeout no data available" ); 600 return 0; 601 } 602 603 const hid_buffer &buffer = m_vecData.front(); 604 size_t nDataLen = buffer.size() > length ? length : buffer.size(); 605 if ( m_bIsBLESteamController ) 606 { 607 data[0] = 0x03; 608 SDL_memcpy( data + 1, buffer.data(), nDataLen ); 609 ++nDataLen; 610 } 611 else 612 { 613 SDL_memcpy( data, buffer.data(), nDataLen ); 614 } 615 m_vecData.pop_front(); 616 617// LOGV("Read %u bytes", nDataLen); 618// LOGV("%02x %02x %02x %02x %02x %02x %02x %02x ....", 619// data[0], data[1], data[2], data[3], 620// data[4], data[5], data[6], data[7]); 621 622 return (int)nDataLen; 623 } 624 625 int WriteReport( const unsigned char *pData, size_t nDataLen, bool bFeature ) 626 { 627 JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); 628 629 if ( !g_HIDDeviceManagerCallbackHandler ) 630 { 631 LOGV( "WriteReport without callback handler" ); 632 return -1; 633 } 634 635 jbyteArray pBuf = NewByteArray( env, pData, nDataLen ); 636 int nRet = env->CallIntMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerWriteReport, m_nId, pBuf, bFeature ); 637 ExceptionCheck( env, "WriteReport" ); 638 env->DeleteLocalRef( pBuf ); 639 return nRet; 640 } 641 642 void ProcessReportResponse( const uint8_t *pBuf, size_t nBufSize ) 643 { 644 hid_mutex_guard cvl( &m_cvLock ); 645 if ( m_bIsWaitingForReportResponse ) 646 { 647 m_reportResponse.assign( pBuf, nBufSize ); 648 649 m_bIsWaitingForReportResponse = false; 650 m_nReportResponseError = 0; 651 pthread_cond_signal( &m_cv ); 652 } 653 } 654 655 int ReadReport( unsigned char *pData, size_t nDataLen, bool bFeature ) 656 { 657 JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); 658 659 if ( !g_HIDDeviceManagerCallbackHandler ) 660 { 661 LOGV( "ReadReport without callback handler" ); 662 return -1; 663 } 664 665 { 666 hid_mutex_guard cvl( &m_cvLock ); 667 if ( m_bIsWaitingForReportResponse ) 668 { 669 LOGV( "Get feature report already ongoing... bail" ); 670 return -1; // Read already ongoing, we currently do not serialize, TODO 671 } 672 m_bIsWaitingForReportResponse = true; 673 } 674 675 jbyteArray pBuf = NewByteArray( env, pData, nDataLen ); 676 int nRet = env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerReadReport, m_nId, pBuf, bFeature ) ? 0 : -1; 677 ExceptionCheck( env, "ReadReport" ); 678 env->DeleteLocalRef( pBuf ); 679 if ( nRet < 0 ) 680 { 681 LOGV( "ReadReport failed" ); 682 m_bIsWaitingForReportResponse = false; 683 return -1; 684 } 685 686 { 687 hid_mutex_guard cvl( &m_cvLock ); 688 if ( m_bIsWaitingForReportResponse ) 689 { 690 LOGV("=== Going to sleep" ); 691 // Wait in CV until we are no longer waiting for a feature report. 692 const int FEATURE_REPORT_TIMEOUT_SECONDS = 2; 693 struct timespec ts, endtime; 694 clock_gettime( CLOCK_REALTIME, &ts ); 695 endtime = ts; 696 endtime.tv_sec += FEATURE_REPORT_TIMEOUT_SECONDS; 697 do 698 { 699 if ( pthread_cond_timedwait( &m_cv, &m_cvLock, &endtime ) != 0 ) 700 { 701 break; 702 } 703 } 704 while ( m_bIsWaitingForReportResponse && get_timespec_ms( ts ) < get_timespec_ms( endtime ) ); 705 706 // We are back 707 if ( m_bIsWaitingForReportResponse ) 708 { 709 m_nReportResponseError = -ETIMEDOUT; 710 m_bIsWaitingForReportResponse = false; 711 } 712 LOGV( "=== Got feature report err=%d", m_nReportResponseError ); 713 if ( m_nReportResponseError != 0 ) 714 { 715 return m_nReportResponseError; 716 } 717 } 718 719 size_t uBytesToCopy = m_reportResponse.size() > nDataLen ? nDataLen : m_reportResponse.size(); 720 SDL_memcpy( pData, m_reportResponse.data(), uBytesToCopy ); 721 m_reportResponse.clear(); 722 LOGV( "=== Got %zu bytes", uBytesToCopy ); 723 724 return (int)uBytesToCopy; 725 } 726 } 727 728 void Close( bool bDeleteDevice ) 729 { 730 JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); 731 732 if ( g_HIDDeviceManagerCallbackHandler ) 733 { 734 if ( !m_bIsWaitingForOpen && m_bOpenResult ) 735 { 736 env->CallVoidMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerClose, m_nId ); 737 ExceptionCheck( env, "Close" ); 738 } 739 } 740 741 hid_mutex_guard dataLock( &m_dataLock ); 742 m_vecData.clear(); 743 744 // Clean and release pending feature report reads 745 hid_mutex_guard cvLock( &m_cvLock ); 746 m_reportResponse.clear(); 747 m_bIsWaitingForReportResponse = false; 748 m_nReportResponseError = -ECONNRESET; 749 pthread_cond_broadcast( &m_cv ); 750 751 m_bOpenResult = false; 752 753 if ( bDeleteDevice ) 754 { 755 delete m_pDevice; 756 m_pDevice = nullptr; 757 } 758 } 759 760private: 761 pthread_mutex_t m_refCountLock = PTHREAD_MUTEX_INITIALIZER; 762 int m_nRefCount = 0; 763 int m_nId = 0; 764 hid_device_info *m_pInfo = nullptr; 765 hid_device *m_pDevice = nullptr; 766 bool m_bIsBLESteamController = false; 767 768 pthread_mutex_t m_dataLock = PTHREAD_MUTEX_INITIALIZER; // This lock has to be held to access m_vecData 769 hid_buffer_pool m_vecData; 770 771 // For handling get_feature_report 772 pthread_mutex_t m_cvLock = PTHREAD_MUTEX_INITIALIZER; // This lock has to be held to access any variables below 773 pthread_cond_t m_cv = PTHREAD_COND_INITIALIZER; 774 bool m_bIsWaitingForOpen = false; 775 bool m_bWasOpenPending = false; 776 bool m_bOpenResult = false; 777 bool m_bIsWaitingForReportResponse = false; 778 int m_nReportResponseError = 0; 779 hid_buffer m_reportResponse; 780 781public: 782 hid_device_ref<CHIDDevice> next; 783}; 784 785class CHIDDevice; 786static pthread_mutex_t g_DevicesMutex = PTHREAD_MUTEX_INITIALIZER; 787static pthread_mutex_t g_DevicesRefCountMutex = PTHREAD_MUTEX_INITIALIZER; 788static hid_device_ref<CHIDDevice> g_Devices; 789 790static hid_device_ref<CHIDDevice> FindDevice( int nDeviceId ) 791{ 792 hid_device_ref<CHIDDevice> pDevice; 793 794 hid_mutex_guard l( &g_DevicesMutex ); 795 for ( pDevice = g_Devices; pDevice; pDevice = pDevice->next ) 796 { 797 if ( pDevice->GetId() == nDeviceId ) 798 { 799 break; 800 } 801 } 802 return pDevice; 803} 804 805 806extern "C" 807JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz); 808 809extern "C" 810JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz); 811 812extern "C" 813JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface, int nInterfaceClass, int nInterfaceSubclass, int nInterfaceProtocol, bool bBluetooth ); 814 815extern "C" 816JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID); 817 818extern "C" 819JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, int nDeviceID, bool bOpened); 820 821extern "C" 822JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, int nDeviceID); 823 824extern "C" 825JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value); 826 827extern "C" 828JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReportResponse)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value); 829 830 831extern "C" 832JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz ) 833{ 834 LOGV( "HIDDeviceRegisterCallback()"); 835 836 if ( g_HIDDeviceManagerCallbackHandler != NULL ) 837 { 838 env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass ); 839 g_HIDDeviceManagerCallbackClass = NULL; 840 env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler ); 841 g_HIDDeviceManagerCallbackHandler = NULL; 842 } 843 844 g_HIDDeviceManagerCallbackHandler = env->NewGlobalRef( thiz ); 845 jclass objClass = env->GetObjectClass( thiz ); 846 if ( objClass ) 847 { 848 g_HIDDeviceManagerCallbackClass = reinterpret_cast< jclass >( env->NewGlobalRef( objClass ) ); 849 g_midHIDDeviceManagerInitialize = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "initialize", "(ZZ)Z" ); 850 if ( !g_midHIDDeviceManagerInitialize ) 851 { 852 __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing initialize" ); 853 } 854 g_midHIDDeviceManagerOpen = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "openDevice", "(I)Z" ); 855 if ( !g_midHIDDeviceManagerOpen ) 856 { 857 __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing openDevice" ); 858 } 859 g_midHIDDeviceManagerWriteReport = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "writeReport", "(I[BZ)I" ); 860 if ( !g_midHIDDeviceManagerWriteReport ) 861 { 862 __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing writeReport" ); 863 } 864 g_midHIDDeviceManagerReadReport = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "readReport", "(I[BZ)Z" ); 865 if ( !g_midHIDDeviceManagerReadReport ) 866 { 867 __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing getFeatureReport" ); 868 } 869 g_midHIDDeviceManagerClose = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "closeDevice", "(I)V" ); 870 if ( !g_midHIDDeviceManagerClose ) 871 { 872 __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing closeDevice" ); 873 } 874 env->DeleteLocalRef( objClass ); 875 } 876} 877 878extern "C" 879JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz) 880{ 881 LOGV("HIDDeviceReleaseCallback"); 882 if ( env->IsSameObject( thiz, g_HIDDeviceManagerCallbackHandler ) ) 883 { 884 env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass ); 885 g_HIDDeviceManagerCallbackClass = NULL; 886 env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler ); 887 g_HIDDeviceManagerCallbackHandler = NULL; 888 g_initialized = false; 889 } 890} 891 892extern "C" 893JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface, int nInterfaceClass, int nInterfaceSubclass, int nInterfaceProtocol, bool bBluetooth ) 894{ 895 LOGV( "HIDDeviceConnected() id=%d VID/PID = %.4x/%.4x, interface %d\n", nDeviceID, nVendorId, nProductId, nInterface ); 896 897 hid_device_info *pInfo = new hid_device_info; 898 SDL_memset( pInfo, 0, sizeof( *pInfo ) ); 899 pInfo->path = CreateStringFromJString( env, sIdentifier ); 900 pInfo->vendor_id = nVendorId; 901 pInfo->product_id = nProductId; 902 pInfo->serial_number = CreateWStringFromJString( env, sSerialNumber ); 903 pInfo->release_number = nReleaseNumber; 904 pInfo->manufacturer_string = CreateWStringFromJString( env, sManufacturer ); 905 pInfo->product_string = CreateWStringFromJString( env, sProduct ); 906 pInfo->interface_number = nInterface; 907 pInfo->interface_class = nInterfaceClass; 908 pInfo->interface_subclass = nInterfaceSubclass; 909 pInfo->interface_protocol = nInterfaceProtocol; 910 if ( bBluetooth ) 911 { 912 pInfo->bus_type = HID_API_BUS_BLUETOOTH; 913 } 914 else 915 { 916 pInfo->bus_type = HID_API_BUS_USB; 917 } 918 919 hid_device_ref<CHIDDevice> pDevice( new CHIDDevice( nDeviceID, pInfo ) ); 920 921 hid_mutex_guard l( &g_DevicesMutex ); 922 hid_device_ref<CHIDDevice> pLast, pCurr; 923 for ( pCurr = g_Devices; pCurr; pLast = pCurr, pCurr = pCurr->next ) 924 { 925 continue; 926 } 927 if ( pLast ) 928 { 929 pLast->next = pDevice; 930 } 931 else 932 { 933 g_Devices = pDevice; 934 } 935} 936 937extern "C" 938JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID) 939{ 940 LOGV( "HIDDeviceOpenPending() id=%d\n", nDeviceID ); 941 hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID ); 942 if ( pDevice ) 943 { 944 pDevice->SetOpenPending(); 945 } 946} 947 948extern "C" 949JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, int nDeviceID, bool bOpened) 950{ 951 LOGV( "HIDDeviceOpenResult() id=%d, result=%s\n", nDeviceID, bOpened ? "true" : "false" ); 952 hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID ); 953 if ( pDevice ) 954 { 955 pDevice->SetOpenResult( bOpened ); 956 } 957} 958 959extern "C" 960JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, int nDeviceID) 961{ 962 LOGV( "HIDDeviceDisconnected() id=%d\n", nDeviceID ); 963 hid_device_ref<CHIDDevice> pDevice; 964 { 965 hid_mutex_guard l( &g_DevicesMutex ); 966 hid_device_ref<CHIDDevice> pLast, pCurr; 967 for ( pCurr = g_Devices; pCurr; pLast = pCurr, pCurr = pCurr->next ) 968 { 969 if ( pCurr->GetId() == nDeviceID ) 970 { 971 pDevice = pCurr; 972 973 if ( pLast ) 974 { 975 pLast->next = pCurr->next; 976 } 977 else 978 { 979 g_Devices = pCurr->next; 980 } 981 } 982 } 983 } 984 if ( pDevice ) 985 { 986 pDevice->Close( false ); 987 } 988} 989 990extern "C" 991JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value) 992{ 993 jbyte *pBuf = env->GetByteArrayElements(value, NULL); 994 jsize nBufSize = env->GetArrayLength(value); 995 996// LOGV( "HIDDeviceInput() id=%d len=%u\n", nDeviceID, nBufSize ); 997 hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID ); 998 if ( pDevice ) 999 { 1000 pDevice->ProcessInput( reinterpret_cast< const uint8_t * >( pBuf ), nBufSize ); 1001 } 1002 1003 env->ReleaseByteArrayElements(value, pBuf, 0); 1004} 1005 1006extern "C" 1007JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReportResponse)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value) 1008{ 1009 jbyte *pBuf = env->GetByteArrayElements(value, NULL); 1010 jsize nBufSize = env->GetArrayLength(value); 1011 1012 LOGV( "HIDDeviceReportResponse() id=%d len=%u\n", nDeviceID, nBufSize ); 1013 hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID ); 1014 if ( pDevice ) 1015 { 1016 pDevice->ProcessReportResponse( reinterpret_cast< const uint8_t * >( pBuf ), nBufSize ); 1017 } 1018 1019 env->ReleaseByteArrayElements(value, pBuf, 0); 1020} 1021 1022////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1023////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1024////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1025 1026extern "C" 1027{ 1028 1029static void SDLCALL RequestBluetoothPermissionCallback( void *userdata, const char *permission, bool granted ) 1030{ 1031 SDL_Log( "Bluetooth permission %s", granted ? "granted" : "denied" ); 1032 1033 if ( granted && g_HIDDeviceManagerCallbackHandler ) 1034 { 1035 JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); 1036 1037 env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerInitialize, false, true ); 1038 } 1039} 1040 1041int hid_init(void) 1042{ 1043 if ( !g_initialized && g_HIDDeviceManagerCallbackHandler ) 1044 { 1045 // HIDAPI doesn't work well with Android < 4.3 1046 if ( SDL_GetAndroidSDKVersion() >= 18 ) 1047 { 1048 JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); 1049 1050 env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerInitialize, true, false ); 1051 1052 // Bluetooth is currently only used for Steam Controllers, so check that hint 1053 // before initializing Bluetooth, which will prompt the user for permission. 1054 if ( SDL_GetHintBoolean( SDL_HINT_JOYSTICK_HIDAPI_STEAM, false ) ) 1055 { 1056 if ( SDL_GetAndroidSDKVersion() < 31 ) 1057 { 1058 env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerInitialize, false, true ); 1059 } 1060 else 1061 { 1062 SDL_Log( "Requesting Bluetooth permission" ); 1063 SDL_RequestAndroidPermission( "android.permission.BLUETOOTH_CONNECT", RequestBluetoothPermissionCallback, NULL ); 1064 } 1065 } 1066 ExceptionCheck( env, NULL, "hid_init" ); 1067 } 1068 g_initialized = true; // Regardless of result, so it's only called once 1069 } 1070 return 0; 1071} 1072 1073struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id) 1074{ 1075 struct hid_device_info *root = NULL; 1076 1077 hid_mutex_guard l( &g_DevicesMutex ); 1078 for ( hid_device_ref<CHIDDevice> pDevice = g_Devices; pDevice; pDevice = pDevice->next ) 1079 { 1080 // Don't enumerate devices that are currently being opened, we'll re-enumerate them when we're done 1081 // Make sure we skip them at least once, so they get removed and then re-added to the caller's device list 1082 if ( pDevice->BWasOpenPending() ) 1083 { 1084 // Don't enumerate devices that failed to open, otherwise the application might try to keep prompting for access 1085 if ( !pDevice->BOpenPending() && pDevice->BOpenResult() ) 1086 { 1087 pDevice->SetWasOpenPending( false ); 1088 } 1089 continue; 1090 } 1091 1092 const hid_device_info *info = pDevice->GetDeviceInfo(); 1093 1094 /* See if there are any devices we should skip in enumeration */ 1095 if (SDL_HIDAPI_ShouldIgnoreDevice(HID_API_BUS_UNKNOWN, info->vendor_id, info->product_id, 0, 0)) { 1096 continue; 1097 } 1098 1099 if ( ( vendor_id == 0x0 || info->vendor_id == vendor_id ) && 1100 ( product_id == 0x0 || info->product_id == product_id ) ) 1101 { 1102 hid_device_info *dev = CopyHIDDeviceInfo( info ); 1103 dev->next = root; 1104 root = dev; 1105 } 1106 } 1107 return root; 1108} 1109 1110void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs) 1111{ 1112 while ( devs ) 1113 { 1114 struct hid_device_info *next = devs->next; 1115 FreeHIDDeviceInfo( devs ); 1116 devs = next; 1117 } 1118} 1119 1120HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) 1121{ 1122 // TODO: Implement 1123 return NULL; 1124} 1125 1126HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path) 1127{ 1128 LOGV( "hid_open_path( %s )", path ); 1129 1130 hid_device_ref< CHIDDevice > pDevice; 1131 { 1132 hid_mutex_guard r( &g_DevicesRefCountMutex ); 1133 hid_mutex_guard l( &g_DevicesMutex ); 1134 for ( hid_device_ref<CHIDDevice> pCurr = g_Devices; pCurr; pCurr = pCurr->next ) 1135 { 1136 if ( SDL_strcmp( pCurr->GetDeviceInfo()->path, path ) == 0 ) 1137 { 1138 hid_device *pValue = pCurr->GetDevice(); 1139 if ( pValue ) 1140 { 1141 ++pValue->m_nDeviceRefCount; 1142 LOGD("Incrementing device %d (%p), refCount = %d\n", pValue->m_nId, pValue, pValue->m_nDeviceRefCount); 1143 return pValue; 1144 } 1145 1146 // Hold a shared pointer to the controller for the duration 1147 pDevice = pCurr; 1148 break; 1149 } 1150 } 1151 } 1152 if ( !pDevice ) 1153 { 1154 SDL_SetError( "Couldn't find device with path %s", path ); 1155 return NULL; 1156 } 1157 if ( pDevice->BOpen() ) 1158 { 1159 return pDevice->GetDevice(); 1160 } 1161 return NULL; 1162} 1163 1164int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length) 1165{ 1166 if ( device ) 1167 { 1168// LOGV( "hid_write id=%d length=%zu", device->m_nId, length ); 1169 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1170 if ( pDevice ) 1171 { 1172 return pDevice->WriteReport( data, length, false ); 1173 } 1174 } 1175 return -1; // Controller was disconnected 1176} 1177 1178static uint32_t getms() 1179{ 1180 struct timeval now; 1181 1182 gettimeofday(&now, NULL); 1183 return (uint32_t)(now.tv_sec * 1000 + now.tv_usec / 1000); 1184} 1185 1186static void delayms(uint32_t ms) 1187{ 1188 int was_error; 1189 1190 struct timespec elapsed, tv; 1191 1192 /* Set the timeout interval */ 1193 elapsed.tv_sec = ms / 1000; 1194 elapsed.tv_nsec = (ms % 1000) * 1000000; 1195 do { 1196 errno = 0; 1197 1198 tv.tv_sec = elapsed.tv_sec; 1199 tv.tv_nsec = elapsed.tv_nsec; 1200 was_error = nanosleep(&tv, &elapsed); 1201 } while (was_error && (errno == EINTR)); 1202} 1203 1204int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *device, unsigned char *data, size_t length, int milliseconds) 1205{ 1206 if ( device ) 1207 { 1208// LOGV( "hid_read_timeout id=%d length=%u timeout=%d", device->m_nId, length, milliseconds ); 1209 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1210 if ( pDevice ) 1211 { 1212 int nResult = pDevice->GetInput( data, length ); 1213 if ( nResult == 0 && milliseconds > 0 ) 1214 { 1215 uint32_t start = getms(); 1216 do 1217 { 1218 delayms( 1 ); 1219 nResult = pDevice->GetInput( data, length ); 1220 } while ( nResult == 0 && ( getms() - start ) < milliseconds ); 1221 } 1222 return nResult; 1223 } 1224 LOGV( "controller was disconnected" ); 1225 } 1226 return -1; // Controller was disconnected 1227} 1228 1229// TODO: Implement blocking 1230int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length) 1231{ 1232// LOGV( "hid_read id=%d length=%zu", device->m_nId, length ); 1233 return hid_read_timeout( device, data, length, 0 ); 1234} 1235 1236// TODO: Implement? 1237int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock) 1238{ 1239 return -1; 1240} 1241 1242int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length) 1243{ 1244 if ( device ) 1245 { 1246 LOGV( "hid_send_feature_report id=%d length=%zu", device->m_nId, length ); 1247 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1248 if ( pDevice ) 1249 { 1250 return pDevice->WriteReport( data, length, true ); 1251 } 1252 } 1253 return -1; // Controller was disconnected 1254} 1255 1256 1257// Synchronous operation. Will block until completed. 1258int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length) 1259{ 1260 if ( device ) 1261 { 1262 LOGV( "hid_get_feature_report id=%d length=%zu", device->m_nId, length ); 1263 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1264 if ( pDevice ) 1265 { 1266 return pDevice->ReadReport( data, length, true ); 1267 } 1268 } 1269 return -1; // Controller was disconnected 1270} 1271 1272 1273// Synchronous operation. Will block until completed. 1274int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *device, unsigned char *data, size_t length) 1275{ 1276 if ( device ) 1277 { 1278 LOGV( "hid_get_input_report id=%d length=%zu", device->m_nId, length ); 1279 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1280 if ( pDevice ) 1281 { 1282 return pDevice->ReadReport( data, length, false ); 1283 } 1284 } 1285 return -1; // Controller was disconnected 1286} 1287 1288 1289void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device) 1290{ 1291 if ( device ) 1292 { 1293 LOGV( "hid_close id=%d", device->m_nId ); 1294 hid_mutex_guard r( &g_DevicesRefCountMutex ); 1295 LOGD("Decrementing device %d (%p), refCount = %d\n", device->m_nId, device, device->m_nDeviceRefCount - 1); 1296 if ( --device->m_nDeviceRefCount == 0 ) 1297 { 1298 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1299 if ( pDevice ) 1300 { 1301 pDevice->Close( true ); 1302 } 1303 else 1304 { 1305 delete device; 1306 } 1307 LOGD("Deleted device %p\n", device); 1308 } 1309 } 1310} 1311 1312int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen) 1313{ 1314 if ( device ) 1315 { 1316 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1317 if ( pDevice ) 1318 { 1319 wcsncpy( string, pDevice->GetDeviceInfo()->manufacturer_string, maxlen ); 1320 return 0; 1321 } 1322 } 1323 return -1; 1324} 1325 1326int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen) 1327{ 1328 if ( device ) 1329 { 1330 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1331 if ( pDevice ) 1332 { 1333 wcsncpy( string, pDevice->GetDeviceInfo()->product_string, maxlen ); 1334 return 0; 1335 } 1336 } 1337 return -1; 1338} 1339 1340int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen) 1341{ 1342 if ( device ) 1343 { 1344 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1345 if ( pDevice ) 1346 { 1347 wcsncpy( string, pDevice->GetDeviceInfo()->serial_number, maxlen ); 1348 return 0; 1349 } 1350 } 1351 return -1; 1352} 1353 1354int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen) 1355{ 1356 return -1; 1357} 1358 1359struct hid_device_info *hid_get_device_info(hid_device *device) 1360{ 1361 if ( device ) 1362 { 1363 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1364 if ( pDevice ) 1365 { 1366 return pDevice->GetDeviceInfo(); 1367 } 1368 } 1369 return NULL; 1370} 1371 1372int hid_get_report_descriptor(hid_device *device, unsigned char *buf, size_t buf_size) 1373{ 1374 // Not implemented 1375 return -1; 1376} 1377 1378HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *device) 1379{ 1380 return NULL; 1381} 1382 1383int hid_exit(void) 1384{ 1385 return 0; 1386} 1387 1388} 1389 1390#else 1391 1392extern "C" 1393JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz); 1394 1395extern "C" 1396JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz); 1397 1398extern "C" 1399JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface, int nInterfaceClass, int nInterfaceSubclass, int nInterfaceProtocol, bool bBluetooth ); 1400 1401extern "C" 1402JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID); 1403 1404extern "C" 1405JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, int nDeviceID, bool bOpened); 1406 1407extern "C" 1408JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, int nDeviceID); 1409 1410extern "C" 1411JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value); 1412 1413extern "C" 1414JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReportResponse)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value); 1415 1416 1417extern "C" 1418JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz ) 1419{ 1420 LOGV("Stub HIDDeviceRegisterCallback()"); 1421} 1422 1423extern "C" 1424JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz) 1425{ 1426 LOGV("Stub HIDDeviceReleaseCallback()"); 1427} 1428 1429extern "C" 1430JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface, int nInterfaceClass, int nInterfaceSubclass, int nInterfaceProtocol, bool bBluetooth ) 1431{ 1432 LOGV("Stub HIDDeviceConnected() id=%d VID/PID = %.4x/%.4x, interface %d\n", nDeviceID, nVendorId, nProductId, nInterface); 1433} 1434 1435extern "C" 1436JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID) 1437{ 1438 LOGV("Stub HIDDeviceOpenPending() id=%d\n", nDeviceID); 1439} 1440 1441extern "C" 1442JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, int nDeviceID, bool bOpened) 1443{ 1444 LOGV("Stub HIDDeviceOpenResult() id=%d, result=%s\n", nDeviceID, bOpened ? "true" : "false"); 1445} 1446 1447extern "C" 1448JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, int nDeviceID) 1449{ 1450 LOGV("Stub HIDDeviceDisconnected() id=%d\n", nDeviceID); 1451} 1452 1453extern "C" 1454JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value) 1455{ 1456 LOGV("Stub HIDDeviceInput() id=%d len=%u\n", nDeviceID, nBufSize); 1457} 1458 1459extern "C" 1460JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReportResponse)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value) 1461{ 1462 LOGV("Stub HIDDeviceReportResponse() id=%d len=%u\n", nDeviceID, nBufSize); 1463} 1464 1465#endif /* SDL_HIDAPI_DISABLED */ 1466 1467extern "C" 1468JNINativeMethod HIDDeviceManager_tab[8] = { 1469 { "HIDDeviceRegisterCallback", "()V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback) }, 1470 { "HIDDeviceReleaseCallback", "()V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback) }, 1471 { "HIDDeviceConnected", "(ILjava/lang/String;IILjava/lang/String;ILjava/lang/String;Ljava/lang/String;IIIIZ)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected) }, 1472 { "HIDDeviceOpenPending", "(I)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending) }, 1473 { "HIDDeviceOpenResult", "(IZ)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult) }, 1474 { "HIDDeviceDisconnected", "(I)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected) }, 1475 { "HIDDeviceInputReport", "(I[B)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport) }, 1476 { "HIDDeviceReportResponse", "(I[B)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReportResponse) } 1477}; 1478[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.