diff --git a/.appveyor.yml b/.appveyor.yml index e7897f406d..c83642f89f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -32,7 +32,7 @@ on_success: If ($env:configuration -eq 'Release') { cd "bin\${env:configuration}" 7z u "${env:configuration}.zip" ..\..\..\COPYING ..\..\..\README.md - 7z u "${env:configuration}.zip" Cxbx.exe glew32.dll subhook.dll CxbxVSBC.dll + 7z u "${env:configuration}.zip" Cxbx.exe glew32.dll subhook.dll SDL2.dll 7z u "${env:configuration}.zip" cxbxr-debugger.exe capstone.dll cs_x86.dll Get-ChildItem .\*.zip | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } } diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 0280922f14..996dd5fdf2 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -50,7 +50,7 @@ jobs: build\bin\$(configuration)\Cxbx.exe build\bin\$(configuration)\glew32.dll build\bin\$(configuration)\subhook.dll - build\bin\$(configuration)\CxbxVSBC.dll + build\bin\$(configuration)\SDL2.dll build\bin\$(configuration)\cxbxr-debugger.exe build\bin\$(configuration)\capstone.dll build\bin\$(configuration)\cx_x86.dll diff --git a/.gitmodules b/.gitmodules index 87bacd292a..d0f38eba87 100644 --- a/.gitmodules +++ b/.gitmodules @@ -18,3 +18,6 @@ path = import/libtomcrypt url = https://github.com/libtom/libtomcrypt branch = master +[submodule "import/SDL2"] + path = import/SDL2 + url = https://github.com/SDL-mirror/SDL diff --git a/.travis.yml b/.travis.yml index 783ddd58f0..1fadc7b084 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ script: # - mkdir export # - 7z u export/${configuration} COPYING README.md # - cd build/win32/${configuration} -# - 7z u ../../../export/${configuration} Cxbx.exe glew32.dll subhook.dll CxbxVSBC.dll +# - 7z u ../../../export/${configuration} Cxbx.exe glew32.dll subhook.dll SDL2.dll # - 7z u ../../../export/${configuration} CxbxDebugger.exe capstone.dll cs_x86.dll # - cd ../../../ diff --git a/CMakeLists.txt b/CMakeLists.txt index 3678e7c0dd..5d9838affd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/import/XbSymbolDatabase") # Not require since only include a header file #add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/import/simpleini") -#add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/import/SDL2") +add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/import/SDL2") if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|[9][0-9])") add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/import/cs_x86") @@ -54,7 +54,7 @@ configure_file( NEWLINE_STYLE LF ) -add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/vsbc") +#add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/vsbc") # Split the files into group for which project is likely # going to be used for both header and source files. @@ -73,8 +73,15 @@ file (GLOB CXBXR_HEADER_COMMON "${CXBXR_ROOT_DIR}/src/common/CxbxDebugger.h" "${CXBXR_ROOT_DIR}/src/common/EmuEEPROM.h" "${CXBXR_ROOT_DIR}/src/common/Error.h" - "${CXBXR_ROOT_DIR}/src/common/input/InputConfig.h" - "${CXBXR_ROOT_DIR}/src/common/input/SDL2_Device.h" + "${CXBXR_ROOT_DIR}/src/common/input/Button.h" + "${CXBXR_ROOT_DIR}/src/common/input/DInputKeyboardCodes.h" + "${CXBXR_ROOT_DIR}/src/common/input/DInputKeyboardMouse.h" + "${CXBXR_ROOT_DIR}/src/common/input/EmuDevice.h" + "${CXBXR_ROOT_DIR}/src/common/input/InputDevice.h" + "${CXBXR_ROOT_DIR}/src/common/input/InputManager.h" + "${CXBXR_ROOT_DIR}/src/common/input/InputWindow.h" + "${CXBXR_ROOT_DIR}/src/common/input/SdlJoystick.h" + "${CXBXR_ROOT_DIR}/src/common/input/XInputPad.h" "${CXBXR_ROOT_DIR}/src/common/IPCHybrid.hpp" "${CXBXR_ROOT_DIR}/src/common/Logging.h" "${CXBXR_ROOT_DIR}/src/common/ReservedMemory.h" @@ -85,11 +92,9 @@ file (GLOB CXBXR_HEADER_COMMON "${CXBXR_ROOT_DIR}/src/common/util/CxbxUtil.h" "${CXBXR_ROOT_DIR}/src/common/win32/AlignPosfix1.h" "${CXBXR_ROOT_DIR}/src/common/win32/AlignPrefix1.h" - "${CXBXR_ROOT_DIR}/src/common/win32/DInputController.h" "${CXBXR_ROOT_DIR}/src/common/win32/EmuShared.h" "${CXBXR_ROOT_DIR}/src/common/win32/Mutex.h" "${CXBXR_ROOT_DIR}/src/common/win32/Threads.h" - "${CXBXR_ROOT_DIR}/src/common/win32/XBPortMapping.h" "${CXBXR_ROOT_DIR}/src/common/xbdm/CxbxXbdm.h" "${CXBXR_ROOT_DIR}/src/common/xbe/Xbe.h" "${CXBXR_ROOT_DIR}/src/common/xbe/XbePrinter.h" @@ -105,12 +110,12 @@ file (GLOB CXBXR_HEADER_GUIv1 "${CXBXR_ROOT_DIR}/src/gui/DbgConsole.h" "${CXBXR_ROOT_DIR}/src/gui/DlgAbout.h" "${CXBXR_ROOT_DIR}/src/gui/DlgAudioConfig.h" - "${CXBXR_ROOT_DIR}/src/gui/DlgControllerConfig.h" + "${CXBXR_ROOT_DIR}/src/gui/DlgInputConfig.h" + "${CXBXR_ROOT_DIR}/src/gui/DlgDukeControllerConfig.h" "${CXBXR_ROOT_DIR}/src/gui/DlgEepromConfig.h" "${CXBXR_ROOT_DIR}/src/gui/DlgLoggingConfig.h" "${CXBXR_ROOT_DIR}/src/gui/DlgNetworkConfig.h" "${CXBXR_ROOT_DIR}/src/gui/DlgVideoConfig.h" - "${CXBXR_ROOT_DIR}/src/gui/DlgXboxControllerPortMapping.h" "${CXBXR_ROOT_DIR}/src/gui/ResCxbx.h" "${CXBXR_ROOT_DIR}/src/gui/Wnd.h" "${CXBXR_ROOT_DIR}/src/gui/WndMain.h" @@ -140,9 +145,8 @@ file (GLOB CXBXR_HEADER_EMU "${CXBXR_ROOT_DIR}/src/core/hle/Intercept.hpp" "${CXBXR_ROOT_DIR}/src/core/hle/Patches.hpp" "${CXBXR_ROOT_DIR}/src/core/hle/XACTENG/XactEng.h" - "${CXBXR_ROOT_DIR}/src/core/hle/XAPI/OHCI/XInput/DInput.h" - "${CXBXR_ROOT_DIR}/src/core/hle/XAPI/OHCI/XInput/XInput.h" "${CXBXR_ROOT_DIR}/src/core/hle/XAPI/Xapi.h" + "${CXBXR_ROOT_DIR}/src/core/hle/XAPI/XapiCxbxr.h" "${CXBXR_ROOT_DIR}/src/core/hle/XGRAPHIC/XGraphic.h" "${CXBXR_ROOT_DIR}/src/core/hle/XONLINE/XOnline.h" "${CXBXR_ROOT_DIR}/src/core/kernel/common/strings.hpp" @@ -199,21 +203,25 @@ file (GLOB CXBXR_SOURCE_COMMON "${CXBXR_ROOT_DIR}/src/common/CxbxDebugger.cpp" "${CXBXR_ROOT_DIR}/src/common/EmuEEPROM.cpp" "${CXBXR_ROOT_DIR}/src/common/Error.cpp" - "${CXBXR_ROOT_DIR}/src/common/input/InputConfig.cpp" - "${CXBXR_ROOT_DIR}/src/common/input/SDL2_Device.cpp" + "${CXBXR_ROOT_DIR}/src/common/input/Button.cpp" + "${CXBXR_ROOT_DIR}/src/common/input/DInputKeyboardMouse.cpp" + "${CXBXR_ROOT_DIR}/src/common/input/EmuDevice.cpp" + "${CXBXR_ROOT_DIR}/src/common/input/InputDevice.cpp" + "${CXBXR_ROOT_DIR}/src/common/input/InputManager.cpp" + "${CXBXR_ROOT_DIR}/src/common/input/InputWindow.cpp" + "${CXBXR_ROOT_DIR}/src/common/input/SdlJoystick.cpp" + "${CXBXR_ROOT_DIR}/src/common/input/XInputPad.cpp" "${CXBXR_ROOT_DIR}/src/common/Logging.cpp" "${CXBXR_ROOT_DIR}/src/common/Settings.cpp" "${CXBXR_ROOT_DIR}/src/common/Timer.cpp" "${CXBXR_ROOT_DIR}/src/common/util/crc32c.cpp" "${CXBXR_ROOT_DIR}/src/common/util/CxbxUtil.cpp" "${CXBXR_ROOT_DIR}/src/common/util/hasher.cpp" - "${CXBXR_ROOT_DIR}/src/common/win32/DInputController.cpp" "${CXBXR_ROOT_DIR}/src/common/win32/EmuShared.cpp" "${CXBXR_ROOT_DIR}/src/common/win32/InlineFunc.cpp" "${CXBXR_ROOT_DIR}/src/common/win32/IPCWindows.cpp" "${CXBXR_ROOT_DIR}/src/common/win32/Mutex.cpp" "${CXBXR_ROOT_DIR}/src/common/win32/Threads.cpp" - "${CXBXR_ROOT_DIR}/src/common/win32/XBPortMapping.cpp" "${CXBXR_ROOT_DIR}/src/common/xbdm/CxbxXbdm.cpp" "${CXBXR_ROOT_DIR}/src/common/xbe/Xbe.cpp" "${CXBXR_ROOT_DIR}/src/common/xbe/XbePrinter.cpp" @@ -227,12 +235,12 @@ file (GLOB CXBXR_SOURCE_COMMON file (GLOB CXBXR_SOURCE_GUIv1 "${CXBXR_ROOT_DIR}/src/gui/DlgAbout.cpp" "${CXBXR_ROOT_DIR}/src/gui/DlgAudioConfig.cpp" - "${CXBXR_ROOT_DIR}/src/gui/DlgControllerConfig.cpp" + "${CXBXR_ROOT_DIR}/src/gui/DlgInputConfig.cpp" + "${CXBXR_ROOT_DIR}/src/gui/DlgDukeControllerConfig.cpp" "${CXBXR_ROOT_DIR}/src/gui/DlgEepromConfig.cpp" "${CXBXR_ROOT_DIR}/src/gui/DlgLoggingConfig.cpp" "${CXBXR_ROOT_DIR}/src/gui/DlgNetworkConfig.cpp" "${CXBXR_ROOT_DIR}/src/gui/DlgVideoConfig.cpp" - "${CXBXR_ROOT_DIR}/src/gui/DlgXboxControllerPortMapping.cpp" "${CXBXR_ROOT_DIR}/src/gui/WinMain.cpp" "${CXBXR_ROOT_DIR}/src/gui/Wnd.cpp" "${CXBXR_ROOT_DIR}/src/gui/WndMain.cpp" @@ -265,8 +273,6 @@ file (GLOB CXBXR_SOURCE_EMU "${CXBXR_ROOT_DIR}/src/core/hle/Intercept.cpp" "${CXBXR_ROOT_DIR}/src/core/hle/Patches.cpp" "${CXBXR_ROOT_DIR}/src/core/hle/XACTENG/XactEng.cpp" - "${CXBXR_ROOT_DIR}/src/core/hle/XAPI/OHCI/XInput/DInput.cpp" - "${CXBXR_ROOT_DIR}/src/core/hle/XAPI/OHCI/XInput/XInput.cpp" "${CXBXR_ROOT_DIR}/src/core/hle/XAPI/Xapi.cpp" "${CXBXR_ROOT_DIR}/src/core/hle/XGRAPHIC/XGraphic.cpp" "${CXBXR_ROOT_DIR}/src/core/hle/XONLINE/XOnline.cpp" @@ -374,6 +380,6 @@ if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|[9][0-9])") endif() # Cxbx-Reloaded project with third-party libraries -set_target_properties(cxbx subhook XbSymbolDatabase vsbc libtommath libtomcrypt +set_target_properties(cxbx subhook XbSymbolDatabase libtommath libtomcrypt PROPERTIES FOLDER Cxbx-Reloaded ) diff --git a/import/SDL2 b/import/SDL2 new file mode 160000 index 0000000000..c7b8b49ef8 --- /dev/null +++ b/import/SDL2 @@ -0,0 +1 @@ +Subproject commit c7b8b49ef8691ac85ad18298468f7e4a616290ed diff --git a/projects/cxbx/CMakeLists.txt b/projects/cxbx/CMakeLists.txt index b277805c2a..0172b97ab4 100644 --- a/projects/cxbx/CMakeLists.txt +++ b/projects/cxbx/CMakeLists.txt @@ -21,6 +21,7 @@ include_directories( "${CXBXR_ROOT_DIR}/import/libtommath" "${CXBXR_ROOT_DIR}/import/libtomcrypt/src/headers" "${CXBXR_ROOT_DIR}/import/winpcap/Include" + "${CXBXR_ROOT_DIR}/import/SDL2/include" ) link_directories( @@ -175,12 +176,12 @@ set(WINS_LIB XINPUT9_1_0 Iphlpapi wpcap + SDL2 ) target_link_libraries(cxbx PUBLIC XbSymbolDatabase subhook - vsbc libtomcrypt ${WINS_LIB} diff --git a/resource/Cxbx.rc b/resource/Cxbx.rc index 545cc7d56e..e03f5addc4 100644 --- a/resource/Cxbx.rc +++ b/resource/Cxbx.rc @@ -27,14 +27,6 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN - IDD_CONTROLLER_HOST_MAPPING, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 394 - TOPMARGIN, 7 - BOTTOMMARGIN, 112 - END - IDD_VIRTUAL_SBC_FEEDBACK, DIALOG BEGIN LEFTMARGIN, 7 @@ -43,10 +35,6 @@ BEGIN BOTTOMMARGIN, 207 END - IDD_CONTROLLER_CFG, DIALOG - BEGIN - END - IDD_VIDEO_CFG, DIALOG BEGIN BOTTOMMARGIN, 121 @@ -78,45 +66,104 @@ END // Dialog // -IDD_CONTROLLER_HOST_MAPPING DIALOGEX 0, 0, 401, 119 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Config Xbox Controller to Host Mapping" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 +IDD_INPUT_CFG DIALOGEX 0, 0, 243, 124 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Cxbx-Reloaded : Input Configuration" +FONT 8, "Verdana", 0, 0, 0x1 BEGIN - DEFPUSHBUTTON "Apply",IDC_HOST_APPLY,288,98,50,14 - PUSHBUTTON "Cancel",IDC_HOST_CANCEL,344,98,50,14 - GROUPBOX "Xbox Port 0",IDC_XBOX_PORT_0,7,7,93,83,WS_GROUP,WS_EX_CLIENTEDGE - CONTROL "Not Connected",IDC_HOST_NOTCONNECT_0_0,"Button",BS_AUTORADIOBUTTON,17,19,64,10 - CONTROL "XInput Port 0",IDC_HOST_XINPUT_0_0,"Button",BS_AUTORADIOBUTTON,17,28,59,10 - CONTROL "XInput Port 1",IDC_HOST_XINPUT_0_1,"Button",BS_AUTORADIOBUTTON,17,37,59,10 - CONTROL "XInput Port 2",IDC_HOST_XINPUT_0_2,"Button",BS_AUTORADIOBUTTON,17,46,59,10 - CONTROL "XInput Port 3",IDC_HOST_XINPUT_0_3,"Button",BS_AUTORADIOBUTTON,17,55,59,10 - CONTROL "DirectInput Port 0",IDC_HOST_DINPUT_0_0,"Button",BS_AUTORADIOBUTTON,17,64,73,10 - CONTROL "Virtual SteelBattalion",IDC_HOST_VIRTUAL_SBC_0_0,"Button",BS_AUTORADIOBUTTON,17,74,79,10 - GROUPBOX "Xbox Port 1",IDC_XBOX_PORT_1,104,7,93,83,WS_GROUP,WS_EX_CLIENTEDGE - CONTROL "Not Connected",IDC_HOST_NOTCONNECT_1_0,"Button",BS_AUTORADIOBUTTON,114,20,64,10 - CONTROL "XInput Port 0",IDC_HOST_XINPUT_1_0,"Button",BS_AUTORADIOBUTTON,114,29,59,10 - CONTROL "XInput Port 1",IDC_HOST_XINPUT_1_1,"Button",BS_AUTORADIOBUTTON,114,38,59,10 - CONTROL "XInput Port 2",IDC_HOST_XINPUT_1_2,"Button",BS_AUTORADIOBUTTON,114,47,59,10 - CONTROL "XInput Port 3",IDC_HOST_XINPUT_1_3,"Button",BS_AUTORADIOBUTTON,114,56,59,10 - CONTROL "DirectInput Port 0",IDC_HOST_DINPUT_1_0,"Button",BS_AUTORADIOBUTTON,114,65,73,10 - CONTROL "Virtual SteelBattalion",IDC_HOST_VIRTUAL_SBC_1_0,"Button",BS_AUTORADIOBUTTON,114,75,79,10 - GROUPBOX "Xbox Port 2",IDC_XBOX_PORT_2,201,7,93,83,WS_GROUP,WS_EX_CLIENTEDGE - CONTROL "Not Connected",IDC_HOST_NOTCONNECT_2_0,"Button",BS_AUTORADIOBUTTON,211,21,64,10 - CONTROL "XInput Port 0",IDC_HOST_XINPUT_2_0,"Button",BS_AUTORADIOBUTTON,211,30,59,10 - CONTROL "XInput Port 1",IDC_HOST_XINPUT_2_1,"Button",BS_AUTORADIOBUTTON,211,39,59,10 - CONTROL "XInput Port 2",IDC_HOST_XINPUT_2_2,"Button",BS_AUTORADIOBUTTON,211,48,59,10 - CONTROL "XInput Port 3",IDC_HOST_XINPUT_2_3,"Button",BS_AUTORADIOBUTTON,211,57,59,10 - CONTROL "DirectInput Port 0",IDC_HOST_DINPUT_2_0,"Button",BS_AUTORADIOBUTTON,211,66,73,10 - CONTROL "Virtual SteelBattalion",IDC_HOST_VIRTUAL_SBC_2_0,"Button",BS_AUTORADIOBUTTON,211,75,79,10 - GROUPBOX "Xbox Port 3",IDC_XBOX_PORT_3,298,7,93,83,WS_GROUP,WS_EX_CLIENTEDGE - CONTROL "Not Connected",IDC_HOST_NOTCONNECT_3_0,"Button",BS_AUTORADIOBUTTON,308,21,64,10 - CONTROL "XInput Port 0",IDC_HOST_XINPUT_3_0,"Button",BS_AUTORADIOBUTTON,308,30,59,10 - CONTROL "XInput Port 1",IDC_HOST_XINPUT_3_1,"Button",BS_AUTORADIOBUTTON,308,39,59,10 - CONTROL "XInput Port 2",IDC_HOST_XINPUT_3_2,"Button",BS_AUTORADIOBUTTON,308,48,59,10 - CONTROL "XInput Port 3",IDC_HOST_XINPUT_3_3,"Button",BS_AUTORADIOBUTTON,308,57,59,10 - CONTROL "DirectInput Port 0",IDC_HOST_DINPUT_3_0,"Button",BS_AUTORADIOBUTTON,308,66,73,10 - CONTROL "Virtual SteelBattalion",IDC_HOST_VIRTUAL_SBC_3_0,"Button",BS_AUTORADIOBUTTON,308,75,79,10 + GROUPBOX "Xbox device configuration", IDC_XID_CONFIG, 13, 10, 217, 103, WS_GROUP, WS_EX_CLIENTEDGE + COMBOBOX IDC_DEVICE_PORT1, 50, 25, 110, 14, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_DEVICE_PORT2, 50, 46, 110, 14, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_DEVICE_PORT3, 50, 67, 110, 14, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_DEVICE_PORT4, 50, 88, 110, 14, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure", IDC_CONFIGURE_PORT1, 166, 25, 50, 14, BS_FLAT + PUSHBUTTON "Configure", IDC_CONFIGURE_PORT2, 166, 46, 50, 14, BS_FLAT + PUSHBUTTON "Configure", IDC_CONFIGURE_PORT3, 166, 67, 50, 14, BS_FLAT + PUSHBUTTON "Configure", IDC_CONFIGURE_PORT4, 166, 88, 50, 14, BS_FLAT + LTEXT "Port 1", IDC_STATIC, 23, 27, 20, 10 + LTEXT "Port 2", IDC_STATIC, 23, 48, 20, 10 + LTEXT "Port 3", IDC_STATIC, 23, 69, 20, 10 + LTEXT "Port 4", IDC_STATIC, 23, 90, 20, 10 +END + +IDD_XID_DUKE_CFG DIALOGEX 0, 0, 528, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +FONT 8, "Verdana", 0, 0, 0x1 +BEGIN + GROUPBOX "Device", IDC_XID_CONFIG, 12, 10, 175, 35, WS_GROUP + COMBOBOX IDC_DEVICE_LIST, 21, 23, 101, 15, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Refresh", IDC_REFRESH_DEVICES, 128, 23, 50, 14, BS_FLAT + GROUPBOX "Profile", IDC_XID_PROFILE, 197, 10, 320, 35, WS_GROUP + COMBOBOX IDC_XID_PROFILE_NAME, 207, 24, 194, 10, CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Save", IDC_XID_PROFILE_SAVE, 405, 23, 50, 14, BS_FLAT + PUSHBUTTON "Delete", IDC_XID_PROFILE_DELETE, 459, 23, 50, 14, BS_FLAT + GROUPBOX "Buttons", IDC_XID_BUTTONS, 12, 65, 121, 181, WS_GROUP + PUSHBUTTON "", IDC_SET_A, 59, 75, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_B, 59, 93, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_X, 59, 111, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_Y, 59, 129, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_BLACK, 59, 147, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_WHITE, 59, 165, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_BACK, 59, 183, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_START, 59, 201, 57, 14, BS_FLAT + LTEXT "A", IDC_STATIC, 28, 75, 20, 14, SS_CENTERIMAGE + LTEXT "B", IDC_STATIC, 28, 93, 20, 14, SS_CENTERIMAGE + LTEXT "X", IDC_STATIC, 28, 111, 20, 14, SS_CENTERIMAGE + LTEXT "Y", IDC_STATIC, 28, 129, 20, 14, SS_CENTERIMAGE + LTEXT "Black", IDC_STATIC, 28, 147, 20, 14, SS_CENTERIMAGE + LTEXT "White", IDC_STATIC, 28, 165, 20, 14, SS_CENTERIMAGE + LTEXT "Back", IDC_STATIC, 28, 183, 20, 14, SS_CENTERIMAGE + LTEXT "Start", IDC_STATIC, 28, 201, 20, 14, SS_CENTERIMAGE + GROUPBOX "L Stick", IDC_XID_LSTICK, 140, 65, 121, 181, WS_GROUP + PUSHBUTTON "", IDC_SET_LEFT_POSY, 187, 75, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_LEFT_NEGY, 187, 93, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_LEFT_NEGX, 187, 111, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_LEFT_POSX, 187, 129, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_LTHUMB, 187, 147, 57, 14, BS_FLAT + LTEXT "Up", IDC_STATIC, 156, 75, 20, 14, SS_CENTERIMAGE + LTEXT "Down", IDC_STATIC, 156, 93, 20, 14, SS_CENTERIMAGE + LTEXT "Left", IDC_STATIC, 156, 111, 20, 14, SS_CENTERIMAGE + LTEXT "Right", IDC_STATIC, 156, 129, 20, 14, SS_CENTERIMAGE + LTEXT "L Click", IDC_STATIC, 156, 147, 27, 14, SS_CENTERIMAGE + GROUPBOX "R Stick", IDC_XID_RSTICK, 268, 65, 121, 181, WS_GROUP + PUSHBUTTON "", IDC_SET_RIGHT_POSY, 315, 75, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_RIGHT_NEGY, 315, 93, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_RIGHT_NEGX, 315, 111, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_RIGHT_POSX, 315, 129, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_RTHUMB, 315, 147, 57, 14, BS_FLAT + LTEXT "Up", IDC_STATIC, 284, 75, 20, 14, SS_CENTERIMAGE + LTEXT "Down", IDC_STATIC, 284, 93, 20, 14, SS_CENTERIMAGE + LTEXT "Left", IDC_STATIC, 284, 111, 20, 14, SS_CENTERIMAGE + LTEXT "Right", IDC_STATIC, 284, 129, 20, 14, SS_CENTERIMAGE + LTEXT "R Click", IDC_STATIC, 284, 147, 27, 14, SS_CENTERIMAGE + GROUPBOX "D Pad", IDC_XID_DPAD, 396, 65, 121, 88, WS_GROUP + PUSHBUTTON "", IDC_SET_DPAD_UP, 443, 75, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_DPAD_DOWN, 443, 93, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_DPAD_LEFT, 443, 111, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_DPAD_RIGHT, 443, 129, 57, 14, BS_FLAT + LTEXT "Up", IDC_STATIC, 412, 75, 20, 14, SS_CENTERIMAGE + LTEXT "Down", IDC_STATIC, 412, 93, 20, 14, SS_CENTERIMAGE + LTEXT "Left", IDC_STATIC, 412, 111, 20, 14, SS_CENTERIMAGE + LTEXT "Right", IDC_STATIC, 412, 129, 20, 14, SS_CENTERIMAGE + GROUPBOX "Triggers", IDC_XID_TRIGGERS, 396, 157, 121, 52, WS_GROUP + PUSHBUTTON "", IDC_SET_LTRIGGER, 443, 168, 57, 14, BS_FLAT + PUSHBUTTON "", IDC_SET_RTRIGGER, 443, 187, 57, 14, BS_FLAT + LTEXT "Left", IDC_STATIC, 412, 168, 20, 14, SS_CENTERIMAGE + LTEXT "Right", IDC_STATIC, 412, 187, 20, 14, SS_CENTERIMAGE + GROUPBOX "Rumble", IDC_XID_RUMBLE, 396, 212, 121, 34, WS_GROUP + PUSHBUTTON "", IDC_SET_MOTOR, 443, 224, 57, 14, BS_FLAT + LTEXT "Motor", IDC_STATIC, 412, 224, 26, 14, SS_CENTERIMAGE + PUSHBUTTON "XInput Default", IDC_XINP_DEFAULT, 362, 256, 69, 14, BS_FLAT + PUSHBUTTON "Clear", IDC_XID_CLEAR, 443, 256, 50, 14, BS_FLAT +END + +IDD_RUMBLE_CFG DIALOGEX 0, 0, 155, 35 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Rumble Configuration" +FONT 8, "Verdana", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_RUMBLE_LIST, 15, 11, 70, 15, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Test", IDC_RUMBLE_TEST, 95, 11, 45, 14, BS_FLAT END IDD_VIRTUAL_SBC_FEEDBACK DIALOGEX 0, 0, 1039, 214 @@ -236,45 +283,6 @@ BEGIN CONTROL "",IDC_PB_FILT_CONTROL_SYSTEM,"msctls_progress32",WS_BORDER,169,165,14,10 END -IDD_CONTROLLER_CFG DIALOGEX 0, 0, 343, 137 -STYLE DS_SETFONT | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Cxbx-Reloaded : Controller Configuration" -FONT 8, "Verdana", 0, 0, 0x1 -BEGIN - PUSHBUTTON "X",IDC_SET_X,7,11,50,14,BS_FLAT - PUSHBUTTON "Y",IDC_SET_Y,60,11,50,14,BS_FLAT - PUSHBUTTON "A",IDC_SET_A,113,11,50,14,BS_FLAT - PUSHBUTTON "B",IDC_SET_B,167,11,50,14,BS_FLAT - PUSHBUTTON "White",IDC_SET_WHITE,7,29,50,14,BS_FLAT - PUSHBUTTON "Black",IDC_SET_BLACK,60,29,50,14,BS_FLAT - PUSHBUTTON "Left Trigger",IDC_SET_LTRIGGER,113,29,50,14,BS_FLAT - PUSHBUTTON "Right Trigger",IDC_SET_RTRIGGER,167,29,50,14,BS_FLAT - PUSHBUTTON "DPad Up",IDC_SET_DPAD_UP,6,61,50,14,BS_FLAT - PUSHBUTTON "DPad Down",IDC_SET_DPAD_DOWN,60,61,50,14,BS_FLAT - PUSHBUTTON "DPad Left",IDC_SET_DPAD_LEFT,113,61,50,14,BS_FLAT - PUSHBUTTON "DPad Right",IDC_SET_DPAD_RIGHT,167,61,50,14,BS_FLAT - PUSHBUTTON "Back",IDC_SET_BACK,6,79,50,14,BS_FLAT - PUSHBUTTON "Start",IDC_SET_START,60,79,50,14,BS_FLAT - PUSHBUTTON "Left Thumb",IDC_SET_LTHUMB,113,79,50,14,BS_FLAT - PUSHBUTTON "Right Thumb",IDC_SET_RTHUMB,167,79,50,14,BS_FLAT - PUSHBUTTON "Up",IDC_SET_LEFT_POSY,231,11,50,14,BS_FLAT - PUSHBUTTON "Down",IDC_SET_LEFT_NEGY,284,11,50,14,BS_FLAT - PUSHBUTTON "Left",IDC_SET_LEFT_NEGX,231,29,50,14,BS_FLAT - PUSHBUTTON "Right",IDC_SET_LEFT_POSX,284,29,50,14,BS_FLAT - PUSHBUTTON "Up",IDC_SET_RIGHT_POSY,231,61,50,14,BS_FLAT - PUSHBUTTON "Down",IDC_SET_RIGHT_NEGY,284,61,50,14,BS_FLAT - PUSHBUTTON "Left",IDC_SET_RIGHT_NEGX,231,79,50,14,BS_FLAT - PUSHBUTTON "Right",IDC_SET_RIGHT_POSX,284,79,50,14,BS_FLAT - PUSHBUTTON "&Cancel",IDC_INPUT_CONFIG_CANCEL,231,102,50,14,BS_FLAT - PUSHBUTTON "&Accept",IDC_INPUT_CONFIG_ACCEPT,284,102,51,14,BS_FLAT - GROUPBOX "Analog Buttons",IDC_STATIC,2,1,220,47 - GROUPBOX "Digital Buttons",IDC_STATIC,2,51,220,46 - GROUPBOX "Analog Thumbstick (Left)",IDC_STATIC,226,1,113,47 - GROUPBOX "Analog Thumbstick (Right)",IDC_STATIC,227,51,112,46 - CTEXT "Please choose one of the controller components from above...",IDC_CONFIG_STATUS,2,121,336,12,SS_CENTERIMAGE,WS_EX_STATICEDGE - PUSHBUTTON "Click to configure all input...",IDC_CONFIGURE_ALL,6,102,210,14,BS_FLAT -END - IDD_VIDEO_CFG DIALOGEX 0, 0, 259, 150 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Cxbx-Reloaded : Video Configuration" @@ -405,7 +413,7 @@ BEGIN CONTROL "VTXB",IDC_LOG_VTXB,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,87,129,34,10 CONTROL "DINP",IDC_LOG_DINP,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,142,129,33,10 CONTROL "XINP",IDC_LOG_XINP,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,202,129,32,10 - CONTROL "SDL2",IDC_LOG_SDL2,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,33,144,33,10 + CONTROL "SDL",IDC_LOG_SDL,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,33,144,33,10 CONTROL "FILE",IDC_LOG_FILE,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,91,144,30,10 CONTROL "X86",IDC_LOG_X86,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,146,144,29,10 CONTROL "HLE",IDC_LOG_HLE,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,206,144,28,10 @@ -418,6 +426,7 @@ BEGIN CONTROL "HUB",IDC_LOG_HUB,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,145,174,30,10 CONTROL "XIDCTRL",IDC_LOG_XIDCTRL,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,188,174,46,10 CONTROL "ADM",IDC_LOG_ADM,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,35,189,31,10 + CONTROL "INPSYS",IDC_LOG_INPSYS,"Button",BS_AUTOCHECKBOX|BS_LEFTTEXT|WS_TABSTOP,80,189,41,10 GROUPBOX "Kernel Event",IDC_KERNEL_EVENTS,13,212,235,110,WS_GROUP,WS_EX_CLIENTEDGE CONTROL "Enable all",IDC_LOG_ENABLE_KERNEL,"Button",BS_AUTORADIOBUTTON | BS_LEFTTEXT,19,226,47,10 CONTROL "Disable all",IDC_LOG_DISABLE_KERNEL,"Button",BS_AUTORADIOBUTTON | BS_LEFTTEXT,71,226,50,10 @@ -599,9 +608,7 @@ BEGIN END POPUP "&Settings", 65535,MFT_STRING,MFS_ENABLED BEGIN - MENUITEM "Config Xbox Controller &Mapping", ID_SETTINGS_CONFIG_XBOX_CONTROLLER_MAPPING,MFT_STRING,MFS_ENABLED - MENUITEM "Config DirectInput &Controller...", ID_SETTINGS_CONFIG_CONTROLLER,MFT_STRING,MFS_ENABLED - MENUITEM MFT_SEPARATOR + MENUITEM "Config I&nput...", ID_SETTINGS_CONFIG_INPUT, MFT_STRING, MFS_ENABLED MENUITEM "Config &Video...", ID_SETTINGS_CONFIG_VIDEO,MFT_STRING,MFS_ENABLED MENUITEM "Config &Audio...", ID_SETTINGS_CONFIG_AUDIO,MFT_STRING,MFS_ENABLED MENUITEM "Config &Network...", ID_SETTINGS_CONFIG_NETWORK,MFT_STRING,MFS_ENABLED diff --git a/src/common/IPCHybrid.hpp b/src/common/IPCHybrid.hpp index a2f7963bee..5a249f2288 100644 --- a/src/common/IPCHybrid.hpp +++ b/src/common/IPCHybrid.hpp @@ -49,6 +49,7 @@ void ipc_send_gui_update(IPC_UPDATE_GUI command, const unsigned int value); typedef enum class _IPC_UPDATE_KERNEL { CONFIG_LOGGING_SYNC = 0 + , CONFIG_INPUT_SYNC } IPC_UPDATE_KERNEL; void ipc_send_kernel_update(IPC_UPDATE_KERNEL command, const unsigned int value, const unsigned int hwnd); diff --git a/src/common/Logging.cpp b/src/common/Logging.cpp index 96457bcf1b..45d5fa6241 100644 --- a/src/common/Logging.cpp +++ b/src/common/Logging.cpp @@ -61,7 +61,7 @@ const char* g_EnumModules2String[to_underlying(CXBXR_MODULE::MAX)] = { "VTXB ", "DINP ", "XINP ", - "SDL2 ", + "SDL ", "FILE ", "X86 ", "HLE ", @@ -74,6 +74,7 @@ const char* g_EnumModules2String[to_underlying(CXBXR_MODULE::MAX)] = { "HUB ", "XIDCTRL ", "ADM ", + "INPSYS ", "KRNL ", "LOG ", "XBOX ", diff --git a/src/common/Logging.h b/src/common/Logging.h index 201cbedefe..8b2ac04765 100644 --- a/src/common/Logging.h +++ b/src/common/Logging.h @@ -71,7 +71,7 @@ typedef enum class _CXBXR_MODULE: unsigned int { VTXB, DINP, XINP, - SDL2, + SDL, FILE, X86, HLE, @@ -84,6 +84,7 @@ typedef enum class _CXBXR_MODULE: unsigned int { HUB, XIDCTRL, ADM, + INPSYS, // kernel KRNL, LOG, diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index c84e50fe87..c8b5f2e67f 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -20,7 +20,8 @@ // * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. // * // * (c) 2018 wutno (#/g/punk - Rizon) -// * (c) 2018 RadWolfie +// * (c) 2018 RadWolfie +// * (c) 2019 ergo720 // * // * All rights reserved // * @@ -29,7 +30,8 @@ #include "Settings.hpp" #include "core\kernel\support\Emu.h" #include "EmuShared.h" -#include +#include +#include "common\input\EmuDevice.h" // TODO: Implement Qt support when real CPU emulation is available. #ifndef QT_VERSION // NOTE: Non-Qt will be using current directory for data @@ -48,8 +50,15 @@ std::string g_exec_filepath; uint16_t g_LibVersion_D3D8 = 0; uint16_t g_LibVersion_DSOUND = 0; -// NOTE: Update settings_version when add/edit/delete setting's structure. -const unsigned int settings_version = 4; +// NOTE: Update settings_version when add/edit/delete setting's structure. +/////////////////////////// +// * History: +// * 2: (RadWolfie), initial version +// * 3: (ergo720), added logging settings +// * 4: (LukeUsher), added network settings +// * 5: (ergo720), added new input gui settings and revision to core +/////////////////////////// +const unsigned int settings_version = 5; Settings* g_Settings = nullptr; @@ -71,7 +80,8 @@ static struct { } sect_gui_keys; static const char* section_core = "core"; -static struct { +static struct { + const char* Revision = "Revision"; const char* FlagsLLE = "FlagsLLE"; const char* KrnlDebugMode = "KrnlDebugMode"; const char* KrnlDebugLogFile = "KrnlDebugLogFile"; @@ -107,19 +117,22 @@ static struct { } sect_network_keys; static const char* section_controller_dinput = "controller-dinput"; -// All keys so far are dynamic -static struct { - const char* device_name = "DeviceName 0x%.02X"; - const char* object_name = "Object : \"%s\""; - const char* object_name_value = "%08X %08X %08X"; -} sect_controller_dinput_keys; - static const char* section_controller_port = "controller-port"; -// All keys so far are dynamic -static struct { - const char* xbox_port_x_host_type = "XboxPort%dHostType"; - const char* xbox_port_x_host_port = "XboxPort%dHostPort"; -} sect_controller_port_keys; + +static const char* section_input = "input-port-"; +static struct { + const char* type = "Type"; + const char* device = "DeviceName"; + const char* config = "ProfileName"; +} sect_input; + +static const char* section_input_profiles = "input-profile-"; +static struct { + const char* type = "Type"; + const char* config = "ProfileName"; + const char* device = "DeviceName"; + const char* control = "%s"; +} sect_input_profiles; static const char* section_hack = "hack"; static struct { @@ -336,7 +349,8 @@ bool Settings::LoadConfig() // ==== GUI End ============= // ==== Core Begin ========== - + + m_core.Revision = m_si.GetLongValue(section_core, sect_core_keys.Revision, 4); m_core.FlagsLLE = m_si.GetLongValue(section_core, sect_core_keys.FlagsLLE, /*Default=*/LLE_NONE); m_core.KrnlDebugMode = (DebugMode)m_si.GetLongValue(section_core, sect_core_keys.KrnlDebugMode, /*Default=*/DM_NONE); si_data = m_si.GetValue(section_core, sect_core_keys.KrnlDebugLogFile, /*Default=*/nullptr); @@ -445,66 +459,54 @@ bool Settings::LoadConfig() // ==== Network End ========= - // ==== Controller Begin ==== - - int v = 0; - char szKeyName[64]; - - // ****************************************************************** - // * Load Device Names - // ****************************************************************** - for (v = 0; v < XBCTRL_MAX_DEVICES; v++) { - std::sprintf(szKeyName, sect_controller_dinput_keys.device_name, v); - si_data = m_si.GetValue(section_controller_dinput, szKeyName, /*Default=*/nullptr); - - // Fallback to null string if value is empty or contain bigger string. - if (si_data == nullptr || std::strlen(si_data) >= MAX_PATH) { - // default is a null string - m_controller_dinput.DeviceName[v][0] = '\0'; - } - else { - trim_str = TrimQuoteFromString(si_data); - std::strncpy(m_controller_dinput.DeviceName[v], trim_str.c_str(), MAX_PATH); - } - } - - // ****************************************************************** - // * Load Object Configuration - // ****************************************************************** - for (v = 0; v, to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)> control_names; + for (int i = 0; i < dev_num_buttons[0]; i++) { + char control_name[30]; + std::sprintf(control_name, sect_input_profiles.control, button_xbox_ctrl_names[i][0]); + control_names[0].push_back(control_name); + } + // TODO: add the control names of the other devices + + index = 0; + while (true) { + std::string current_section = std::string(section_input_profiles) + std::to_string(index); + if (m_si.GetSectionSize(current_section.c_str()) == -1) { + break; + } + s_input_profiles local_profile; + local_profile.Type = m_si.GetLongValue(current_section.c_str(), sect_input_profiles.type); + local_profile.ProfileName = TrimQuoteFromString(m_si.GetValue(current_section.c_str(), sect_input_profiles.config)); + local_profile.DeviceName = m_si.GetValue(current_section.c_str(), sect_input_profiles.device); + for (int vec_control_index = 0; vec_control_index < dev_num_buttons[local_profile.Type]; vec_control_index++) { + local_profile.ControlList.push_back(m_si.GetValue(current_section.c_str(), + control_names[local_profile.Type][vec_control_index].c_str())); + } + m_input_profiles[local_profile.Type].push_back(std::move(local_profile)); + index++; } - // ==== Controller End ====== + // ==== Input Profile End ====== + + // Delete legacy configs from previous revisions + RemoveLegacyConfigs(m_core.Revision); + m_core.Revision = settings_version; return true; } @@ -536,7 +538,8 @@ bool Settings::Save(std::string file_path) // ==== GUI End ============= // ==== Core Begin ========== - + + m_si.SetLongValue(section_core, sect_core_keys.Revision, m_core.Revision, nullptr, false, true); m_si.SetLongValue(section_core, sect_core_keys.FlagsLLE, m_core.FlagsLLE, nullptr, true, true); m_si.SetLongValue(section_core, sect_core_keys.KrnlDebugMode, m_core.KrnlDebugMode, nullptr, true, true); m_si.SetValue(section_core, sect_core_keys.KrnlDebugLogFile, m_core.szKrnlDebug, nullptr, true); @@ -589,53 +592,63 @@ bool Settings::Save(std::string file_path) // ==== Network End ========= - // ==== Controller Begin ==== - - int v = 0; - char szKeyName[64]; + // ==== Input Begin ==== - // ****************************************************************** - // * Save Device Names - // ****************************************************************** - for (v = 0; v < XBCTRL_MAX_DEVICES; v++) { - std::sprintf(szKeyName, sect_controller_dinput_keys.device_name, v); - - if (m_controller_dinput.DeviceName[v][0] == 0) { - m_si.Delete(section_controller_dinput, szKeyName, true); - } - else { - quote_str = AppendQuoteToString(m_controller_dinput.DeviceName[v]); - m_si.SetValue(section_controller_dinput, szKeyName, quote_str.c_str(), nullptr, true); - } - } - - // ****************************************************************** - // * Save Object Configuration - // ****************************************************************** - for (v = 0; v, to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)> control_names; + for (int i = 0; i < dev_num_buttons[0]; i++) { + char control_name[30]; + std::sprintf(control_name, sect_input_profiles.control, button_xbox_ctrl_names[i][0]); + control_names[0].push_back(control_name); + } + // TODO: add the control names of the other devices + + int profile_num = 0; + for (int i = 0; i < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX); i++) { + size_t vec_size = m_input_profiles[i].size(); + if (vec_size == 0) { + continue; + } + for (unsigned int vec_index = 0; vec_index < vec_size; vec_index++, profile_num++) { + std::string current_section = std::string(section_input_profiles) + std::to_string(profile_num); + std::string quoted_prf_str = m_input_profiles[i][vec_index].ProfileName.insert(0, "\""); + quoted_prf_str += "\""; + m_si.SetLongValue(current_section.c_str(), sect_input_profiles.type, m_input_profiles[i][vec_index].Type, nullptr, false, true); + m_si.SetValue(current_section.c_str(), sect_input_profiles.config, quoted_prf_str.c_str(), nullptr, true); + m_si.SetValue(current_section.c_str(), sect_input_profiles.device, m_input_profiles[i][vec_index].DeviceName.c_str(), nullptr, true); + size_t vec_control_size = m_input_profiles[i][vec_index].ControlList.size(); + if (vec_control_size == 0) { + continue; + } + m_si.SetValue(current_section.c_str(), control_names[i][0].c_str(), m_input_profiles[i][vec_index].ControlList[0].c_str(), nullptr, true); + for (unsigned int vec_control_index = 1; vec_control_index < vec_control_size; vec_control_index++) { + m_si.SetValue(current_section.c_str(), control_names[i][vec_control_index].c_str(), + m_input_profiles[i][vec_index].ControlList[vec_control_index].c_str(), nullptr, true); + } + } + } + while (true) { + std::string current_section = std::string(section_input_profiles) + std::to_string(profile_num); + if (m_si.GetSectionSize(current_section.c_str()) == -1) { + break; + } + m_si.Delete(current_section.c_str(), nullptr, true); + profile_num++; } - // ==== Controller End ====== + // ==== Input Profile End ====== // ==== Hack Begin ========== @@ -681,9 +694,27 @@ void Settings::SyncToEmulator() // register Network settings g_EmuShared->SetNetworkSettings(&m_network); - // register Controller settings - g_EmuShared->SetControllerDInputSettings(&m_controller_dinput); - g_EmuShared->SetControllerPortSettings(&m_controller_port); + // register input settings + for (int i = 0; i < 4; i++) { + g_EmuShared->SetInputDevTypeSettings(&m_input[i].Type, i); + if (m_input[i].Type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { + g_EmuShared->SetInputDevNameSettings(m_input[i].DeviceName.c_str(), i); + auto it = std::find_if(m_input_profiles[m_input[i].Type].begin(), + m_input_profiles[m_input[i].Type].end(), [this, i](const auto& profile) { + if (profile.ProfileName == m_input[i].ProfileName) { + return true; + } + return false; + }); + if (it != m_input_profiles[m_input[i].Type].end()) { + char controls_name[XBOX_CTRL_NUM_BUTTONS][30]; + for (int index = 0; index < dev_num_buttons[m_input[i].Type]; index++) { + strncpy(controls_name[index], it->ControlList[index].c_str(), 30); + } + g_EmuShared->SetInputBindingsSettings(controls_name, XBOX_CTRL_NUM_BUTTONS, i); + } + } + } // register Hacks settings g_EmuShared->SetHackSettings(&m_hacks); @@ -773,25 +804,17 @@ std::string Settings::GetDataLocation() return m_current_data_location; } -// ****************************************************************** -// * Input Device Name Lookup Table -// ****************************************************************** -const char *Settings::s_controller_dinput::XboxControllerObjectNameLookup[XBCTRL_OBJECT_COUNT] = -{ - // ****************************************************************** - // * Analog Axis - // ****************************************************************** - "LThumbPosX", "LThumbNegX", "LThumbPosY", "LThumbNegY", - "RThumbPosX", "RThumbNegX", "RThumbPosY", "RThumbNegY", - - // ****************************************************************** - // * Analog Buttons - // ****************************************************************** - "A", "B", "X", "Y", "Black", "White", "LTrigger", "RTrigger", - - // ****************************************************************** - // * Digital Buttons - // ****************************************************************** - "DPadUp", "DPadDown", "DPadLeft", "DPadRight", - "Back", "Start", "LThumb", "RThumb" -}; +void Settings::RemoveLegacyConfigs(unsigned int CurrentRevision) +{ + switch (CurrentRevision) { + case 2: + case 3: + case 4: + m_si.Delete(section_controller_dinput, nullptr, true); + m_si.Delete(section_controller_port, nullptr, true); + break; + case 5: + default: + break; + } +} diff --git a/src/common/Settings.hpp b/src/common/Settings.hpp index 014159d65d..f46ac389af 100644 --- a/src/common/Settings.hpp +++ b/src/common/Settings.hpp @@ -18,7 +18,8 @@ // * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. // * // * (c) 2002-2003 Aaron Robinson -// * (c) 2017-2018 RadWolfie +// * (c) 2017-2018 RadWolfie +// * (c) 2019 ergo720 // * // * All rights reserved // * @@ -27,8 +28,11 @@ #define SETTINGS_HPP #include "Cxbx.h" -#include "SimpleIni.h" +#include "SimpleIni.h" +#include "input\InputDevice.h" +#include "common\util\CxbxUtil.h" #include +#include extern std::string g_exec_filepath; @@ -43,68 +47,7 @@ typedef enum _CXBX_DATA { CXBX_DATA_APPDATA = 0, CXBX_DATA_EXECDIR = 1, CXBX_DATA_CUSTOM = 2, -} CXBX_DATA; - -// ****************************************************************** -// * Xbox Controller Object IDs -// ****************************************************************** -enum XBCtrlObject -{ - // ****************************************************************** - // * Analog Axis - // ****************************************************************** - XBCTRL_OBJECT_LTHUMBPOSX = 0, - XBCTRL_OBJECT_LTHUMBNEGX, - XBCTRL_OBJECT_LTHUMBPOSY, - XBCTRL_OBJECT_LTHUMBNEGY, - XBCTRL_OBJECT_RTHUMBPOSX, - XBCTRL_OBJECT_RTHUMBNEGX, - XBCTRL_OBJECT_RTHUMBPOSY, - XBCTRL_OBJECT_RTHUMBNEGY, - // ****************************************************************** - // * Analog Buttons - // ****************************************************************** - XBCTRL_OBJECT_A, - XBCTRL_OBJECT_B, - XBCTRL_OBJECT_X, - XBCTRL_OBJECT_Y, - XBCTRL_OBJECT_BLACK, - XBCTRL_OBJECT_WHITE, - XBCTRL_OBJECT_LTRIGGER, - XBCTRL_OBJECT_RTRIGGER, - // ****************************************************************** - // * Digital Buttons - // ****************************************************************** - XBCTRL_OBJECT_DPADUP, - XBCTRL_OBJECT_DPADDOWN, - XBCTRL_OBJECT_DPADLEFT, - XBCTRL_OBJECT_DPADRIGHT, - XBCTRL_OBJECT_BACK, - XBCTRL_OBJECT_START, - XBCTRL_OBJECT_LTHUMB, - XBCTRL_OBJECT_RTHUMB, - // ****************************************************************** - // * Total number of components - // ****************************************************************** - XBCTRL_OBJECT_COUNT -}; - -// ****************************************************************** -// * Maximum number of devices allowed -// ****************************************************************** -#define XBCTRL_MAX_DEVICES XBCTRL_OBJECT_COUNT - -#define XBCTRL_MAX_GAMEPAD_PORTS 4 - -// ****************************************************************** -// * Xbox Controller Object Config -// ****************************************************************** -struct XBCtrlObjectCfg -{ - int dwDevice; // offset into m_InputDevice - int dwInfo; // extended information, depending on dwFlags - int dwFlags; // flags explaining the data format -}; +} CXBX_DATA; // ****************************************************************** // * Define number of integers required to store logging settings @@ -142,7 +85,8 @@ class Settings } m_gui; // Core settings - struct s_core { + struct s_core { + unsigned int Revision; unsigned int FlagsLLE; DebugMode KrnlDebugMode; char szKrnlDebug[MAX_PATH] = ""; @@ -179,35 +123,25 @@ class Settings int Reserved99[14] = { 0 }; } m_audio; + struct s_input { + int Type; + std::string DeviceName; + std::string ProfileName; + }; + std::array m_input; + + struct s_input_profiles { + int Type; + std::string ProfileName; + std::string DeviceName; + std::vector ControlList; + }; + std::array, to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)> m_input_profiles; + // Network settings struct s_network { char adapter_name[MAX_PATH] = ""; - } m_network; - - // Controller settings - struct s_controller_dinput { - - // ****************************************************************** - // * Input Device Name Lookup Table - // ****************************************************************** - static const char *XboxControllerObjectNameLookup[XBCTRL_OBJECT_COUNT]; - - // ****************************************************************** - // * Device Names - // ****************************************************************** - char DeviceName[XBCTRL_MAX_DEVICES][MAX_PATH]; - - // ****************************************************************** - // * Object Configuration - // ****************************************************************** - XBCtrlObjectCfg ObjectConfig[XBCTRL_OBJECT_COUNT]; - - } m_controller_dinput; - - struct s_controller_port { - unsigned int XboxPortMapHostType[XBCTRL_MAX_GAMEPAD_PORTS] = { 1, 1, 1, 1 }; - unsigned int XboxPortMapHostPort[XBCTRL_MAX_GAMEPAD_PORTS] = { 0, 1, 2, 3 }; - } m_controller_port; + } m_network; // Hack settings // NOTE: When removing fields, replace them with place-holders @@ -225,7 +159,8 @@ class Settings int Reserved99[8] = { 0 }; } m_hacks; -private: +private: + void RemoveLegacyConfigs(unsigned int CurrentRevision); std::string m_file_path = ""; CSimpleIniA m_si; std::string m_current_data_location; diff --git a/src/common/input/Button.cpp b/src/common/input/Button.cpp new file mode 100644 index 0000000000..c63181f198 --- /dev/null +++ b/src/common/input/Button.cpp @@ -0,0 +1,80 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +#include "Button.h" +#include "InputWindow.h" +#include "..\..\gui\ResCxbx.h" + + +void Button::EnableButton(bool enable) const +{ + EnableWindow(m_button_hwnd, enable); +} + +void Button::UpdateText(const char* text) const +{ + SendMessage(m_button_hwnd, WM_SETTEXT, 0, reinterpret_cast(text)); +} + +void Button::UpdateText() const // xinput specific +{ + SendMessage(m_button_hwnd, WM_SETTEXT, 0, reinterpret_cast(m_xinput_button.c_str())); +} + +void Button::ClearText() const +{ + SendMessage(m_button_hwnd, WM_SETTEXT, 0, reinterpret_cast("")); +} + +void Button::GetText(char* const text, size_t size) const +{ + SendMessage(m_button_hwnd, WM_GETTEXT, size, reinterpret_cast(text)); +} + +LRESULT CALLBACK ButtonSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +{ + switch (uMsg) + { + // Remove the window subclass when this window is destroyed + case WM_NCDESTROY: { + RemoveWindowSubclass(hWnd, ButtonSubclassProc, uIdSubclass); + } + break; + + case WM_RBUTTONDOWN: { + reinterpret_cast(dwRefData)->ClearText(); + g_InputWindow->UpdateProfile(std::string(), BUTTON_CLEAR); + if (reinterpret_cast(dwRefData)->GetId() == IDC_SET_MOTOR) { + g_InputWindow->UpdateProfile(std::string(), RUMBLE_CLEAR); + } + } + break; + + } + + return DefSubclassProc(hWnd, uMsg, wParam, lParam); +} diff --git a/src/common/input/Button.h b/src/common/input/Button.h new file mode 100644 index 0000000000..698e6afbda --- /dev/null +++ b/src/common/input/Button.h @@ -0,0 +1,61 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +#pragma once + +#include "windows.h" +#include +#include + +#define XBOX_CTRL_NUM_BUTTONS 25 + + +/* Represents the gui buttons of the xbox device currently being configured */ +class Button +{ +public: + Button(const char* name, const char* xname, int id, int index, HWND hwnd) : m_name(name), + m_xinput_button(xname), m_id(id), m_index(index), m_button_hwnd(GetDlgItem(hwnd, m_id)) {}; + void EnableButton(bool enable) const; + void UpdateText(const char* text) const; + void UpdateText() const; + void ClearText() const; + void GetText(char* const text, size_t size) const; + std::string GetName() const { return m_name; } + int GetId() const { return m_id; } + int GetIndex() const { return m_index; } + + +private: + std::string m_name; + std::string m_xinput_button; + int m_id; + int m_index; + HWND m_button_hwnd; +}; + +LRESULT CALLBACK ButtonSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); diff --git a/src/common/input/DInputKeyboardCodes.h b/src/common/input/DInputKeyboardCodes.h new file mode 100644 index 0000000000..55978a12e2 --- /dev/null +++ b/src/common/input/DInputKeyboardCodes.h @@ -0,0 +1,312 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +#pragma once + +{DIK_A, "A"}, { DIK_B, "B" }, { DIK_C, "C" }, { DIK_D, "D" }, { DIK_E, "E" }, { DIK_F, "F" }, { DIK_G, "G" }, +{ DIK_H, "H" }, { DIK_I, "I" }, { DIK_J, "J" }, { DIK_K, "K" }, { DIK_L, "L" }, { DIK_M, "M" }, +{ DIK_N, "N" }, { DIK_O, "O" }, { DIK_P, "P" }, { DIK_Q, "Q" }, { DIK_R, "R" }, { DIK_S, "S" }, +{ DIK_T, "T" }, { DIK_U, "U" }, { DIK_V, "V" }, { DIK_W, "W" }, { DIK_X, "X" }, { DIK_Y, "Y" }, +{ DIK_Z, "Z" }, { DIK_0, "0" }, { DIK_1, "1" }, { DIK_2, "2" }, { DIK_3, "3" }, { DIK_4, "4" }, +{ DIK_5, "5" }, { DIK_6, "6" }, { DIK_7, "7" }, { DIK_8, "8" }, { DIK_9, "9" }, { DIK_UP, "UP" }, +{ DIK_DOWN, "DOWN" }, { DIK_LEFT, "LEFT" }, { DIK_RIGHT, "RIGHT" }, { DIK_ABNT_C1, "ABNT_C1" }, +{ DIK_ABNT_C2, "ABNT_C2" }, { DIK_ADD, "ADD" }, { DIK_APOSTROPHE, "APOSTROPHE" }, { DIK_APPS, "APPS" }, +{ DIK_AT, "AT" }, { DIK_AX, "AX" }, { DIK_BACK, "BACK" }, { DIK_BACKSLASH, "BACKSLASH" }, +{ DIK_CALCULATOR, "CALCULATOR" }, { DIK_CAPITAL, "CAPITAL" }, { DIK_COLON, "COLON" }, +{ DIK_COMMA, "COMMA" }, { DIK_CONVERT, "CONVERT" }, { DIK_DECIMAL, "DECIMAL" }, +{ DIK_DELETE, "DELETE" }, { DIK_DIVIDE, "DIVIDE" }, { DIK_EQUALS, "EQUALS" }, { DIK_ESCAPE, "ESCAPE" }, +{ DIK_F1, "F1" }, { DIK_F2, "F2" }, { DIK_F3, "F3" }, { DIK_F4, "F4" }, { DIK_F5, "F5" }, { DIK_F6, "F6" }, +{ DIK_F7, "F7" }, { DIK_F8, "F8" }, { DIK_F9, "F9" }, { DIK_F10, "F10" }, { DIK_F11, "F11" }, +{ DIK_F12, "F12" }, { DIK_F13, "F13" }, { DIK_F14, "F14" }, { DIK_F15, "F15" }, { DIK_GRAVE, "GRAVE" }, +{ DIK_HOME, "HOME" }, { DIK_END, "END" }, { DIK_INSERT, "INSERT" }, { DIK_KANA, "KANA" }, +{ DIK_KANJI, "KANJI" }, { DIK_MAIL, "MAIL" }, { DIK_MEDIASELECT, "MEDIASELECT" }, +{ DIK_MEDIASTOP, "MEDIASTOP" }, { DIK_MINUS, "MINUS" }, { DIK_MULTIPLY, "MULTIPLY" }, +{ DIK_MUTE, "MUTE" }, { DIK_MYCOMPUTER, "MYCOMPUTER" }, { DIK_NEXTTRACK, "NEXTTRACK" }, +{ DIK_NOCONVERT, "NOCONVERT" }, { DIK_NUMLOCK, "NUMLOCK" }, { DIK_NUMPAD0, "NUMPAD0" }, +{ DIK_NUMPAD1, "NUMPAD1" }, { DIK_NUMPAD2, "NUMPAD2" }, { DIK_NUMPAD3, "NUMPAD3" }, +{ DIK_NUMPAD4, "NUMPAD4" }, { DIK_NUMPAD5, "NUMPAD5" }, { DIK_NUMPAD6, "NUMPAD6" }, +{ DIK_NUMPAD7, "NUMPAD7" }, { DIK_NUMPAD8, "NUMPAD8" }, { DIK_NUMPAD9, "NUMPAD9" }, +{ DIK_NUMPADCOMMA, "NUMPADCOMMA" }, { DIK_NUMPADENTER, "NUMPADENTER" }, +{ DIK_NUMPADEQUALS, "NUMPADEQUALS" }, { DIK_OEM_102, "OEM_102" }, { DIK_PAUSE, "PAUSE" }, +{ DIK_PERIOD, "PERIOD" }, { DIK_PLAYPAUSE, "PLAYPAUSE" }, { DIK_POWER, "POWER" }, +{ DIK_PREVTRACK, "PREVTRACK" }, { DIK_PRIOR, "PRIOR" }, { DIK_NEXT, "NEXT" }, { DIK_RETURN, "RETURN" }, +{ DIK_LBRACKET, "LBRACKET" }, { DIK_RBRACKET, "RBRACKET" }, { DIK_LCONTROL, "LCONTROL" }, +{ DIK_RCONTROL, "RCONTROL" }, { DIK_LMENU, "LMENU" }, { DIK_RMENU, "RMENU" }, { DIK_LSHIFT, "LSHIFT" }, +{ DIK_RSHIFT, "RSHIFT" }, { DIK_LWIN, "LWIN" }, { DIK_RWIN, "RWIN" }, { DIK_SCROLL, "SCROLL" }, +{ DIK_SEMICOLON, "SEMICOLON" }, { DIK_SLASH, "SLASH" }, { DIK_SLEEP, "SLEEP" }, { DIK_SPACE, "SPACE" }, +{ DIK_STOP, "STOP" }, { DIK_SUBTRACT, "SUBTRACT" }, { DIK_SYSRQ, "SYSRQ" }, { DIK_TAB, "TAB" }, +{ DIK_UNDERLINE, "UNDERLINE" }, { DIK_UNLABELED, "UNLABELED" }, { DIK_VOLUMEDOWN, "VOLUMEDOWN" }, +{ DIK_VOLUMEUP, "VOLUMEUP" }, { DIK_WAKE, "WAKE" }, { DIK_WEBBACK, "WEBBACK" }, +{ DIK_WEBFAVORITES, "WEBFAVORITES" }, { DIK_WEBFORWARD, "WEBFORWARD" }, { DIK_WEBHOME, "WEBHOME" }, +{ DIK_WEBREFRESH, "WEBREFRESH" }, { DIK_WEBSEARCH, "WEBSEARCH" }, { DIK_WEBSTOP, "WEBSTOP" }, +{ DIK_YEN, "YEN" }, + +// Sdl keyboard key codes I have prepared when, in the future, we'll use sdl to handle the keyboard +/* +{ "0", SDL_SCANCODE_0 }, +{ "1", SDL_SCANCODE_1 }, +{ "2", SDL_SCANCODE_2 }, +{ "3", SDL_SCANCODE_3 }, +{ "4", SDL_SCANCODE_4 }, +{ "5", SDL_SCANCODE_5 }, +{ "6", SDL_SCANCODE_6 }, +{ "7", SDL_SCANCODE_7 }, +{ "8", SDL_SCANCODE_8 }, +{ "9", SDL_SCANCODE_9 }, +{ "A", SDL_SCANCODE_A }, +{ "AC Back", SDL_SCANCODE_AC_BACK }, +{ "AC Bookmarks", SDL_SCANCODE_AC_BOOKMARKS }, +{ "AC Forward", SDL_SCANCODE_AC_FORWARD }, +{ "AC Home", SDL_SCANCODE_AC_HOME }, +{ "AC Refresh", SDL_SCANCODE_AC_REFRESH }, +{ "AC Search", SDL_SCANCODE_AC_SEARCH }, +{ "AC Stop", SDL_SCANCODE_AC_STOP }, +{ "Again", SDL_SCANCODE_AGAIN }, +{ "AltErase", SDL_SCANCODE_ALTERASE }, +{ "'", SDL_SCANCODE_APOSTROPHE }, +{ "Application", SDL_SCANCODE_APPLICATION }, +{ "AudioMute", SDL_SCANCODE_AUDIOMUTE }, +{ "AudioNext", SDL_SCANCODE_AUDIONEXT }, +{ "AudioPlay", SDL_SCANCODE_AUDIOPLAY }, +{ "AudioPrev", SDL_SCANCODE_AUDIOPREV }, +{ "AudioStop", SDL_SCANCODE_AUDIOSTOP }, +{ "B", SDL_SCANCODE_B }, +{ "\\", SDL_SCANCODE_BACKSLASH }, +{ "Backspace", SDL_SCANCODE_BACKSPACE }, +{ "BrightnessDown", SDL_SCANCODE_BRIGHTNESSDOWN }, +{ "BrightnessUp", SDL_SCANCODE_BRIGHTNESSUP }, +{ "C", SDL_SCANCODE_C }, +{ "Calculator", SDL_SCANCODE_CALCULATOR }, +{ "Cancel", SDL_SCANCODE_CANCEL }, +{ "CapsLock", SDL_SCANCODE_CAPSLOCK }, +{ "Clear", SDL_SCANCODE_CLEAR }, +{ "ClearAgain", SDL_SCANCODE_CLEARAGAIN }, +{ ",", SDL_SCANCODE_COMMA }, +{ "Computer", SDL_SCANCODE_COMPUTER }, +{ "Copy", SDL_SCANCODE_COPY }, +{ "CrSel", SDL_SCANCODE_CRSEL }, +{ "MoneySubUnit", SDL_SCANCODE_CURRENCYSUBUNIT }, +{ "MoneyUnit", SDL_SCANCODE_CURRENCYUNIT }, +{ "Cut", SDL_SCANCODE_CUT }, +{ "D", SDL_SCANCODE_D }, +{ "DecimalSep", SDL_SCANCODE_DECIMALSEPARATOR }, +{ "Delete", SDL_SCANCODE_DELETE }, +{ "DisplaySwitch", SDL_SCANCODE_DISPLAYSWITCH }, +{ "Down", SDL_SCANCODE_DOWN }, +{ "E", SDL_SCANCODE_E }, +{ "Eject", SDL_SCANCODE_EJECT }, +{ "End", SDL_SCANCODE_END }, +{ "=", SDL_SCANCODE_EQUALS }, +{ "Escape", SDL_SCANCODE_ESCAPE }, +{ "Execute", SDL_SCANCODE_EXECUTE }, +{ "ExSel", SDL_SCANCODE_EXSEL }, +{ "F", SDL_SCANCODE_F }, +{ "F1", SDL_SCANCODE_F1 }, +{ "F10", SDL_SCANCODE_F10 }, +{ "F11", SDL_SCANCODE_F11 }, +{ "F12", SDL_SCANCODE_F12 }, +{ "F13", SDL_SCANCODE_F13 }, +{ "F14", SDL_SCANCODE_F14 }, +{ "F15", SDL_SCANCODE_F15 }, +{ "F16", SDL_SCANCODE_F16 }, +{ "F17", SDL_SCANCODE_F17 }, +{ "F18", SDL_SCANCODE_F18 }, +{ "F19", SDL_SCANCODE_F19 }, +{ "F2", SDL_SCANCODE_F2 }, +{ "F20", SDL_SCANCODE_F20 }, +{ "F21", SDL_SCANCODE_F21 }, +{ "F22", SDL_SCANCODE_F22 }, +{ "F23", SDL_SCANCODE_F23 }, +{ "F24", SDL_SCANCODE_F24 }, +{ "F3", SDL_SCANCODE_F3 }, +{ "F4", SDL_SCANCODE_F4 }, +{ "F5", SDL_SCANCODE_F5 }, +{ "F6", SDL_SCANCODE_F6 }, +{ "F7", SDL_SCANCODE_F7 }, +{ "F8", SDL_SCANCODE_F8 }, +{ "F9", SDL_SCANCODE_F9 }, +{ "Find", SDL_SCANCODE_FIND }, +{ "G", SDL_SCANCODE_G }, +{ "`", SDL_SCANCODE_GRAVE }, +{ "H", SDL_SCANCODE_H }, +{ "Help", SDL_SCANCODE_HELP }, +{ "Home", SDL_SCANCODE_HOME }, +{ "I", SDL_SCANCODE_I }, +{ "Insert", SDL_SCANCODE_INSERT }, +{ "J", SDL_SCANCODE_J }, +{ "K", SDL_SCANCODE_K }, +{ "KBDIllumDown", SDL_SCANCODE_KBDILLUMDOWN }, +{ "KBDIllumToggle", SDL_SCANCODE_KBDILLUMTOGGLE }, +{ "KBDIllumUp", SDL_SCANCODE_KBDILLUMUP }, +{ "KP 0", SDL_SCANCODE_KP_0 }, +{ "KP 00", SDL_SCANCODE_KP_00 }, +{ "KP 000", SDL_SCANCODE_KP_000 }, +{ "KP 1", SDL_SCANCODE_KP_1 }, +{ "KP 2", SDL_SCANCODE_KP_2 }, +{ "KP 3", SDL_SCANCODE_KP_3 }, +{ "KP 4", SDL_SCANCODE_KP_4 }, +{ "KP 5", SDL_SCANCODE_KP_5 }, +{ "KP 6", SDL_SCANCODE_KP_6 }, +{ "KP 7", SDL_SCANCODE_KP_7 }, +{ "KP 8", SDL_SCANCODE_KP_8 }, +{ "KP 9", SDL_SCANCODE_KP_9 }, +{ "KP A", SDL_SCANCODE_KP_A }, +{ "KP &", SDL_SCANCODE_KP_AMPERSAND }, +{ "KP @", SDL_SCANCODE_KP_AT }, +{ "KP B", SDL_SCANCODE_KP_B }, +{ "KP Backspace", SDL_SCANCODE_KP_BACKSPACE }, +{ "KP Binary", SDL_SCANCODE_KP_BINARY }, +{ "KP C", SDL_SCANCODE_KP_C }, +{ "KP Clear", SDL_SCANCODE_KP_CLEAR }, +{ "KP ClearEntry", SDL_SCANCODE_KP_CLEARENTRY }, +{ "KP :", SDL_SCANCODE_KP_COLON }, +{ "KP ,", SDL_SCANCODE_KP_COMMA }, +{ "KP D", SDL_SCANCODE_KP_D }, +{ "KP &&", SDL_SCANCODE_KP_DBLAMPERSAND }, +{ "KP ||", SDL_SCANCODE_KP_DBLVERTICALBAR }, +{ "KP Decimal", SDL_SCANCODE_KP_DECIMAL }, +{ "KP /", SDL_SCANCODE_KP_DIVIDE }, +{ "KP E", SDL_SCANCODE_KP_E }, +{ "KP Enter", SDL_SCANCODE_KP_ENTER }, +{ "KP =",SDL_SCANCODE_KP_EQUALS }, +{ "KP = (AS400)", SDL_SCANCODE_KP_EQUALSAS400 }, +{ "KP !", SDL_SCANCODE_KP_EXCLAM }, +{ "KP F", SDL_SCANCODE_KP_F }, +{ "KP >", SDL_SCANCODE_KP_GREATER }, +{ "KP #", SDL_SCANCODE_KP_HASH }, +{ "KP Hex", SDL_SCANCODE_KP_HEXADECIMAL }, +{ "KP {", SDL_SCANCODE_KP_LEFTBRACE }, +{ "KP (", SDL_SCANCODE_KP_LEFTPAREN }, +{ "KP <", SDL_SCANCODE_KP_LESS }, +{ "KP Add", SDL_SCANCODE_KP_MEMADD }, +{ "KP Clear", SDL_SCANCODE_KP_MEMCLEAR }, +{ "KP Divide", SDL_SCANCODE_KP_MEMDIVIDE }, +{ "KP Multiply", SDL_SCANCODE_KP_MEMMULTIPLY }, +{ "KP Recall", SDL_SCANCODE_KP_MEMRECALL }, +{ "KP Store", SDL_SCANCODE_KP_MEMSTORE }, +{ "KP Subtract", SDL_SCANCODE_KP_MEMSUBTRACT }, +{ "KP -", SDL_SCANCODE_KP_MINUS }, +{ "KP *", SDL_SCANCODE_KP_MULTIPLY }, +{ "KP Octal", SDL_SCANCODE_KP_OCTAL }, +{ "KP %", SDL_SCANCODE_KP_PERCENT }, +{ "KP .", SDL_SCANCODE_KP_PERIOD }, +{ "KP +", SDL_SCANCODE_KP_PLUS }, +{ "KP +/-", SDL_SCANCODE_KP_PLUSMINUS }, +{ "KP ^", SDL_SCANCODE_KP_POWER }, +{ "KP }", SDL_SCANCODE_KP_RIGHTBRACE }, +{ "KP )", SDL_SCANCODE_KP_RIGHTPAREN }, +{ "KP Space", SDL_SCANCODE_KP_SPACE }, +{ "KP Tab", SDL_SCANCODE_KP_TAB }, +{ "KP |", SDL_SCANCODE_KP_VERTICALBAR }, +{ "KP XOR", SDL_SCANCODE_KP_XOR }, +{ "L", SDL_SCANCODE_L }, +{ "Left Alt", SDL_SCANCODE_LALT }, +{ "Left Ctrl", SDL_SCANCODE_LCTRL }, +{ "Left", SDL_SCANCODE_LEFT }, +{ "[", SDL_SCANCODE_LEFTBRACKET }, +{ "Left GUI", SDL_SCANCODE_LGUI }, +{ "Left Shift", SDL_SCANCODE_LSHIFT }, +{ "M", SDL_SCANCODE_M }, +{ "Mail", SDL_SCANCODE_MAIL }, +{ "MediaSelect", SDL_SCANCODE_MEDIASELECT }, +{ "Menu", SDL_SCANCODE_MENU }, +{ "-", SDL_SCANCODE_MINUS }, +{ "ModeSwitch", SDL_SCANCODE_MODE }, +{ "Mute", SDL_SCANCODE_MUTE }, +{ "N", SDL_SCANCODE_N }, +{ "Numlock", SDL_SCANCODE_NUMLOCKCLEAR }, +{ "O", SDL_SCANCODE_O }, +{ "Oper", SDL_SCANCODE_OPER }, +{ "Out", SDL_SCANCODE_OUT }, +{ "P", SDL_SCANCODE_P }, +{ "PageDown", SDL_SCANCODE_PAGEDOWN }, +{ "PageUp", SDL_SCANCODE_PAGEUP }, +{ "Paste", SDL_SCANCODE_PASTE }, +{ "Pause", SDL_SCANCODE_PAUSE }, +{ ".", SDL_SCANCODE_PERIOD }, +{ "Power", SDL_SCANCODE_POWER }, +{ "PrintScreen", SDL_SCANCODE_PRINTSCREEN }, +{ "Prior", SDL_SCANCODE_PRIOR }, +{ "Q", SDL_SCANCODE_Q }, +{ "R", SDL_SCANCODE_R }, +{ "Right Alt", SDL_SCANCODE_RALT }, +{ "Right Ctrl", SDL_SCANCODE_RCTRL }, +{ "Return", SDL_SCANCODE_RETURN }, +{ "Return", SDL_SCANCODE_RETURN2 }, +{ "Right GUI", SDL_SCANCODE_RGUI }, +{ "Right", SDL_SCANCODE_RIGHT }, +{ "]", SDL_SCANCODE_RIGHTBRACKET }, +{ "Right Shift", SDL_SCANCODE_RSHIFT }, +{ "S", SDL_SCANCODE_S }, +{ "ScrollLock", SDL_SCANCODE_SCROLLLOCK }, +{ "Select", SDL_SCANCODE_SELECT }, +{ ";", SDL_SCANCODE_SEMICOLON }, +{ "Separator", SDL_SCANCODE_SEPARATOR }, +{ "/", SDL_SCANCODE_SLASH }, +{ "Sleep", SDL_SCANCODE_SLEEP }, +{ "Space", SDL_SCANCODE_SPACE }, +{ "Stop", SDL_SCANCODE_STOP }, +{ "SysReq", SDL_SCANCODE_SYSREQ }, +{ "T", SDL_SCANCODE_T }, +{ "Tab", SDL_SCANCODE_TAB }, +{ "ThousandsSep", SDL_SCANCODE_THOUSANDSSEPARATOR }, +{ "U", SDL_SCANCODE_U }, +{ "Undo", SDL_SCANCODE_UNDO }, +{ "", SDL_SCANCODE_UNKNOWN }, +{ "Up", SDL_SCANCODE_UP }, +{ "V", SDL_SCANCODE_V }, +{ "VolumeDown", SDL_SCANCODE_VOLUMEDOWN }, +{ "VolumeUp", SDL_SCANCODE_VOLUMEUP }, +{ "W", SDL_SCANCODE_W }, +{ "WWW", SDL_SCANCODE_WWW }, +{ "X", SDL_SCANCODE_X }, +{ "Y", SDL_SCANCODE_Y }, +{ "Z", SDL_SCANCODE_Z }, +{ "International1", SDL_SCANCODE_INTERNATIONAL1 }, +{ "International2", SDL_SCANCODE_INTERNATIONAL2 }, +{ "International3", SDL_SCANCODE_INTERNATIONAL3 }, +{ "International4", SDL_SCANCODE_INTERNATIONAL4 }, +{ "International5", SDL_SCANCODE_INTERNATIONAL5 }, +{ "International6", SDL_SCANCODE_INTERNATIONAL6 }, +{ "International7", SDL_SCANCODE_INTERNATIONAL7 }, +{ "International8", SDL_SCANCODE_INTERNATIONAL8 }, +{ "International9", SDL_SCANCODE_INTERNATIONAL9 }, +{ "Lang1", SDL_SCANCODE_LANG1 }, +{ "Lang2", SDL_SCANCODE_LANG2 }, +{ "Lang3", SDL_SCANCODE_LANG3 }, +{ "Lang4", SDL_SCANCODE_LANG4 }, +{ "Lang5", SDL_SCANCODE_LANG5 }, +{ "Lang6", SDL_SCANCODE_LANG6 }, +{ "Lang7", SDL_SCANCODE_LANG7 }, +{ "Lang8", SDL_SCANCODE_LANG8 }, +{ "Lang9", SDL_SCANCODE_LANG9 }, +//{ "Caps Lk", SDL_SCANCODE_LOCKINGCAPSLOCK }, +//{ "Num Lk", SDL_SCANCODE_LOCKINGNUMLOCK }, +//{ "Scr Lk", SDL_SCANCODE_LOCKINGSCROLLLOCK }, +{ "NonUsBacklash", SDL_SCANCODE_NONUSBACKSLASH }, +{ "NonUsHash", SDL_SCANCODE_NONUSHASH }, +*/ diff --git a/src/common/input/DInputKeyboardMouse.cpp b/src/common/input/DInputKeyboardMouse.cpp new file mode 100644 index 0000000000..15debc8afe --- /dev/null +++ b/src/common/input/DInputKeyboardMouse.cpp @@ -0,0 +1,262 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +// Copyright 2010 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file of Dolphin at https://github.com/dolphin-emu/dolphin/blob/master/license.txt. + +// Derived from DInputKeyboardMouse.cpp of Dolphin emulator +// https://github.com/dolphin-emu/dolphin + +#define LOG_PREFIX CXBXR_MODULE::DINP + +#include "DInputKeyboardMouse.h" +#include "InputManager.h" +#include "core\kernel\support\Emu.h" + +// Unfortunately, sdl doesn't seem to be able to capture keyboard/mouse input from windows it didn't create (we currently use +// win32 for that). So unless we create sdl windows, we will have to keep dinput around to handle keyboard/mouse input. + +namespace DInput +{ + static const struct kb_keys { + const uint8_t code; + const char* const name; + } + named_keys[] = { +#include "DInputKeyboardCodes.h" + }; + + bool bKbMoEnumerated = false; + + void InitKeyboardMouse(IDirectInput8* idi8) + { + // From Dolphin: "mouse and keyboard are a combined device, to allow shift+click and stuff + // if that's dumb, I will make a VirtualDevice class that just uses ranges of inputs/outputs from + // other devices so there can be a separated Keyboard and mouse, as well as combined KeyboardMouse" + + LPDIRECTINPUTDEVICE8 kb_device = nullptr; + //LPDIRECTINPUTDEVICE8 mo_device = nullptr; + + if (SUCCEEDED(idi8->CreateDevice(GUID_SysKeyboard, &kb_device, nullptr)) && + SUCCEEDED(kb_device->SetDataFormat(&c_dfDIKeyboard)) && + SUCCEEDED(kb_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) //&& + //SUCCEEDED(idi8->CreateDevice(GUID_SysMouse, &mo_device, nullptr)) && + //SUCCEEDED(mo_device->SetDataFormat(&c_dfDIMouse2)) && + //SUCCEEDED(mo_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) + { + g_InputDeviceManager.AddDevice(std::make_shared(kb_device)); + bKbMoEnumerated = true; + return; + } + + if (kb_device) + kb_device->Release(); +#if 0 + if (mo_device) + mo_device->Release(); +#endif + } + + void PopulateDevices() + { + bKbMoEnumerated = false; + IDirectInput8* idi8; + if (FAILED(DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, + (LPVOID*)& idi8, nullptr))) + { + return; + } + + InitKeyboardMouse(idi8); + idi8->Release(); + } + + void GetDeviceChanges() + { + if (bKbMoEnumerated) { + return; + } + PopulateDevices(); + } + + KeyboardMouse::KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device) + : m_kb_device(kb_device)//, m_mo_device(mo_device) + { + m_kb_device->Acquire(); + //m_mo_device->Acquire(); + + memset(&m_state_in, 0, sizeof(m_state_in)); + + // KEYBOARD + // add keys + for (uint8_t i = 0; i < sizeof(named_keys) / sizeof(*named_keys); ++i) { + AddInput(new Key(i, m_state_in.keyboard[named_keys[i].code])); + } +#if 0 + // MOUSE + // get caps + DIDEVCAPS mouse_caps; + memset(&mouse_caps, 0, sizeof(mouse_caps)); + mouse_caps.dwSize = sizeof(mouse_caps); + m_mo_device->GetCapabilities(&mouse_caps); + // mouse buttons + for (unsigned char i = 0; i < mouse_caps.dwButtons; ++i) { + AddInput(new Button(i, m_state_in.mouse.rgbButtons[i])); + } + + // cursor, with a hax for-loop + for (unsigned int i = 0; i < 4; ++i) { + AddInput(new Cursor(!!(i & 2), (&m_state_in.cursor.x)[i / 2], !!(i & 1))); + } +#endif + } + + KeyboardMouse::~KeyboardMouse() + { + // kb + m_kb_device->Unacquire(); + m_kb_device->Release(); +#if 0 + // mouse + m_mo_device->Unacquire(); + m_mo_device->Release(); +#endif + } + + void GetMousePos(ControlState* const x, ControlState* const y) + { + POINT point = { 1, 1 }; + GetCursorPos(&point); + // Get the cursor position relative to the upper left corner of the current window + HWND hwnd = WindowFromPoint(point); + DWORD processId; + GetWindowThreadProcessId(hwnd, &processId); + if (processId == GetCurrentProcessId()) + { + ScreenToClient(hwnd, &point); + + // Get the size of the current window. + RECT rect; + GetClientRect(hwnd, &rect); + // Width and height is the size of the rendering window + unsigned int win_width = rect.right - rect.left; + unsigned int win_height = rect.bottom - rect.top; + + // Return the mouse position as a range from -1 to 1 + *x = (ControlState)point.x / (ControlState)win_width * 2 - 1; + *y = (ControlState)point.y / (ControlState)win_height * 2 - 1; + } + else + { + *x = (ControlState)0; + *y = (ControlState)0; + } + } + + bool KeyboardMouse::UpdateInput() + { + // Update keyboard and mouse button states + HRESULT kb_hr = m_kb_device->GetDeviceState(sizeof(m_state_in.keyboard), &m_state_in.keyboard); + //HRESULT mo_hr = m_mo_device->GetDeviceState(sizeof(m_state_in.mouse), &m_state_in.mouse); + + if (DIERR_INPUTLOST == kb_hr || DIERR_NOTACQUIRED == kb_hr) { + m_kb_device->Acquire(); + } +#if 0 + if (DIERR_INPUTLOST == mo_hr || DIERR_NOTACQUIRED == mo_hr) { + m_mo_device->Acquire(); + } +#endif + if (SUCCEEDED(kb_hr)) //&& SUCCEEDED(mo_hr)) + { +#if 0 + ControlState temp_x, temp_y; + + // Update absolute mouse position + GetMousePos(&m_state_in.cursor.x, &m_state_in.cursor.y); + + // Save current absolute mouse position + temp_x = m_state_in.cursor.x; + temp_y = m_state_in.cursor.y; + + // Update relative mouse motion + m_state_in.cursor.x -= m_state_in.cursor.last_x; + m_state_in.cursor.y -= m_state_in.cursor.last_y; + + // Update previous absolute mouse position + m_state_in.cursor.last_x = temp_x; + m_state_in.cursor.last_y = temp_y; +#endif + return true; + } + return false; + } + + std::string KeyboardMouse::GetDeviceName() const + { + return "Keyboard"; + } + + std::string KeyboardMouse::GetAPI() const + { + return "DInput"; + } + + std::string KeyboardMouse::Key::GetName() const + { + return named_keys[m_index].name; + } + + std::string KeyboardMouse::Button::GetName() const + { + return std::string("Click ") + char('0' + m_index); + } + + std::string KeyboardMouse::Cursor::GetName() const + { + static char tmpstr[] = "Cursor .."; + tmpstr[7] = (char)('X' + m_index); + tmpstr[8] = (m_positive ? '+' : '-'); + return tmpstr; + } + + ControlState KeyboardMouse::Key::GetState() const + { + return (m_key != 0); + } + + ControlState KeyboardMouse::Button::GetState() const + { + return (m_button != 0); + } + + ControlState KeyboardMouse::Cursor::GetState() const + { + return std::max(0.0, ControlState(m_axis) / (m_positive ? 1.0 : -1.0)); + } +} diff --git a/src/common/input/DInputKeyboardMouse.h b/src/common/input/DInputKeyboardMouse.h new file mode 100644 index 0000000000..302e826709 --- /dev/null +++ b/src/common/input/DInputKeyboardMouse.h @@ -0,0 +1,105 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +#pragma once + +#include "InputDevice.h" +#define DIRECTINPUT_VERSION 0x0800 +#include "dinput.h" + + +namespace DInput +{ + extern bool bKbMoEnumerated; + void GetDeviceChanges(); + void PopulateDevices(); + + class KeyboardMouse : public InputDevice + { + public: + KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device); + ~KeyboardMouse(); + std::string GetDeviceName() const override; + std::string GetAPI() const override; + bool UpdateInput() override; + + + private: + class Key : public Input + { + public: + Key(uint8_t index, const BYTE& key) : m_index(index), m_key(key) {} + std::string GetName() const override; + ControlState GetState() const override; + + private: + const BYTE& m_key; + const uint8_t m_index; + }; + + class Button : public Input + { + public: + Button(uint8_t index, const BYTE& button) : m_button(button), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; + + private: + const BYTE& m_button; + const uint8_t m_index; + }; + + class Cursor : public Input + { + public: + Cursor(uint8_t index, const ControlState& axis, const bool positive) + : m_axis(axis), m_index(index), m_positive(positive) {} + std::string GetName() const override; + bool IsDetectable() override { return true; } + ControlState GetState() const override; + + private: + const ControlState& m_axis; + const uint8_t m_index; + const bool m_positive; + }; + + struct State + { + BYTE keyboard[256]; + DIMOUSESTATE2 mouse; + struct + { + ControlState x, y, last_x, last_y; + } cursor; + }; + + const LPDIRECTINPUTDEVICE8 m_kb_device; + //const LPDIRECTINPUTDEVICE8 m_mo_device; + State m_state_in; + }; +} diff --git a/src/common/input/EmuDevice.cpp b/src/common/input/EmuDevice.cpp new file mode 100644 index 0000000000..454adfae1c --- /dev/null +++ b/src/common/input/EmuDevice.cpp @@ -0,0 +1,146 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +#include"Button.h" +#include "InputManager.h" +#include "..\..\gui\ResCxbx.h" + +static int button_xbox_ctrl_id[XBOX_CTRL_NUM_BUTTONS] = { + IDC_SET_DPAD_UP, + IDC_SET_DPAD_DOWN, + IDC_SET_DPAD_LEFT, + IDC_SET_DPAD_RIGHT, + IDC_SET_START, + IDC_SET_BACK, + IDC_SET_LTHUMB, + IDC_SET_RTHUMB, + IDC_SET_A, + IDC_SET_B, + IDC_SET_X, + IDC_SET_Y, + IDC_SET_BLACK, + IDC_SET_WHITE, + IDC_SET_LTRIGGER, + IDC_SET_RTRIGGER, + IDC_SET_LEFT_POSX, + IDC_SET_LEFT_NEGX, + IDC_SET_LEFT_POSY, + IDC_SET_LEFT_NEGY, + IDC_SET_RIGHT_POSX, + IDC_SET_RIGHT_NEGX, + IDC_SET_RIGHT_POSY, + IDC_SET_RIGHT_NEGY, + IDC_SET_MOTOR, +}; + +const char* button_xbox_ctrl_names[XBOX_CTRL_NUM_BUTTONS][2] = { + "D Pad Up", "Pad N", + "D Pad Down", "Pad S", + "D Pad Left", "Pad W", + "D Pad Right", "Pad E", + "Start", "Start", + "Back", "Back", + "L Thumb", "Thumb L", + "R Thumb", "Thumb R", + "A", "Button A", + "B", "Button B", + "X", "Button X", + "Y", "Button Y", + "Black", "Shoulder R", + "White", "Shoulder L", + "L Trigger", "Trigger L", + "R Trigger", "Trigger R", + "Left Axis X+", "Left X+", + "Left Axis X-", "Left X-", + "Left Axis Y+", "Left Y+", + "Left Axis Y-", "Left Y-", + "Right Axis X+", "Right X+", + "Right Axis X-", "Right X-", + "Right Axis Y+", "Right Y+", + "Right Axis Y-", "Right Y-", + "Motor", "LeftRight", +}; + + +EmuDevice::EmuDevice(int type, HWND hwnd) +{ + switch (type) + { + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): { + m_hwnd = hwnd; + for (int i = 0; i < ARRAY_SIZE(button_xbox_ctrl_id); i++) { + m_buttons.push_back(new Button(button_xbox_ctrl_names[i][0], button_xbox_ctrl_names[i][1], + button_xbox_ctrl_id[i], i, hwnd)); + + // Install the subclass for the button control + SetWindowSubclass(GetDlgItem(hwnd, button_xbox_ctrl_id[i]), ButtonSubclassProc, 0, reinterpret_cast(m_buttons[i])); + } + } + break; + + default: + break; + } +} + +EmuDevice::~EmuDevice() +{ + for (auto button : m_buttons) { + delete button; + } +} + +Button* EmuDevice::FindButtonById(int id) +{ + auto it = std::find_if(m_buttons.begin(), m_buttons.end(), [&id](const auto button) { + if (button->GetId() == id) { + return true; + } + return false; + }); + assert(it != m_buttons.end()); + return *it; +} + +Button* EmuDevice::FindButtonByIndex(int index) +{ + return m_buttons[index]; +} + +void EmuDevice::BindXInput() +{ + std::for_each(m_buttons.begin(), m_buttons.end(), [](const auto button) { + button->UpdateText(); + }); +} + +void EmuDevice::ClearButtons() +{ + std::for_each(m_buttons.begin(), m_buttons.end(), [](const auto button) { + button->ClearText(); + }); +} diff --git a/src/core/hle/XAPI/OHCI/XInput/XInput.h b/src/common/input/EmuDevice.h similarity index 58% rename from src/core/hle/XAPI/OHCI/XInput/XInput.h rename to src/common/input/EmuDevice.h index bb5b2c4c04..346a94de7c 100644 --- a/src/core/hle/XAPI/OHCI/XInput/XInput.h +++ b/src/common/input/EmuDevice.h @@ -1,3 +1,5 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // ****************************************************************** // * // * This file is part of the Cxbx project. @@ -17,25 +19,34 @@ // * If not, write to the Free Software Foundation, Inc., // * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. // * -// * (c) 2002-2003 Aaron Robinson +// * (c) 2019 ergo720 // * // * All rights reserved // * // ****************************************************************** -#ifndef XINPUT_H -#define XINPUT_H -//query the total connected xinput gamepad -DWORD XInputGamepad_Connected(void); +#pragma once -// ****************************************************************** -// * patch: XInputPCPoll -// ****************************************************************** -void EmuXInputPCPoll( DWORD dwPort, XTL::PX_XINPUT_STATE Controller ); +#include "Button.h" +#include "common\util\CxbxUtil.h" + +extern const char* button_xbox_ctrl_names[XBOX_CTRL_NUM_BUTTONS][2]; +extern int dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)]; + + +/* Represents the guest device currently being configured in the gui */ +class EmuDevice +{ +public: + EmuDevice(int type, HWND hwnd); + ~EmuDevice(); + Button* FindButtonById(int id); + Button* FindButtonByIndex(int index); + void BindXInput(); + void ClearButtons(); -// ****************************************************************** -// * Native implementation of XInputSetState -// ****************************************************************** -void EmuXInputSetState(DWORD dwPort, XTL::PX_XINPUT_FEEDBACK Feedback); -#endif +private: + std::vector m_buttons; + HWND m_hwnd; +}; diff --git a/src/common/input/InputConfig.cpp b/src/common/input/InputConfig.cpp deleted file mode 100644 index a323019a10..0000000000 --- a/src/common/input/InputConfig.cpp +++ /dev/null @@ -1,460 +0,0 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -// ****************************************************************** -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2018 ergo720 -// * -// * All rights reserved -// * -// ****************************************************************** -#if 0 // Reenable this when LLE USB actually works -#define LOG_PREFIX CXBXR_MODULE::SDL2 - -// prevent name collisions -namespace xboxkrnl -{ - #include // For PKINTERRUPT, etc. -}; - -#include "InputConfig.h" -#include "SDL2_Device.h" -#include "..\devices\usb\XidGamepad.h" -#include "core\kernel\exports\EmuKrnl.h" // For EmuLog -#include - - -InputDeviceManager* g_InputDeviceManager = nullptr; - -InputDeviceManager::InputDeviceManager() -{ - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) { - CxbxKrnlCleanup("Failed to initialize SDL2 input subsystem. The error was: %s\n", SDL_GetError()); - return; - } -} - -InputDeviceManager::~InputDeviceManager() -{ - SDL_Quit(); -} - -int InputDeviceManager::EnumSdl2Devices() -{ - int NumOfJoysticks; - int NumInvalidJoysticks; - SDL2Devices* pDev; - SDL_Joystick* pJoystick; - std::vector::iterator it; - - NumOfJoysticks = SDL_NumJoysticks(); - if (NumOfJoysticks < 0) { - EmuLog(LOG_LEVEL::WARNING, "Failed to enumerate joysticks. The error was: %s", SDL_GetError()); - return 0; - } - - NumInvalidJoysticks = 0; - - for (int i = 0; i < NumOfJoysticks; i++) { - pDev = new SDL2Devices(); - pDev->m_Index = i; - m_Sdl2Devices.push_back(pDev); - } - - for (it = m_Sdl2Devices.begin(); it != m_Sdl2Devices.end();) { - pJoystick = SDL_JoystickOpen((*it)->m_Index); - if (pJoystick == nullptr) { - EmuLog(LOG_LEVEL::WARNING, "Failed to open joystick %s. The error was %s\n", SDL_GameControllerNameForIndex((*it)->m_Index), SDL_GetError()); - delete (*it); - it = m_Sdl2Devices.erase(it); - NumInvalidJoysticks++; - } - else { - printf("Found joystick %s\n", SDL_JoystickName(pJoystick)); - (*it)->m_Joystick = pJoystick; - (*it)->m_jyID = SDL_JoystickInstanceID(pJoystick); - (*it)->m_Attached = 1; - ++it; - } - } - - return NumOfJoysticks - NumInvalidJoysticks; -} - -int InputDeviceManager::ConnectDeviceToXbox(int port, int type) -{ - int ret = -1; - std::vector::iterator it; - - if (port > 4 || port < 1) { return ret; }; - - for (it = m_Sdl2Devices.begin(); it != m_Sdl2Devices.end(); ++it) { - if ((*it)->m_Index == (port - 1)) { - --port; - break; - } - } - - if (it == m_Sdl2Devices.end()) { - EmuLog(LOG_LEVEL::WARNING, "Attempted to connect a device not yet enumerated.\n"); - return ret; - } - - switch (type) - { - case MS_CONTROLLER_DUKE: { - if (g_HubObjArray[port] == nullptr) { - g_HubObjArray[port] = new Hub; - ret = g_HubObjArray[port]->Init(port + 1); - if (ret) { - delete g_HubObjArray[port]; - g_HubObjArray[port] = nullptr; - break; - } - if (g_XidControllerObjArray[port] == nullptr) { - g_XidControllerObjArray[port] = new XidGamepad; - ret = g_XidControllerObjArray[port]->Init(port + 1); - if (ret) { - g_HubObjArray[port]->HubDestroy(); - delete g_HubObjArray[port]; - g_HubObjArray[port] = nullptr; - delete g_XidControllerObjArray[port]; - g_XidControllerObjArray[port] = nullptr; - } - } - else { - ret = -1; - g_HubObjArray[port]->HubDestroy(); - delete g_HubObjArray[port]; - g_HubObjArray[port] = nullptr; - EmuLog(LOG_LEVEL::WARNING, "Xid controller already present at port %d.2\n", port + 1); - } - } - else { - EmuLog(LOG_LEVEL::WARNING, "Hub already present at port %d\n", port + 1); - } - break; - } - - case MS_CONTROLLER_S: - case LIGHT_GUN: - case STEERING_WHEEL: - case MEMORY_UNIT: - case IR_DONGLE: - case STEEL_BATTALION_CONTROLLER: { - printf("This device type is not yet supported\n"); - break; - } - - default: - EmuLog(LOG_LEVEL::WARNING, "Attempted to attach an unknown device type\n"); - } - - if (!ret) { - (*it)->m_Type = type; - (*it)->m_Attached = 1; - } - - return ret; -} - -void InputDeviceManager::DisconnectDeviceFromXbox(int port) -{ - std::vector::iterator it; - - if (port < 1) { return; } - - for (it = m_Sdl2Devices.begin(); it != m_Sdl2Devices.end(); ++it) { - if ((*it)->m_Index == (port - 1)) { - --port; - break; - } - } - - if (it == m_Sdl2Devices.end()) { - // Not necessarily a bug. This could also be triggered by detaching an unsupported joystick - return; - } - - if (port + 1 > 4) { - delete (*it); - m_Sdl2Devices.erase(it); - return; - } - - switch ((*it)->m_Type) - { - case MS_CONTROLLER_DUKE: { - if (g_HubObjArray[port] != nullptr && g_XidControllerObjArray[port] != nullptr) { - g_HubObjArray[port]->HubDestroy(); - delete g_HubObjArray[port]; - g_HubObjArray[port] = nullptr; - delete g_XidControllerObjArray[port]; - g_XidControllerObjArray[port] = nullptr; - delete (*it); - m_Sdl2Devices.erase(it); - // Here, we could also see if there are detached devices that have a matching type and bound buttons, so that it can immediately - // be used instead of remaining inactive (example: 5 controllers and 1st is detached -> 5th can be used if it has bindings) - } - else { - EmuLog(LOG_LEVEL::WARNING, "Attempted to disconnect a device not attached to the Xbox.\n"); - } - break; - } - - case MS_CONTROLLER_S: - case LIGHT_GUN: - case STEERING_WHEEL: - case MEMORY_UNIT: - case IR_DONGLE: - case STEEL_BATTALION_CONTROLLER: { - printf("This device type is not yet supported\n"); - break; - } - - default: - EmuLog(LOG_LEVEL::WARNING, "Attempted to detach an unknown device type\n"); - } -} - -void InputDeviceManager::StartInputThread() -{ - std::thread(InputThread, this).detach(); -} - -void InputDeviceManager::InputThread(InputDeviceManager* pVoid) -{ - SetThreadAffinityMask(GetCurrentThread(), g_CPUOthers); - bool bContinue = true; - SDL_Event event; - - if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { - CxbxKrnlCleanup("Failed to initialize SDL2 video subsystem. The error was: %s\n", SDL_GetError()); - return; - } - - SDL_JoystickEventState(SDL_ENABLE); - - while (bContinue) - { - if (SDL_WaitEvent(&event)) - { - switch (event.type) - { - case SDL_JOYBUTTONUP: - case SDL_JOYBUTTONDOWN: { - pVoid->UpdateButtonState(event.jbutton.which, event.jbutton.button, event.jbutton.state); - break; - } - - case SDL_JOYHATMOTION: { - pVoid->UpdateHatState(event.jhat.which, event.jhat.hat, event.jhat.value); - break; - } - - case SDL_JOYAXISMOTION: { - pVoid->UpdateAxisState(event.jaxis.which, event.jaxis.axis, event.jaxis.value); - break; - } - - case SDL_JOYDEVICEADDED: { - bool found = false; - for (auto dev : pVoid->m_Sdl2Devices) { - if (dev->m_Index == event.jdevice.which) { - // already enumerated, skipping - found = true; - break; - } - } - if (!found) { - // for now we only support a single controller at port 1, more will be added later - if (!pVoid->IsValidController(event.jdevice.which) && event.jdevice.which == 0) { - pVoid->ConnectDeviceToXbox(1, MS_CONTROLLER_DUKE); - } - } - break; - } - - case SDL_JOYDEVICEREMOVED: { - pVoid->DisconnectDeviceFromXbox(event.jdevice.which + 1); - break; - } - - case SDL_QUIT: { - bContinue = false; - break; - } - - default: - break; - } - } - } -} - -void InputDeviceManager::UpdateButtonState(SDL_JoystickID id, uint8_t button, uint8_t state) -{ - SDL2Devices* ControllerObj = nullptr; - int xbox_button; - - for (auto Obj : m_Sdl2Devices) { - if (Obj->m_jyID == id) { - ControllerObj = Obj; - break; - } - } - - if (ControllerObj == nullptr) { - return; - } - - xbox_button = ControllerObj->GetBoundButton(button); - - if (xbox_button == GAMEPAD_INVALID) { - return; - } - - switch (xbox_button) - { - case GAMEPAD_A: - case GAMEPAD_B: - case GAMEPAD_X: - case GAMEPAD_Y: - case GAMEPAD_BLACK: - case GAMEPAD_WHITE: - case GAMEPAD_LEFT_TRIGGER: - case GAMEPAD_RIGHT_TRIGGER: { - ControllerObj->UpdateAnalogButtonState(xbox_button, state); - break; - } - - case GAMEPAD_BACK: - case GAMEPAD_START: - case GAMEPAD_LEFT_THUMB: - case GAMEPAD_RIGHT_THUMB: - case GAMEPAD_DPAD_UP: - case GAMEPAD_DPAD_DOWN: - case GAMEPAD_DPAD_LEFT: - case GAMEPAD_DPAD_RIGHT: { - ControllerObj->UpdateDigitalButtonState(xbox_button, state); - break; - } - - default: - break; - } -} - -void InputDeviceManager::UpdateHatState(SDL_JoystickID id, uint8_t hat_index, uint8_t state) -{ - SDL2Devices* ControllerObj = nullptr; - int xbox_button; - - for (auto Obj : m_Sdl2Devices) { - if (Obj->m_jyID == id) { - ControllerObj = Obj; - break; - } - } - - if (ControllerObj == nullptr) { - return; - } - - xbox_button = ControllerObj->GetBoundButton(hat_index + HAT_CONSTANT); - - if (xbox_button == GAMEPAD_INVALID) { - return; - } - - ControllerObj->UpdateHatState(state); -} - -void InputDeviceManager::UpdateAxisState(SDL_JoystickID id, uint8_t axis_index, int16_t state) -{ - SDL2Devices* ControllerObj = nullptr; - int xbox_button; - - for (auto Obj : m_Sdl2Devices) { - if (Obj->m_jyID == id) { - ControllerObj = Obj; - break; - } - } - - if (ControllerObj == nullptr) { - return; - } - - xbox_button = ControllerObj->GetBoundButton(axis_index); - - if (xbox_button == GAMEPAD_INVALID) { - return; - } - - ControllerObj->UpdateAxisState(xbox_button, state); -} - -int InputDeviceManager::IsValidController(int index) -{ - SDL2Devices* pDev; - SDL_Joystick* pJoystick; - - if (SDL_IsGameController(index)) { - pDev = new SDL2Devices(); - pDev->m_Index = index; - m_Sdl2Devices.push_back(pDev); - } - else { - // this joystick is not supported at the moment - return -1; - } - - pJoystick = SDL_JoystickOpen(pDev->m_Index); - if (pJoystick == nullptr) { - EmuLog(LOG_LEVEL::WARNING, "Failed to open game controller %s. The error was %s\n", SDL_GameControllerNameForIndex(pDev->m_Index), SDL_GetError()); - delete pDev; - m_Sdl2Devices.erase(m_Sdl2Devices.begin() + index); - return -1; - } - else if (pDev->m_Index > 3) { - printf("More than 4 controllers detected. Putting game controller %s in detached state\n", SDL_JoystickName(pJoystick)); - pDev->m_Attached = 0; - return -1; - } - else { - printf("Found game controller %s\n", SDL_JoystickName(pJoystick)); - pDev->m_Joystick = pJoystick; - pDev->m_jyID = SDL_JoystickInstanceID(pJoystick); - return 0; - } -} - -SDL2Devices* InputDeviceManager::FindDeviceFromXboxPort(int port) -{ - if (port > 4 || port < 1) { return nullptr; }; - - for (auto it = m_Sdl2Devices.begin(); it != m_Sdl2Devices.end(); ++it) { - if ((*it)->m_Index == (port - 1)) { - return *it; - } - } - return nullptr; -} -#endif diff --git a/src/common/input/InputConfig.h b/src/common/input/InputConfig.h deleted file mode 100644 index 0e4ab7de40..0000000000 --- a/src/common/input/InputConfig.h +++ /dev/null @@ -1,119 +0,0 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -// ****************************************************************** -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2018 ergo720 -// * -// * All rights reserved -// * -// ****************************************************************** - -#ifndef INPUTCONFIG_H_ -#define INPUTCONFIG_H_ -#if 0 // Reenable this when LLE USB actually works -#include -#include -#include "SDL.h" - -#define GAMEPAD_A 0 -#define GAMEPAD_B 1 -#define GAMEPAD_X 2 -#define GAMEPAD_Y 3 -#define GAMEPAD_BLACK 4 -#define GAMEPAD_WHITE 5 -#define GAMEPAD_LEFT_TRIGGER 6 -#define GAMEPAD_RIGHT_TRIGGER 7 - -#define GAMEPAD_DPAD_UP 8 -#define GAMEPAD_DPAD_DOWN 9 -#define GAMEPAD_DPAD_LEFT 10 -#define GAMEPAD_DPAD_RIGHT 11 -#define GAMEPAD_START 12 -#define GAMEPAD_BACK 13 -#define GAMEPAD_LEFT_THUMB 14 -#define GAMEPAD_RIGHT_THUMB 15 - -#define GAMEPAD_LEFT_THUMB_X 16 -#define GAMEPAD_LEFT_THUMB_Y 17 -#define GAMEPAD_RIGHT_THUMB_X 18 -#define GAMEPAD_RIGHT_THUMB_Y 19 - -#define GAMEPAD_INVALID -1 - -#define HAT_CONSTANT 255 - -#define BUTTON_MASK(button) (1 << ((button) - GAMEPAD_DPAD_UP)) - - -/* enum indicating the device type to attach to the virtual xbox */ -typedef enum { - DEVICE_INVALID = 0, - MS_CONTROLLER_DUKE, - MS_CONTROLLER_S, - LIGHT_GUN, - STEERING_WHEEL, - MEMORY_UNIT, - IR_DONGLE, - STEEL_BATTALION_CONTROLLER, -} -XBOX_INPUT_DEVICE; - -class SDL2Devices; // forward declare - - -class InputDeviceManager -{ - public: - InputDeviceManager(); - ~InputDeviceManager(); - - // enumerate all available sdl2 controllers - int EnumSdl2Devices(); - // start input event processing thread - void StartInputThread(); - // connect the enumerated device to the virtual xbox - int ConnectDeviceToXbox(int port, int type); - // disconnect a device from the emulated xbox - void DisconnectDeviceFromXbox(int port); - // find the device attached to the supplied xbox port - SDL2Devices* FindDeviceFromXboxPort(int port); - - - private: - // all enumerated devices currently detected and supported - std::vector m_Sdl2Devices; - - // assign the button binding to the devices - //void AssignBindings(); - // input thread - static void InputThread(InputDeviceManager* pVoid); - // updates the button state of a joystick - void UpdateButtonState(SDL_JoystickID id, uint8_t button, uint8_t state); - // updates the hat state of a joystick - void UpdateHatState(SDL_JoystickID id, uint8_t hat_index, uint8_t state); - // updates the axis state of a joystick - void UpdateAxisState(SDL_JoystickID id, uint8_t axis_index, int16_t state); - // checks if the controller attached can be used by sdl - int IsValidController(int index); -}; - -extern InputDeviceManager* g_InputDeviceManager; -#endif -#endif diff --git a/src/common/input/InputDevice.cpp b/src/common/input/InputDevice.cpp new file mode 100644 index 0000000000..b8184a8a3c --- /dev/null +++ b/src/common/input/InputDevice.cpp @@ -0,0 +1,133 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file of Dolphin at https://github.com/dolphin-emu/dolphin/blob/master/license.txt. + +// Partially derived from Device.cpp of Dolphin emulator +// https://github.com/dolphin-emu/dolphin + +#include "InputDevice.h" +#include "common\util\CxbxUtil.h" +#include + + +std::string GetInputDeviceName(int dev_type) +{ + std::string str; + + switch (dev_type) + { + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): { + str = "MS Gamepad Duke"; + } + break; + + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): { + str = "MS Gamepad S"; + } + break; + + case to_underlying(XBOX_INPUT_DEVICE::LIGHT_GUN): { + str = "Light gun"; + } + break; + + case to_underlying(XBOX_INPUT_DEVICE::STEERING_WHEEL): { + str = "Steering wheel"; + } + break; + + case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT): { + str = "Memory unit"; + } + break; + + case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE): { + str = "IR dongle"; + } + break; + + case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): { + str = "Steel battalion controller"; + } + break; + + case to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID): + case to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX): { + str = "Invalid"; + } + break; + + default: + str = "Unknown"; + } + + return str; +} + +// Destructor, delete all inputs/outputs on device destruction +InputDevice::~InputDevice() +{ + // delete inputs + for (InputDevice::Input* input : m_Inputs) { + delete input; + } + + // delete outputs + for (InputDevice::Output* output : m_Outputs) { + delete output; + } +} + +void InputDevice::AddInput(Input* const In) +{ + m_Inputs.push_back(In); +} + +void InputDevice::AddOutput(Output* const Out) +{ + m_Outputs.push_back(Out); +} + +std::string InputDevice::GetQualifiedName() const +{ + return this->GetAPI() + "/" + std::to_string(GetId()) + "/" + this->GetDeviceName(); +} + +const std::vector InputDevice::GetIoControls() +{ + std::vector vec; + std::for_each(m_Inputs.begin(), m_Inputs.end(), [&vec](const auto input) { + vec.push_back(dynamic_cast(input)); + }); + std::for_each(m_Outputs.begin(), m_Outputs.end(), [&vec](const auto output) { + vec.push_back(dynamic_cast(output)); + }); + return vec; +} diff --git a/src/common/input/InputDevice.h b/src/common/input/InputDevice.h new file mode 100644 index 0000000000..4ff6d44650 --- /dev/null +++ b/src/common/input/InputDevice.h @@ -0,0 +1,185 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +#ifndef INPUT_DEVICE +#define INPUT_DEVICE + +#include +#include +#include +#include +#include +#include +#include "SDL.h" + +#define PORT_INVALID -1 +#define PORT_1 0 +#define PORT_2 1 +#define PORT_3 2 +#define PORT_4 3 + +#define PORT_INC(port) ((port) + 1) +#define PORT_DEC(port) ((port) - 1) + +#define DIRECTION_IN 0 +#define DIRECTION_OUT 1 + + +typedef double ControlState; + +/* enum indicating the device type to attach to the virtual xbox */ +typedef enum class _XBOX_INPUT_DEVICE : int { + DEVICE_INVALID = -1, + MS_CONTROLLER_DUKE, + MS_CONTROLLER_S, + LIGHT_GUN, + STEERING_WHEEL, + MEMORY_UNIT, + IR_DONGLE, + STEEL_BATTALION_CONTROLLER, + DEVICE_MAX, +} +XBOX_INPUT_DEVICE; + +// Lookup array used to translate a gui port to an xbox usb port and vice versa +extern int Gui2XboxPortArray[4]; + +// Global function used to retrieve the printable name of a xid type +std::string GetInputDeviceName(int dev_type); + +/* Abstract class which represents a host device usable for input/output */ +class InputDevice +{ +public: + virtual ~InputDevice(); + + class IoControl + { + public: + virtual std::string GetName() const = 0; + }; + + class Input : public IoControl + { + public: + virtual ControlState GetState() const = 0; + virtual bool IsDetectable() { return true; } + }; + + class Output : public IoControl + { + public: + virtual void SetState(ControlState StateLeft, ControlState StateRight) = 0; + }; + + // retrieves the vector of input controls + const std::vector& GetInputs() const { return m_Inputs; } + // retrieves the vector of output controls + const std::vector& GetOutputs() const { return m_Outputs; } + // retrieves all the i/o controls of this device + const std::vector GetIoControls(); + // retrieves the full name of the device (API/ID/API-specific name) + std::string GetQualifiedName() const; + // retrieves the API-specific name of the device + virtual std::string GetDeviceName() const = 0; + // retrieves the API used to control this device + virtual std::string GetAPI() const = 0; + // updates the state of the device and checks if its state has changed + virtual bool UpdateInput() = 0; + // retrieves the ID of this device + int GetId() const { return m_ID; } + // retrieves the sdl id or -1 for non-sdl devices + virtual SDL_JoystickID GetId(SDL_JoystickID id) const { return -1; } + // sets the ID of this device + void SetId(int ID) { m_ID = ID; } + // retrieves the port this device is attached to + bool GetPort(int Port) const { return m_XboxPort[Port]; } + // sets the port this device is attached to + void SetPort(int Port, bool Connect) { m_XboxPort[Port] = Connect; } + + +protected: + // adds an input control to the device + void AddInput(Input* const In); + // adds an output control to the device + void AddOutput(Output* const Out); + // indicates that the device has new input data available + bool m_bDirty; + // lock for the bindings map + mutable std::mutex m_BindingsMtx; + +public: + // retrieves the map of input bindings + const std::map GetBindings() const { + std::lock_guard lck(m_BindingsMtx); + return m_Bindings; + } + // sets a pair in the map of the input bindings + void SetBindings(int XButton, IoControl* Control) { + std::lock_guard lck(m_BindingsMtx); + m_Bindings[XButton] = Control; + } + +protected: + class FullAnalogSurface : public Input + { + public: + FullAnalogSurface(Input* Low, Input* High) : m_Low(*Low), m_High(*High) {} + ControlState GetState() const override + { + return (1 + m_High.GetState() - m_Low.GetState()) / 2; + } + + std::string GetName() const override { return m_Low.GetName() + *m_High.GetName().rbegin(); } + + private: + Input& m_Low; + Input& m_High; + }; + + void AddAnalogInputs(Input* Low, Input* High) + { + AddInput(Low); + AddInput(High); + AddInput(new FullAnalogSurface(Low, High)); + AddInput(new FullAnalogSurface(High, Low)); + } + +private: + // arbitrary ID assigned by to the device + int m_ID; + // all the input controls detected and usable on this device + std::vector m_Inputs; + // all the output controls detected and usable on this device + std::vector m_Outputs; + // xbox port(s) this device is attached to + bool m_XboxPort[4] = { false }; + // button bindings to the xbox device buttons + std::map m_Bindings; +}; + +#endif diff --git a/src/common/input/InputManager.cpp b/src/common/input/InputManager.cpp new file mode 100644 index 0000000000..7e2a8a748f --- /dev/null +++ b/src/common/input/InputManager.cpp @@ -0,0 +1,511 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +// Copyright 2010 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file of Dolphin at https://github.com/dolphin-emu/dolphin/blob/master/license.txt. + +// Partially derived from ControllerInterface.cpp of Dolphin emulator +// https://github.com/dolphin-emu/dolphin + +#define _XBOXKRNL_DEFEXTRN_ +#define LOG_PREFIX CXBXR_MODULE::INPSYS + +// prevent name collisions +namespace xboxkrnl +{ +#include // For PKINTERRUPT, etc. +}; + +#include "SdlJoystick.h" +#include "XInputPad.h" +#include "DInputKeyboardMouse.h" +#include "InputManager.h" +#include "..\devices\usb\XidGamepad.h" +#include "core\kernel\exports\EmuKrnl.h" // For EmuLog +#include "EmuShared.h" +#include "devices\usb\OHCI.h" + +// hle input specific +namespace XTL +{ +#include "core\hle\XAPI\Xapi.h" +} +#include "core\hle\XAPI\XapiCxbxr.h" + +extern X_CONTROLLER_HOST_BRIDGE g_XboxControllerHostBridge[4]; // hle xinput + + +InputDeviceManager g_InputDeviceManager; + +void InputDeviceManager::Initialize(bool is_gui) +{ + // Sdl::Init must be called last since it blocks when it succeeds + std::unique_lock lck(m_Mtx); + m_bPendingShutdown = false; + + m_PollingThread = std::thread([this]() { + XInput::Init(m_Mtx); + Sdl::Init(m_Mtx, m_Cv); + }); + + m_Cv.wait(lck, []() { + return (Sdl::SdlInitStatus != Sdl::SDL_NOT_INIT) && + (XInput::XInputInitStatus != XInput::XINPUT_NOT_INIT); + }); + lck.unlock(); + + if (Sdl::SdlInitStatus < 0 || XInput::XInputInitStatus < 0) { + CxbxKrnlCleanup("Failed to initialize input subsystem! Consult debug log for more information"); + } + + RefreshDevices(); + + if (!is_gui) { + UpdateDevices(PORT_1, false); + UpdateDevices(PORT_2, false); + UpdateDevices(PORT_3, false); + UpdateDevices(PORT_4, false); + } +} + +void InputDeviceManager::Shutdown() +{ + // Prevent additional devices from being added during shutdown. + m_bPendingShutdown = true; + + std::lock_guard lk(m_Mtx); + for (const auto& d : m_Devices) + { + // Set outputs to ZERO before destroying device + for (InputDevice::Output* o : d->GetOutputs()) { + o->SetState(0.0, 0.0); + } + } + m_Devices.clear(); + + XInput::DeInit(); + Sdl::DeInit(m_PollingThread); +} + +void InputDeviceManager::AddDevice(std::shared_ptr Device) +{ + // If we are shutting down, ignore this request + if (m_bPendingShutdown) { + return; + } + + std::lock_guard lk(m_Mtx); + // Try to find an ID for this device + int ID = 0; + while (true) + { + const auto it = + std::find_if(m_Devices.begin(), m_Devices.end(), [&Device, &ID](const auto& d) { + return d->GetAPI() == Device->GetAPI() && d->GetDeviceName() == Device->GetDeviceName() && + d->GetId() == ID; + }); + if (it == m_Devices.end()) { // no device with the same name with this ID, so we can use it + break; + } + else { + ID++; + } + } + Device->SetId(ID); + + EmuLog(LOG_LEVEL::INFO, "Added device: %s", Device->GetQualifiedName().c_str()); + m_Devices.emplace_back(std::move(Device)); +} + +void InputDeviceManager::RemoveDevice(std::function Callback) +{ + // If we are shutting down, ignore this request + if (m_bPendingShutdown) { + return; + } + + std::lock_guard lk(m_Mtx); + auto it = std::remove_if(m_Devices.begin(), m_Devices.end(), [&Callback](const auto& Device) { + if (Callback(Device.get())) + { + EmuLog(LOG_LEVEL::INFO, "Removed device: %s", Device->GetQualifiedName().c_str()); + return true; + } + return false; + }); + if (it != m_Devices.end()) { + m_Devices.erase(it, m_Devices.end()); + } +} + +void InputDeviceManager::UpdateDevices(int port, bool ack) +{ + if (port > PORT_4 || port < PORT_1) { + EmuLog(LOG_LEVEL::WARNING, "Invalid port number. The port was %d", PORT_INC(port)); + return; + } + int type; +#if 0 // lle usb + int usb_port = PORT_DEC(Gui2XboxPortArray[port]); +#else + int usb_port = port; +#endif + g_EmuShared->GetInputDevTypeSettings(&type, port); + + // connect + if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) && + //g_XidDeviceObjArray[usb_port].xid_dev == nullptr) { lle usb + g_XboxControllerHostBridge[usb_port].XboxType == XBOX_INPUT_DEVICE::DEVICE_INVALID) { + ConnectDevice(port, usb_port, type); + } + // disconnect + else if (type == to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) && + //g_XidDeviceObjArray[usb_port].xid_dev != nullptr) { lle usb + g_XboxControllerHostBridge[usb_port].XboxType != XBOX_INPUT_DEVICE::DEVICE_INVALID) { + DisconnectDevice(port, usb_port, ack); + } + // update bindings + else { + auto dev = g_InputDeviceManager.FindDevice(usb_port, 0); + if (dev != nullptr) { + dev->SetPort(usb_port, false); + } + if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { + BindHostDevice(port, usb_port, type); + } + } +} + +void InputDeviceManager::ConnectDevice(int port, int usb_port, int type) +{ +#if 0 // lle usb + switch (type) + { + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): { + if (ConstructHub(usb_port)) { + if (!ConstructXpadDuke(usb_port)) { + DestructHub(usb_port); + return; + } + g_XidDeviceObjArray[usb_port].xid_type = type; + EmuLog(LOG_LEVEL::INFO, "Attached device %s to port %d", GetInputDeviceName(type).c_str(), PORT_INC(port)); + } + } + break; + + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): + case to_underlying(XBOX_INPUT_DEVICE::LIGHT_GUN): + case to_underlying(XBOX_INPUT_DEVICE::STEERING_WHEEL): + case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT): + case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE): + case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): { + EmuLog(LOG_LEVEL::INFO, "%s: device %s is not yet supported", __func__, GetInputDeviceName(type).c_str()); + return; + } + + default: + EmuLog(LOG_LEVEL::WARNING, "Attempted to attach an unknown device type (type was %d)", type); + return; + } +#else + if (!ConstructHleInputDevice(type, port)) { + return; + } + EmuLog(LOG_LEVEL::INFO, "Attached device %s to port %d", GetInputDeviceName(type).c_str(), PORT_INC(port)); +#endif + BindHostDevice(port, usb_port, type); +} + +void InputDeviceManager::DisconnectDevice(int port, int usb_port, bool ack) +{ +#if 0 // lle usb + if (g_XidDeviceObjArray[usb_port].xid_dev != nullptr) { + int type = g_XidDeviceObjArray[usb_port].xid_type; + + switch (type) + { + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): { + if (ack) { + assert(g_HubObjArray[usb_port] != nullptr); + DestructHub(usb_port); + DestructXpadDuke(usb_port); + g_HostController->OHCI_SetRemovalFlag(usb_port, false); + EmuLog(LOG_LEVEL::INFO, "Detached device %s from port %d", GetInputDeviceName(type).c_str(), PORT_INC(port)); + } + else { + g_HostController->OHCI_SetRemovalFlag(usb_port, true); + } + } + break; + + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): + case to_underlying(XBOX_INPUT_DEVICE::LIGHT_GUN): + case to_underlying(XBOX_INPUT_DEVICE::STEERING_WHEEL): + case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT): + case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE): + case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): { + EmuLog(LOG_LEVEL::INFO, "%s: device %s is not yet supported", __func__, GetInputDeviceName(type).c_str()); + return; + } + + default: + EmuLog(LOG_LEVEL::WARNING, "Attempted to detach an unknown device type (type was %d)", type); + return; + } +#endif + if (g_XboxControllerHostBridge[port].XboxType != XBOX_INPUT_DEVICE::DEVICE_INVALID) { + if (ack) { + int type = to_underlying(g_XboxControllerHostBridge[port].XboxType); + DestructHleInputDevice(port); + EmuLog(LOG_LEVEL::INFO, "Detached device %s from port %d", GetInputDeviceName(type).c_str(), PORT_INC(port)); + } + else { + g_XboxControllerHostBridge[port].bPendingRemoval = true; + } + auto dev = g_InputDeviceManager.FindDevice(usb_port, 0); + if (dev != nullptr) { + dev->SetPort(usb_port, false); + } + } + else { + EmuLog(LOG_LEVEL::WARNING, "Attempted to detach a device not attached to the emulated machine"); + } +} + +void InputDeviceManager::BindHostDevice(int port, int usb_port, int type) +{ + char dev_name[50]; + char dev_control_names[XBOX_CTRL_NUM_BUTTONS][30]; + + g_EmuShared->GetInputDevNameSettings(dev_name, port); + g_EmuShared->GetInputBindingsSettings(dev_control_names, XBOX_CTRL_NUM_BUTTONS, port); + + auto dev = FindDevice(std::string(dev_name)); + if (dev != nullptr) { + std::vector controls = dev->GetIoControls(); + for (int index = 0; index < dev_num_buttons[type]; index++) { + std::string dev_button(dev_control_names[index]); + auto it = std::find_if(controls.begin(), controls.end(), [&dev_button](const auto control) { + if (control->GetName() == dev_button) { + return true; + } + return false; + }); + dev->SetBindings(index, (it != controls.end()) ? *it : nullptr); + } + dev->SetPort(usb_port, true); + } +} + +bool InputDeviceManager::UpdateXboxPortInput(int usb_port, void* Buffer, int Direction, int xid_type) +{ + assert(Direction == DIRECTION_IN || Direction == DIRECTION_OUT); + assert(xid_type > to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) && + xid_type < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)); + bool has_changed = false; + + // If somebody else is currently holding the lock, we won't wait and instead report no input changes + if (m_Mtx.try_lock()) { + for (auto dev_ptr : m_Devices) { + if (dev_ptr->GetPort(usb_port)) { + switch (xid_type) + { + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): { + has_changed = UpdateInputXpad(dev_ptr, Buffer, Direction); + } + break; + + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): + case to_underlying(XBOX_INPUT_DEVICE::LIGHT_GUN): + case to_underlying(XBOX_INPUT_DEVICE::STEERING_WHEEL): + case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT): + case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE): + case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): { + EmuLog(LOG_LEVEL::WARNING, "An unsupported device is attached at port %d! The device was %s", + Gui2XboxPortArray[usb_port], GetInputDeviceName(xid_type).c_str()); + } + break; + + default: { + EmuLog(LOG_LEVEL::WARNING, "An unknown device attached at port %d! The type was %s", + Gui2XboxPortArray[usb_port], GetInputDeviceName(xid_type).c_str()); + } + } + } + } + m_Mtx.unlock(); + } + return has_changed; +} + +bool InputDeviceManager::UpdateInputXpad(std::shared_ptr& Device, void* Buffer, int Direction) +{ + std::map bindings = Device->GetBindings(); + assert(bindings.size() == static_cast(dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE)])); + + if (Direction == DIRECTION_IN) { + //XpadInput* in_buf = reinterpret_cast(static_cast(Buffer) + 2); lle usb + XpadInput* in_buf = reinterpret_cast(Buffer); + if (!Device->UpdateInput()) { + return false; + } + + for (int i = 0; i < 8; i++) { + ControlState state = (bindings[i] != nullptr) ? dynamic_cast(bindings[i])->GetState() : 0.0; + if (state) { + in_buf->wButtons |= (1 << i); + } + else { + in_buf->wButtons &= ~(1 << i); + } + } + for (int i = 8, j = 0; i < 16; i++, j++) { + ControlState state = (bindings[i] != nullptr) ? dynamic_cast(bindings[i])->GetState() : 0.0; + in_buf->bAnalogButtons[j] = static_cast(state * 0xFF); + } + + for (int i = 16, j = 0; i < 24; i += 2, j++) { + ControlState state_plus = (bindings[i] != nullptr) ? dynamic_cast(bindings[i])->GetState() : 0.0; + ControlState state_minus = (bindings[i + 1] != nullptr) ? dynamic_cast(bindings[i + 1])->GetState() : 0.0; + ControlState state = state_plus ? state_plus * 0x7FFF : state_minus ? -state_minus * 0x8000 : 0.0; + switch (j) + { + case 0: { + in_buf->sThumbLX = static_cast(state); + } + break; + + case 1: { + in_buf->sThumbLY = static_cast(state); + } + break; + + case 2: { + in_buf->sThumbRX = static_cast(state); + } + break; + + case 3: { + in_buf->sThumbRY = static_cast(state); + } + break; + + default: { + // unreachable + } + } + } + } + else { + if (bindings[24] != nullptr) { + //XpadOutput* out_buf = reinterpret_cast(static_cast(Buffer) + 2); lle usb + XpadOutput* out_buf = reinterpret_cast(Buffer); + dynamic_cast(bindings[24])->SetState(out_buf->left_actuator_strength / static_cast(0xFFFF), + out_buf->right_actuator_strength / static_cast(0xFFFF)); + } + } + return true; +} + +void InputDeviceManager::RefreshDevices() +{ + std::unique_lock lck(m_Mtx); + Sdl::SdlPopulateOK = false; + m_Devices.clear(); + lck.unlock(); + XInput::PopulateDevices(); + DInput::PopulateDevices(); + Sdl::PopulateDevices(); + lck.lock(); + m_Cv.wait(lck, []() { + return Sdl::SdlPopulateOK; + }); +} + +std::vector InputDeviceManager::GetDeviceList() const +{ + std::vector dev_list; + std::lock_guard lck(m_Mtx); + + std::for_each(m_Devices.begin(), m_Devices.end(), [&dev_list](const auto& Device) { + dev_list.push_back(Device->GetQualifiedName()); + }); + + return dev_list; +} + +std::shared_ptr InputDeviceManager::FindDevice(std::string& QualifiedName) const +{ + std::lock_guard lck(m_Mtx); + + auto it = std::find_if(m_Devices.begin(), m_Devices.end(), [&QualifiedName](const auto& Device) { + return QualifiedName == Device->GetQualifiedName(); + }); + if (it != m_Devices.end()) { + return *it; + } + else { + return nullptr; + } +} + +std::shared_ptr InputDeviceManager::FindDevice(SDL_JoystickID id) const +{ + std::lock_guard lck(m_Mtx); + + auto it = std::find_if(m_Devices.begin(), m_Devices.end(), [id](const auto& Device) { + return id == Device->GetId(id); + }); + if (it != m_Devices.end()) { + return *it; + } + else { + return nullptr; + } +} + +std::shared_ptr InputDeviceManager::FindDevice(int usb_port, int dummy) const +{ + // Ignore dummy, it's just used to overload the function + + if (usb_port == PORT_INVALID) { + return nullptr; + } + + std::lock_guard lck(m_Mtx); + + auto it = std::find_if(m_Devices.begin(), m_Devices.end(), [usb_port](const auto& Device) { + return Device->GetPort(usb_port); + }); + if (it != m_Devices.end()) { + return *it; + } + else { + return nullptr; + } +} diff --git a/src/common/input/InputManager.h b/src/common/input/InputManager.h new file mode 100644 index 0000000000..f19d2d25ec --- /dev/null +++ b/src/common/input/InputManager.h @@ -0,0 +1,112 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +#ifndef INPUTMANAGER_H_ +#define INPUTMANAGER_H_ + +#include "InputDevice.h" +#include "EmuDevice.h" + +// Prevent a collision with the SetPort provided by Windows +#ifdef WIN32 +#undef SetPort +#endif + +#pragma pack(1) + +// xpad in/out buffers stripped of the first two bytes +struct XpadInput { + uint16_t wButtons; + uint8_t bAnalogButtons[8]; + int16_t sThumbLX; + int16_t sThumbLY; + int16_t sThumbRX; + int16_t sThumbRY; +}; + +struct XpadOutput { + uint16_t left_actuator_strength; + uint16_t right_actuator_strength; +}; + +#pragma pack() + + +class InputDeviceManager +{ +public: + void Initialize(bool is_gui); + void Shutdown(); + // read/write the input/output from/to the device attached to the supplied xbox port + bool UpdateXboxPortInput(int usb_port, void* Buffer, int Direction, int xid_type); + // add the device to the list of availble devices + void AddDevice(std::shared_ptr Device); + // remove the device from the list of availble devices + void RemoveDevice(std::function Callback); + // update device list + void RefreshDevices(); + // get the name of the devices currently detected + std::vector GetDeviceList() const; + // find device from its gui name + std::shared_ptr FindDevice(std::string& QualifiedName) const; + // find device from its sdl id + std::shared_ptr FindDevice(SDL_JoystickID id) const; + // find device from its xbox port + std::shared_ptr FindDevice(int usb_port, int dummy) const; + // attach/detach guest devices to the emulated machine + void UpdateDevices(int port, bool ack); + + +private: + // update input for an xbox controller + bool UpdateInputXpad(std::shared_ptr& Device, void* Buffer, int Direction); + // bind a host device to an emulated device + void BindHostDevice(int port, int usb_port, int type); + // connect a device to the emulated machine + void ConnectDevice(int port, int usb_port, int type); + // disconnect a device from the emulated machine + void DisconnectDevice(int port, int usb_port, bool ack); + + // all enumerated devices currently detected and supported + std::vector> m_Devices; + // These serve double duty. They are used to signal errors during the initialization and + // later to signal that sdl has finished to refresh its devices + mutable std::mutex m_Mtx; + std::condition_variable m_Cv; + // input polling thread + std::thread m_PollingThread; + // used to indicate that the manager is shutting down + bool m_bPendingShutdown; +}; + +extern InputDeviceManager g_InputDeviceManager; + +// hle input functions +bool ConstructHleInputDevice(int Type, int Port); +void DestructHleInputDevice(int Port); + +#endif diff --git a/src/common/input/InputWindow.cpp b/src/common/input/InputWindow.cpp new file mode 100644 index 0000000000..d6d6d8c652 --- /dev/null +++ b/src/common/input/InputWindow.cpp @@ -0,0 +1,465 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +#include "InputWindow.h" +#include "..\..\gui\ResCxbx.h" +#include "common\IPCHybrid.hpp" +#include "EmuShared.h" +#include + +#define INPUT_TIMEOUT 5000 +#define OUTPUT_TIMEOUT 3000 + + +constexpr ControlState INPUT_DETECT_THRESHOLD = 0.55; // arbitrary number, using what Dolphin uses +InputWindow* g_InputWindow = nullptr; +int dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)] = { + XBOX_CTRL_NUM_BUTTONS, + 0, + 0, + 0, + 0, + 0, + 0, +}; + + +void InputWindow::Initialize(HWND hwnd, int port_num, int dev_type) +{ + // Save window/device specific variables + m_hwnd_window = hwnd; + m_hwnd_device_list = GetDlgItem(m_hwnd_window, IDC_DEVICE_LIST); + m_hwnd_profile_list = GetDlgItem(m_hwnd_window, IDC_XID_PROFILE_NAME); + m_dev_type = dev_type; + m_max_num_buttons = dev_num_buttons[dev_type]; + m_port_num = port_num; + m_bHasChanges = false; + + // Set window icon + SetClassLong(m_hwnd_window, GCL_HICON, (LONG)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_CXBX))); + + // Set window title + std::string title; + switch (m_dev_type) + { + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): { + title += "Xbox Controller Duke at port "; + } + break; + + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): { + title += "Xbox Controller S at port "; + } + break; + + default: + break; + } + SendMessage(m_hwnd_window, WM_SETTEXT, 0, + reinterpret_cast((title + std::to_string(PORT_INC(m_port_num))).c_str())); + + // Set the maximum profile name lenght the user can enter in the profile combobox + SendMessage(m_hwnd_profile_list, CB_LIMITTEXT, 49, 0); + + // construct emu device + m_DeviceConfig = new EmuDevice(m_dev_type, m_hwnd_window); + + // Enumerate devices + UpdateDeviceList(); + + // Load currently saved profile for this port/device type + LoadDefaultProfile(); + + // Load currently selected host device + UpdateCurrentDevice(); + + // Load rumble binding + char rumble[30]; + m_DeviceConfig->FindButtonByIndex(m_max_num_buttons - 1)->GetText(rumble, sizeof(rumble)); + m_rumble = rumble; + + // Install the subclass for the profile combobox + SetWindowSubclass(GetWindow(m_hwnd_profile_list, GW_CHILD), ProfileNameSubclassProc, 0, 0); +} + +InputWindow::~InputWindow() +{ + delete m_DeviceConfig; + m_DeviceConfig = nullptr; +} + +bool InputWindow::IsProfileSaved() +{ + if (m_bHasChanges) { + int ret = MessageBox(m_hwnd_window, "Current configuration is not saved. Save before closing?", "Cxbx-Reloaded", MB_YESNOCANCEL | MB_ICONWARNING | MB_APPLMODAL); + switch (ret) + { + case IDYES: { + char name[50]; + SendMessage(m_hwnd_profile_list, WM_GETTEXT, sizeof(name), reinterpret_cast(name)); + if (SaveProfile(std::string(name))) { + return true; + } + return false; + } + + case IDNO: { + return true; + } + + case IDCANCEL: + default: { + return false; + } + + } + } + return true; +} + +void InputWindow::UpdateDeviceList() +{ + g_InputDeviceManager.RefreshDevices(); + + // Populate device list + LRESULT num_devices = SendMessage(m_hwnd_device_list, CB_GETCOUNT, 0, 0); + for (int i = 0; i < num_devices; i++) { + SendMessage(m_hwnd_device_list, CB_DELETESTRING, 0, 0); + } + + std::vector dev_list = g_InputDeviceManager.GetDeviceList(); + for (const auto& str : dev_list) { + SendMessage(m_hwnd_device_list, CB_ADDSTRING, 0, reinterpret_cast(str.c_str())); + } + if (!dev_list.empty()) { + SendMessage(m_hwnd_device_list, CB_SETCURSEL, 0, 0); + } + + UpdateCurrentDevice(); +} + +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file of Dolphin at https://github.com/dolphin-emu/dolphin/blob/master/license.txt. + +// DetectInput is derived from InputReference::Detect() in ControlReference.cpp of Dolphin emulator +// https://github.com/dolphin-emu/dolphin + +InputDevice::Input* InputWindow::DetectInput(InputDevice* const Device, int ms) +{ + using namespace std::chrono; + + // The intent of the initial_states vector is to detect inputs that were pressed already when this function was called. + // Without it, the initial mouse click used to select a gui button is very likely to be registered as valid input and bound + std::vector::const_iterator i = Device->GetInputs().begin(), + e = Device->GetInputs().end(), b = i; + std::vector initial_states(Device->GetInputs().size()); + for (std::vector::iterator state = initial_states.begin(); i != e; i++) { + *state++ = ((*i)->GetState() > (1 - INPUT_DETECT_THRESHOLD)); + } + + auto now = system_clock::now(); + auto timeout = now + milliseconds(ms); + + while (now <= timeout) { + Device->UpdateInput(); + std::vector::iterator state = initial_states.begin(); + for (; i != e; i++, state++) { + if ((*i)->IsDetectable() && (*i)->GetState() > INPUT_DETECT_THRESHOLD) { + if (*state == false) { + // input was not initially pressed or it was but released afterwards + return *i; + } + } + else if ((*i)->GetState() < (1 - INPUT_DETECT_THRESHOLD)) { + *state = false; + } + } + std::this_thread::sleep_for(milliseconds(10)); + now += milliseconds(10); + i = b; + } + + return nullptr; // no input +} + +void InputWindow::BindButton(int ControlID) +{ + auto dev = g_InputDeviceManager.FindDevice(m_host_dev); + if (dev != nullptr) { + // Don't block the message processing loop + std::thread([this, dev, ControlID]() { + EnableWindow(m_hwnd_window, FALSE); + char current_text[30]; + Button* xbox_button = m_DeviceConfig->FindButtonById(ControlID); + xbox_button->GetText(current_text, sizeof(current_text)); + xbox_button->UpdateText("..."); + std::future fut = std::async(std::launch::async, &InputWindow::DetectInput, this, dev.get(), INPUT_TIMEOUT); + InputDevice::Input* dev_button = fut.get(); + if (dev_button) { + xbox_button->UpdateText(dev_button->GetName().c_str()); + m_bHasChanges = true; + } + else { + xbox_button->UpdateText(current_text); + } + EnableWindow(m_hwnd_window, TRUE); + }).detach(); + } +} + +void InputWindow::BindXInput() +{ + if (std::strncmp(m_host_dev.c_str(), "XInput", std::strlen("XInput")) == 0) { + m_DeviceConfig->BindXInput(); + m_bHasChanges = true; + } +} + +void InputWindow::ClearBindings() +{ + m_DeviceConfig->ClearButtons(); + m_rumble = std::string(); + m_bHasChanges = true; +} + +InputWindow::ProfileIt InputWindow::FindProfile(std::string& name) +{ + auto it = std::find_if(g_Settings->m_input_profiles[m_dev_type].begin(), + g_Settings->m_input_profiles[m_dev_type].end(), [&name](const auto& profile) { + return profile.ProfileName == name; + }); + return it; +} + +void InputWindow::UpdateProfile(std::string& name, int command) +{ + switch (command) + { + case PROFILE_LOAD: { + LoadProfile(name); + } + break; + + case PROFILE_SAVE: { + SaveProfile(name); + } + break; + + case PROFILE_DELETE: { + DeleteProfile(name); + } + break; + + case RUMBLE_CLEAR: { + m_rumble = std::string(); + } + break; + + case BUTTON_CLEAR: { + m_bHasChanges = true; + } + break; + + default: + break; + } +} + +void InputWindow::LoadProfile(std::string& name) +{ + ProfileIt profile = FindProfile(name); + if (profile == g_Settings->m_input_profiles[m_dev_type].end()) { + return; + } + m_host_dev = profile->DeviceName; + LRESULT dev_str_index = SendMessage(m_hwnd_device_list, CB_FINDSTRINGEXACT, 1, reinterpret_cast(m_host_dev.c_str())); + if (dev_str_index == CB_ERR) { + SendMessage(m_hwnd_device_list, CB_ADDSTRING, 0, reinterpret_cast(m_host_dev.c_str())); + } + else { + SendMessage(m_hwnd_device_list, CB_SETCURSEL, dev_str_index, 0); + } + SendMessage(m_hwnd_profile_list, CB_SETCURSEL, SendMessage(m_hwnd_profile_list, CB_FINDSTRINGEXACT, 1, + reinterpret_cast(profile->ProfileName.c_str())), 0); + for (int index = 0; index < m_max_num_buttons; index++) { + m_DeviceConfig->FindButtonByIndex(index)->UpdateText(profile->ControlList[index].c_str()); + } + g_Settings->m_input[m_port_num].DeviceName = profile->DeviceName; + g_Settings->m_input[m_port_num].ProfileName = profile->ProfileName; + m_bHasChanges = false; +} + +bool InputWindow::SaveProfile(std::string& name) +{ + if (name == std::string()) { + MessageBox(m_hwnd_window, "Cannot save. Profile name must not be empty", "Cxbx-Reloaded", MB_OK | MB_ICONSTOP | MB_APPLMODAL); + return false; + } + if (m_host_dev == std::string()) { + MessageBox(m_hwnd_window, "Cannot save. No input devices detected", "Cxbx-Reloaded", MB_OK | MB_ICONSTOP | MB_APPLMODAL); + return false; + } + OverwriteProfile(name); + Settings::s_input_profiles profile; + profile.Type = m_dev_type; + profile.ProfileName = name; + profile.DeviceName = m_host_dev; + for (int index = 0; index < m_max_num_buttons; index++) { + char dev_button[30]; + m_DeviceConfig->FindButtonByIndex(index)->GetText(dev_button, sizeof(dev_button)); + profile.ControlList.push_back(dev_button); + } + SendMessage(m_hwnd_profile_list, CB_SETCURSEL, SendMessage(m_hwnd_profile_list, CB_ADDSTRING, 0, + reinterpret_cast(profile.ProfileName.c_str())), 0); + g_Settings->m_input[m_port_num].DeviceName = profile.DeviceName; + g_Settings->m_input[m_port_num].ProfileName = profile.ProfileName; + g_Settings->m_input_profiles[m_dev_type].push_back(std::move(profile)); + m_bHasChanges = false; + return true; +} + +void InputWindow::DeleteProfile(std::string& name) +{ + ProfileIt profile = FindProfile(name); + if (profile == g_Settings->m_input_profiles[m_dev_type].end()) { + return; + } + SendMessage(m_hwnd_profile_list, CB_DELETESTRING, SendMessage(m_hwnd_profile_list, CB_FINDSTRINGEXACT, 1, + reinterpret_cast(profile->ProfileName.c_str())), 0); + if (profile->ProfileName == g_Settings->m_input[m_port_num].ProfileName) { + SendMessage(m_hwnd_profile_list, CB_SETCURSEL, -1, 0); + UpdateCurrentDevice(); + ClearBindings(); + g_Settings->m_input[m_port_num].DeviceName = ""; + g_Settings->m_input[m_port_num].ProfileName = ""; + m_bHasChanges = false; + } + else { + LoadProfile(g_Settings->m_input[m_port_num].ProfileName); + } + g_Settings->m_input_profiles[m_dev_type].erase(profile); +} + +void InputWindow::OverwriteProfile(std::string& name) +{ + ProfileIt profile = FindProfile(name); + if (profile == g_Settings->m_input_profiles[m_dev_type].end()) { + return; + } + SendMessage(m_hwnd_profile_list, CB_DELETESTRING, SendMessage(m_hwnd_profile_list, CB_FINDSTRINGEXACT, 1, + reinterpret_cast(profile->ProfileName.c_str())), 0); + SendMessage(m_hwnd_profile_list, CB_SETCURSEL, -1, 0); + g_Settings->m_input_profiles[m_dev_type].erase(profile); +} + +void InputWindow::LoadDefaultProfile() +{ + for (unsigned int index = 0; index < g_Settings->m_input_profiles[m_dev_type].size(); index++) { + SendMessage(m_hwnd_profile_list, CB_ADDSTRING, 0, + reinterpret_cast(g_Settings->m_input_profiles[m_dev_type][index].ProfileName.c_str())); + } + LoadProfile(g_Settings->m_input[m_port_num].ProfileName); +} + +void InputWindow::UpdateCurrentDevice() +{ + char device_name[50]; + SendMessage(m_hwnd_device_list, WM_GETTEXT, sizeof(device_name), reinterpret_cast(device_name)); + m_host_dev = device_name; +} + +void InputWindow::InitRumble(HWND hwnd) +{ + m_hwnd_rumble = hwnd; + m_hwnd_rumble_list = GetDlgItem(m_hwnd_rumble, IDC_RUMBLE_LIST); + SendMessage(m_hwnd_rumble_list, CB_ADDSTRING, 0, reinterpret_cast("")); + auto dev = g_InputDeviceManager.FindDevice(m_host_dev); + if (dev != nullptr) { + auto outputs = dev->GetOutputs(); + for (const auto out : outputs) { + SendMessage(m_hwnd_rumble_list, CB_ADDSTRING, 0, reinterpret_cast(out->GetName().c_str())); + } + } + SendMessage(m_hwnd_rumble_list, CB_SETCURSEL, SendMessage(m_hwnd_rumble_list, CB_FINDSTRINGEXACT, 1, + reinterpret_cast(m_rumble.c_str())), 0); +} + +void InputWindow::UpdateRumble(int command) +{ + switch (command) + { + case RUMBLE_SET: { + char rumble[30]; + SendMessage(m_hwnd_rumble_list, WM_GETTEXT, sizeof(rumble), reinterpret_cast(rumble)); + m_rumble = rumble; + } + break; + + case RUMBLE_UPDATE: { + m_DeviceConfig->FindButtonByIndex(m_max_num_buttons - 1)->UpdateText(m_rumble.c_str()); + } + break; + + case RUMBLE_TEST: { + DetectOutput(OUTPUT_TIMEOUT); + } + break; + + default: + break; + } +} + +void InputWindow::DetectOutput(int ms) +{ + if (m_rumble == std::string()) { + return; + } + auto dev = g_InputDeviceManager.FindDevice(m_host_dev); + if (dev != nullptr) { + // Don't block the message processing loop + std::thread([this, dev, ms]() { + EnableWindow(m_hwnd_rumble, FALSE); + SendMessage(m_hwnd_rumble_list, WM_SETTEXT, 0, reinterpret_cast("...")); + auto outputs = dev->GetOutputs(); + for (const auto out : outputs) { + if (out->GetName() == m_rumble) { + out->SetState(1.0, 1.0); + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); + for (const auto out : outputs) { + if (out->GetName() == m_rumble) { + out->SetState(0.0, 0.0); + } + } + SendMessage(m_hwnd_rumble_list, WM_SETTEXT, 0, reinterpret_cast("Test")); + EnableWindow(m_hwnd_rumble, TRUE); + }).detach(); + } +} diff --git a/src/common/input/InputWindow.h b/src/common/input/InputWindow.h new file mode 100644 index 0000000000..0c6702f41f --- /dev/null +++ b/src/common/input/InputWindow.h @@ -0,0 +1,100 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +#pragma once + +#include "InputManager.h" +#include "common\Settings.hpp" +#include + +#define PROFILE_LOAD 1 +#define PROFILE_SAVE 2 +#define PROFILE_DELETE 3 +#define RUMBLE_SET 4 +#define RUMBLE_UPDATE 5 +#define RUMBLE_TEST 6 +#define RUMBLE_CLEAR 7 +#define BUTTON_CLEAR 8 + + +LRESULT CALLBACK ProfileNameSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); + + +class InputWindow +{ +public: + void Initialize(HWND hwnd, int port_num, int dev_type); + void InitRumble(HWND hwnd); + ~InputWindow(); + void UpdateDeviceList(); + void BindButton(int ControlID); + void BindXInput(); + void ClearBindings(); + void UpdateProfile(std::string& name, int command); + void UpdateRumble(int command); + void UpdateCurrentDevice(); + bool IsProfileSaved(); + + +private: + typedef std::vector::iterator ProfileIt; + InputDevice::Input* DetectInput(InputDevice* const Device, int ms); + void DetectOutput(int ms); + ProfileIt FindProfile(std::string& name); + void LoadProfile(std::string& name); + bool SaveProfile(std::string& name); + void DeleteProfile(std::string& name); + void OverwriteProfile(std::string& name); + void LoadDefaultProfile(); + + // xbox device under configuration + EmuDevice* m_DeviceConfig; + // handle of the window + HWND m_hwnd_window; + // handle of the device list combobox + HWND m_hwnd_device_list; + // handle of the profile list combobox + HWND m_hwnd_profile_list; + // handle of the rumble window + HWND m_hwnd_rumble; + // handle of the rumble combobox + HWND m_hwnd_rumble_list; + // type of the device + int m_dev_type; + // num of buttons of device under configuration + int m_max_num_buttons; + // xbox port number the host device attaches to (0 - 3) + int m_port_num; + // host device under configuration + std::string m_host_dev; + // currently selected rumble control + std::string m_rumble; + // indicates if the current profile has unsaved changes + bool m_bHasChanges; +}; + +extern InputWindow* g_InputWindow; diff --git a/src/common/input/SDL2_Device.cpp b/src/common/input/SDL2_Device.cpp deleted file mode 100644 index 82fce968d9..0000000000 --- a/src/common/input/SDL2_Device.cpp +++ /dev/null @@ -1,212 +0,0 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -// ****************************************************************** -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2018 ergo720 -// * -// * All rights reserved -// * -// ****************************************************************** - -#if 0 // Reenable this when LLE USB actually works -#include "SDL2_Device.h" -#include - - -int SDL2Devices::GetBoundButton(int sdl_key) -{ - int i; - - for (i = 0; i < 8; i++) { - if (m_ButtonMap_Analog[i][1] == sdl_key) { - return m_ButtonMap_Analog[i][0]; - } - } - - for (i = 0; i < 8; i++) { - if (m_ButtonMap_Binary[i][1] == sdl_key) { - return m_ButtonMap_Binary[i][0]; - } - } - - if (m_HatIndex == sdl_key) { - return m_HatIndex; - } - - for (i = 0; i < 4; i++) { - if (m_AxisMap[i][1] == sdl_key) { - return m_AxisMap[i][0]; - } - } - - return GAMEPAD_INVALID; -} - -void SDL2Devices::UpdateAnalogButtonState(uint8_t xbox_button, uint8_t state) -{ - for (int i = 0; i < 6; i++) { - if (m_ButtonMap_Analog[i][0] == xbox_button) { - // At the moment, we don't support intermediate values for the analog buttons, so report them as full pressed or released - m_State.bAnalogButtons[m_ButtonMap_Analog[i][0]] = state ? 0xFF : 0; - bStateDirty = true; - return; - } - } - - if (xbox_button == GAMEPAD_LEFT_TRIGGER) { - m_State.bAnalogButtons[m_ButtonMap_Analog[6][0]] = SDL_JoystickGetAxis(m_Joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT) >> 8; - bStateDirty = true; - return; - } - - if (xbox_button == GAMEPAD_RIGHT_TRIGGER) { - m_State.bAnalogButtons[m_ButtonMap_Analog[7][0]] = SDL_JoystickGetAxis(m_Joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT) >> 8; - bStateDirty = true; - return; - } - - assert(0); -} - -void SDL2Devices::UpdateDigitalButtonState(uint8_t xbox_button, uint8_t state) -{ - for (int i = 0; i < 8; i++) { - if (m_ButtonMap_Binary[i][0] == xbox_button) { - if (state) { - m_State.wButtons |= BUTTON_MASK(m_ButtonMap_Binary[i][0]); - bStateDirty = true; - return; - } - else { - m_State.wButtons &= ~(BUTTON_MASK(m_ButtonMap_Binary[i][0])); - bStateDirty = true; - return; - } - } - } - - assert(0); -} - -void SDL2Devices::UpdateHatState(uint8_t state) -{ - m_State.wButtons &= ~0xF; - - switch (state) - { - case SDL_HAT_LEFTUP: { - m_State.wButtons |= (BUTTON_MASK(m_ButtonMap_Binary[4][0]) | BUTTON_MASK(m_ButtonMap_Binary[6][0])); - break; - } - - case SDL_HAT_UP: { - m_State.wButtons |= BUTTON_MASK(m_ButtonMap_Binary[4][0]); - break; - } - - case SDL_HAT_RIGHTUP: { - m_State.wButtons |= (BUTTON_MASK(m_ButtonMap_Binary[4][0]) | BUTTON_MASK(m_ButtonMap_Binary[7][0])); - break; - } - - case SDL_HAT_RIGHT: { - m_State.wButtons |= (BUTTON_MASK(m_ButtonMap_Binary[7][0])); - break; - } - - case SDL_HAT_RIGHTDOWN: { - m_State.wButtons |= (BUTTON_MASK(m_ButtonMap_Binary[7][0]) | BUTTON_MASK(m_ButtonMap_Binary[5][0])); - break; - } - - case SDL_HAT_DOWN: { - m_State.wButtons |= (BUTTON_MASK(m_ButtonMap_Binary[5][0])); - break; - } - - case SDL_HAT_LEFTDOWN: { - m_State.wButtons |= (BUTTON_MASK(m_ButtonMap_Binary[5][0]) | BUTTON_MASK(m_ButtonMap_Binary[6][0])); - break; - } - - case SDL_HAT_LEFT: { - m_State.wButtons |= (BUTTON_MASK(m_ButtonMap_Binary[6][0])); - break; - } - - case SDL_HAT_CENTERED: { - break; - } - - default: - assert(0); - } - - bStateDirty = true; -} - -void SDL2Devices::UpdateAxisState(uint8_t xbox_button, int16_t state) -{ - switch (xbox_button) - { - case GAMEPAD_LEFT_THUMB_X: { - m_State.sThumbLX = state; - break; - } - - case GAMEPAD_LEFT_THUMB_Y: { - m_State.sThumbLY = -state - 1; // not sure of this yet - break; - } - - case GAMEPAD_RIGHT_THUMB_X: { - m_State.sThumbRX = state; - break; - } - - case GAMEPAD_RIGHT_THUMB_Y: { - m_State.sThumbRY = -state - 1; // not sure of this yet - break; - } - - default: - assert(0); - } -} - -bool SDL2Devices::ReadButtonState(uint16_t* wButtons, uint8_t* bAnalogButtons, int16_t* sThumbLX, - int16_t* sThumbLY, int16_t* sThumbRX, int16_t* sThumbRY) -{ - if (bStateDirty) { - *wButtons = m_State.wButtons.load(); - *sThumbLX = m_State.sThumbLX.load(); - *sThumbLY = m_State.sThumbLY.load(); - *sThumbRX = m_State.sThumbRX.load(); - *sThumbRY = m_State.sThumbRY.load(); - for (int i = 0; i < 8; ++i) { - bAnalogButtons[i] = m_State.bAnalogButtons[i].load(); - } - bStateDirty = false; - return true; - } - return false; -} - -#endif diff --git a/src/common/input/SDL2_Device.h b/src/common/input/SDL2_Device.h deleted file mode 100644 index f8ffb5ad59..0000000000 --- a/src/common/input/SDL2_Device.h +++ /dev/null @@ -1,114 +0,0 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -// ****************************************************************** -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2018 ergo720 -// * -// * All rights reserved -// * -// ****************************************************************** - -#ifndef SDL2DEVICE_H_ -#define SDL2DEVICE_H_ -#if 0 // Reenable this when LLE USB actually works -#include "InputConfig.h" - - -/* Button state, analogous to XIDGamepadReport */ -struct ButtonState { - std::atomic_uint16_t wButtons; // all non-analog buttons - std::atomic_uint8_t bAnalogButtons[8]; // X, Y, A, B, white, black, left/right trigger - std::atomic_int16_t sThumbLX; // analog stick, left X - std::atomic_int16_t sThumbLY; // analog stick, left Y - std::atomic_int16_t sThumbRX; // analog stick, right X - std::atomic_int16_t sThumbRY; // analog stick, right Y -}; - - -class SDL2Devices -{ - public: - // index of this joystick - int m_Index; - // joystick object as used by SDL - SDL_Joystick* m_Joystick; - // id of this controller - SDL_JoystickID m_jyID; - // attach/detach state of this joystick - int m_Attached; - // indicates the xbox device emulated by this joystick - int m_Type = DEVICE_INVALID; - - // update analog button state - void UpdateAnalogButtonState(uint8_t xbox_button, uint8_t state); - // update digital button state - void UpdateDigitalButtonState(uint8_t xbox_button, uint8_t state); - // update hat state - void UpdateHatState(uint8_t state); - // update axis state - void UpdateAxisState(uint8_t xbox_button, int16_t state); - // returns the xbox button bound with the sdl key provided - int GetBoundButton(int sdl_key); - // update bBindingsChanged flag - void SetChangedBinding(bool bFlag) { m_bBindingsChanged = bFlag; } - // read the current button state of a device - bool ReadButtonState(uint16_t* wButtons, uint8_t* bAnalogButtons, int16_t* sThumbLX, - int16_t* sThumbLY, int16_t* sThumbRX, int16_t* sThumbRY); - - - private: - // default bindings (hardcoded for now) - const int m_ButtonMap_Analog[8][2] = { - { GAMEPAD_A, SDL_CONTROLLER_BUTTON_A }, - { GAMEPAD_B, SDL_CONTROLLER_BUTTON_B }, - { GAMEPAD_X, SDL_CONTROLLER_BUTTON_X }, - { GAMEPAD_Y, SDL_CONTROLLER_BUTTON_Y }, - { GAMEPAD_BLACK, SDL_CONTROLLER_BUTTON_LEFTSHOULDER }, - { GAMEPAD_WHITE, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER }, - { GAMEPAD_LEFT_TRIGGER, SDL_CONTROLLER_AXIS_TRIGGERLEFT }, - { GAMEPAD_RIGHT_TRIGGER, SDL_CONTROLLER_AXIS_TRIGGERRIGHT }, - }; - const int m_ButtonMap_Binary[8][2] = { - { GAMEPAD_BACK, SDL_CONTROLLER_BUTTON_BACK }, - { GAMEPAD_START, SDL_CONTROLLER_BUTTON_START }, - { GAMEPAD_LEFT_THUMB, SDL_CONTROLLER_BUTTON_LEFTSTICK }, - { GAMEPAD_RIGHT_THUMB, SDL_CONTROLLER_BUTTON_RIGHTSTICK }, - { GAMEPAD_DPAD_UP, SDL_CONTROLLER_BUTTON_DPAD_UP }, - { GAMEPAD_DPAD_DOWN, SDL_CONTROLLER_BUTTON_DPAD_DOWN }, - { GAMEPAD_DPAD_LEFT, SDL_CONTROLLER_BUTTON_DPAD_LEFT }, - { GAMEPAD_DPAD_RIGHT, SDL_CONTROLLER_BUTTON_DPAD_RIGHT }, - }; - const int m_AxisMap[4][2] = { - { GAMEPAD_LEFT_THUMB_X, 0 }, - { GAMEPAD_LEFT_THUMB_Y, 1 }, - { GAMEPAD_RIGHT_THUMB_X, 4 }, - { GAMEPAD_RIGHT_THUMB_Y, 2 }, - }; - // m_HatIndex is added to HAT_CONSTANT to avoid collisions between it and the sdl button indices - int m_HatIndex = HAT_CONSTANT; - // current button state of this joystick - ButtonState m_State; - // signals that the current bindings should be updated - std::atomic_bool m_bBindingsChanged; - // indicates that the button state has been updated since the last time it was read - std::atomic_bool bStateDirty; -}; -#endif -#endif diff --git a/src/common/input/SdlJoystick.cpp b/src/common/input/SdlJoystick.cpp new file mode 100644 index 0000000000..9122aed223 --- /dev/null +++ b/src/common/input/SdlJoystick.cpp @@ -0,0 +1,532 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +// Copyright 2010 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file of Dolphin at https://github.com/dolphin-emu/dolphin/blob/master/license.txt. + +// Derived from SDL.cpp of Dolphin emulator +// https://github.com/dolphin-emu/dolphin + +#define LOG_PREFIX CXBXR_MODULE::SDL + +#include +#include +#include "core\kernel\support\Emu.h" +#include "core\kernel\init\CxbxKrnl.h" +#include "SdlJoystick.h" +#include "XInputPad.h" +#include "DInputKeyboardMouse.h" +#include "InputManager.h" + +// These values are those used by Dolphin! +static const uint16_t RUMBLE_PERIOD = 10; +static const uint16_t RUMBLE_LENGTH_MAX = 500; + + +namespace Sdl +{ + uint32_t ExitEvent_t; + uint32_t PopulateEvent_t; + uint32_t UpdateInputEvent_t; + uint32_t DeviceRemoveAck_t; + int SdlInitStatus = SDL_NOT_INIT; + bool SdlPopulateOK = false; + + void Init(std::mutex& Mtx, std::condition_variable& Cv) + { + SDL_Event Event; + uint32_t CustomEvent_t; + std::unique_lock lck(Mtx); + + if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) < 0) { + EmuLog(LOG_LEVEL::ERROR2, "Failed to initialize SDL subsystem! The error was: %s", SDL_GetError()); + SdlInitStatus = SDL_INIT_ERROR; + lck.unlock(); + Cv.notify_one(); + return; + } + CustomEvent_t = SDL_RegisterEvents(4); + if (CustomEvent_t == (uint32_t)-1) { + SDL_Quit(); + EmuLog(LOG_LEVEL::ERROR2, "Failed to create SDL custom events!"); + SdlInitStatus = SDL_INIT_ERROR; + lck.unlock(); + Cv.notify_one(); + return; + } + ExitEvent_t = CustomEvent_t; + PopulateEvent_t = CustomEvent_t + 1; + UpdateInputEvent_t = CustomEvent_t + 2; + DeviceRemoveAck_t = CustomEvent_t + 3; + + SetThreadAffinityMask(GetCurrentThread(), g_CPUOthers); + + // Drain all joystick add/remove events to avoid creating duplicated + // devices when we call PopulateDevices + while (SDL_PollEvent(&Event)) + { + switch (Event.type) + { + case SDL_JOYDEVICEADDED: { break; } + case SDL_JOYDEVICEREMOVED: { break; } + default: + break; + } + } + SdlInitStatus = SDL_INIT_SUCCESS; + lck.unlock(); + Cv.notify_one(); + + while (SDL_WaitEvent(&Event)) + { + if (Event.type == SDL_JOYDEVICEADDED) { + OpenSdlDevice(Event.jdevice.which); + } + else if (Event.type == SDL_JOYDEVICEREMOVED) { + CloseSdlDevice(Event.jdevice.which); + } + else if (Event.type == SDL_JOYAXISMOTION || + Event.type == SDL_JOYHATMOTION || + Event.type == SDL_JOYBALLMOTION || + Event.type == SDL_JOYBUTTONDOWN || + Event.type == SDL_JOYBUTTONUP) { + SDL_JoystickID id; + switch (Event.type) + { + case SDL_JOYAXISMOTION: + id = Event.jaxis.which; + break; + + case SDL_JOYHATMOTION: + id = Event.jhat.which; + break; + + case SDL_JOYBALLMOTION: + id = Event.jball.which; + break; + + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + id = Event.jbutton.which; + break; + + default: { + // unreachable + } + } + auto dev = g_InputDeviceManager.FindDevice(id); + if (dev != nullptr) { + dynamic_cast(dev.get())->SetDirty(); + } + } + else if (Event.type == PopulateEvent_t) { + for (int i = 0; i < SDL_NumJoysticks(); i++) { + OpenSdlDevice(i); + } + SdlPopulateOK = true; + Cv.notify_one(); + } + else if (Event.type == ExitEvent_t) { + break; + } + else if (Event.type == UpdateInputEvent_t) { + XInput::GetDeviceChanges(); + DInput::GetDeviceChanges(); + g_InputDeviceManager.UpdateDevices(*static_cast(Event.user.data1), false); + delete Event.user.data1; + Event.user.data1 = nullptr; + } + else if (Event.type == DeviceRemoveAck_t) { + g_InputDeviceManager.UpdateDevices(*static_cast(Event.user.data1), true); + delete Event.user.data1; + Event.user.data1 = nullptr; + } + } + + SDL_Quit(); + } + + void DeInit(std::thread& Thr) + { + SdlInitStatus = SDL_NOT_INIT; + if (!Thr.joinable()) { + return; + } + + SDL_Event ExitEvent; + SDL_memset(&ExitEvent, 0, sizeof(SDL_Event)); + ExitEvent.type = ExitEvent_t; + SDL_PushEvent(&ExitEvent); + + Thr.join(); + } + + void OpenSdlDevice(const int Index) + { + SDL_Joystick* pJoystick = SDL_JoystickOpen(Index); + if (pJoystick) { + auto Device = std::make_shared(pJoystick, Index); + if (Device->IsXInput()) { + EmuLog(LOG_LEVEL::INFO, "Rejected joystick %i. It will be handled by XInput", Index); + return; + } + // only add the device if it has some I/O controls + if (!Device->GetInputs().empty() || !Device->GetOutputs().empty()) { + g_InputDeviceManager.AddDevice(std::move(Device)); + } + else { + EmuLog(LOG_LEVEL::INFO, "Rejected joystick %i. No controls detected", Index); + } + } + else { + EmuLog(LOG_LEVEL::ERROR2, "Failed to open joystick %i. The error was %s", Index, SDL_GetError()); + } + } + + void CloseSdlDevice(const int Index) + { + g_InputDeviceManager.RemoveDevice([&Index](const auto& Device) { + const SdlJoystick* joystick = dynamic_cast(Device); + return joystick && SDL_JoystickInstanceID(joystick->GetSDLJoystick()) == Index; + }); + } + + void PopulateDevices() + { + SDL_Event PopulateEvent; + SDL_memset(&PopulateEvent, 0, sizeof(SDL_Event)); + PopulateEvent.type = PopulateEvent_t; + SDL_PushEvent(&PopulateEvent); + } + + SdlJoystick::SdlJoystick(SDL_Joystick* const Joystick, const int Index) + : m_Joystick(Joystick), m_Sdl_ID(SDL_JoystickInstanceID(Joystick)), + m_DeviceName(StripSpaces(SDL_JoystickNameForIndex(Index))), m_bIsXInput(false) + { + uint8_t i; + int NumButtons, NumAxes, NumHats, NumBalls; + std::string lcasename; + + // From Dolphin: + // "really bad HACKS: do not use SDL for an XInput device, + // too many people on the forums pick the SDL device and ask: + // "why don't my 360 gamepad triggers/rumble work correctly?". + // Checking the name is probably good (and hacky) enough, + // but I'll double check with the num of buttons/axes" + // ergo720: also added check for xbox one and generic xinput controllers + lcasename = GetDeviceName(); + std::transform(lcasename.begin(), lcasename.end(), lcasename.begin(), tolower); + NumButtons = SDL_JoystickNumButtons(Joystick); + NumAxes = SDL_JoystickNumAxes(Joystick); + NumHats = SDL_JoystickNumHats(Joystick); + NumBalls = SDL_JoystickNumBalls(Joystick); + + if ((std::string::npos != lcasename.find("xbox 360")) && + (10 == NumButtons) && (5 == NumAxes) && + (1 == NumHats) && (0 == NumBalls)) + { + // this device won't be used + m_bIsXInput = true; + return; + } + /* FIXME: is this correct? */ + else if ((std::string::npos != lcasename.find("xbox one")) && + (10 == NumButtons) && (5 == NumAxes) && + (1 == NumHats) && (0 == NumBalls)) + { + // this device won't be used + m_bIsXInput = true; + return; + } + else if (std::string::npos != lcasename.find("xinput")) + { + // this device won't be used + m_bIsXInput = true; + return; + } + else if (NumButtons > 255 || NumAxes > 255 || + NumHats > 255 || NumBalls > 255) + { + // From Dolphin: + // "This device is invalid, don't use it. + // Some crazy devices (HP webcam 2100) end up as HID devices. + // SDL tries parsing these as joysticks" + return; + } + + // get buttons + for (i = 0; i != NumButtons; ++i) { + AddInput(new Button(i, m_Joystick)); + } + + // get hats + for (i = 0; i != NumHats; ++i) { + // each hat gets 4 input instances associated with it (up down left right) + for (uint8_t d = 0; d != 4; ++d) { + AddInput(new Hat(i, m_Joystick, d)); + } + } + + // get axes + for (i = 0; i != NumAxes; ++i) { + // each axis gets a negative and a positive input instance associated with it + AddAnalogInputs(new Axis(i, m_Joystick, -32768), new Axis(i, m_Joystick, 32767)); + } + + // try to get supported ff effects + m_Haptic = SDL_HapticOpenFromJoystick(m_Joystick); + if (m_Haptic) + { + const unsigned int SupportedEffects = SDL_HapticQuery(m_Haptic); + + // constant effect + if (SupportedEffects & SDL_HAPTIC_CONSTANT) { + AddOutput(new ConstantEffect(m_Haptic)); + } + + // ramp effect + if (SupportedEffects & SDL_HAPTIC_RAMP) { + AddOutput(new RampEffect(m_Haptic)); + } + + // sine effect + if (SupportedEffects & SDL_HAPTIC_SINE) { + AddOutput(new SineEffect(m_Haptic)); + } + + // triangle effect + if (SupportedEffects & SDL_HAPTIC_TRIANGLE) { + AddOutput(new TriangleEffect(m_Haptic)); + } + + // left-right effect + if (SupportedEffects & SDL_HAPTIC_LEFTRIGHT) { + AddOutput(new LeftRightEffect(m_Haptic)); + } + } + else { + EmuLog(LOG_LEVEL::INFO, "Joystick %i doesn't support any haptic effects", Index); + } + + // init dirty flag + m_bDirty = false; + } + + SdlJoystick::~SdlJoystick() + { + if (m_Haptic) + { + // stop/destroy all effects + SDL_HapticStopAll(m_Haptic); + // close haptic first + SDL_HapticClose(m_Haptic); + } + + // close joystick + SDL_JoystickClose(m_Joystick); + } + + std::string SdlJoystick::GetDeviceName() const + { + return m_DeviceName; + } + + std::string SdlJoystick::GetAPI() const + { + return "SDL"; + } + + SDL_Joystick* SdlJoystick::GetSDLJoystick() const + { + return m_Joystick; + } + + SDL_JoystickID SdlJoystick::GetId(SDL_JoystickID id) const + { + // ignore id argument + return m_Sdl_ID; + } + + bool SdlJoystick::UpdateInput() + { + SDL_JoystickUpdate(); + if (m_bDirty) { + m_bDirty = false; + return true; + } + return m_bDirty; + } + + std::string SdlJoystick::ConstantEffect::GetName() const + { + return "Constant"; + } + + std::string SdlJoystick::RampEffect::GetName() const + { + return "Ramp"; + } + + std::string SdlJoystick::SineEffect::GetName() const + { + return "Sine"; + } + + std::string SdlJoystick::TriangleEffect::GetName() const + { + return "Triangle"; + } + + std::string SdlJoystick::LeftRightEffect::GetName() const + { + return "LeftRight"; + } + + std::string SdlJoystick::Button::GetName() const + { + std::ostringstream ss; + ss << "Button " << (int)m_Index; + return ss.str(); + } + + std::string SdlJoystick::Axis::GetName() const + { + std::ostringstream ss; + ss << "Axis " << (int)m_Index << (m_Range < 0 ? '-' : '+'); + return ss.str(); + } + + std::string SdlJoystick::Hat::GetName() const + { + static char tmpstr[] = "Hat . ."; + // From Dolphin: "I don't think more than 10 hats are supported" + tmpstr[4] = (char)('0' + m_Index); + tmpstr[6] = "NESW"[m_Direction]; + return tmpstr; + } + + ControlState SdlJoystick::Button::GetState() const + { + return SDL_JoystickGetButton(m_Js, m_Index); + } + + ControlState SdlJoystick::Axis::GetState() const + { + return std::max(0.0, ControlState(SDL_JoystickGetAxis(m_Js, m_Index)) / m_Range); + } + + ControlState SdlJoystick::Hat::GetState() const + { + return (SDL_JoystickGetHat(m_Js, m_Index) & (1 << m_Direction)) > 0; + } + + void SdlJoystick::HapticEffect::SetState(ControlState StateLeft, ControlState StateRight) + { + memset(&m_Effect, 0, sizeof(m_Effect)); + if (StateLeft || StateRight) + { + SetSDLHapticEffect(StateLeft, StateRight); + } + else + { + // this module uses type==0 to indicate 'off' + m_Effect.type = 0; + } + Update(); + } + + void SdlJoystick::HapticEffect::Update() + { + if (m_ID == -1 && m_Effect.type > 0) + { + m_ID = SDL_HapticNewEffect(m_Haptic, &m_Effect); + if (m_ID > -1) { + SDL_HapticRunEffect(m_Haptic, m_ID, 1); + } + } + else if (m_ID > -1 && m_Effect.type == 0) + { + SDL_HapticStopEffect(m_Haptic, m_ID); + SDL_HapticDestroyEffect(m_Haptic, m_ID); + m_ID = -1; + } + else if (m_ID > -1) + { + SDL_HapticUpdateEffect(m_Haptic, m_ID, &m_Effect); + } + } + + // I'm not really sure if a simple arithmetic mean is enough here, if someone has a better idea they are welcome + // to change the code below + void SdlJoystick::ConstantEffect::SetSDLHapticEffect(ControlState StateLeft, ControlState StateRight) + { + m_Effect.type = SDL_HAPTIC_CONSTANT; + m_Effect.constant.length = RUMBLE_LENGTH_MAX; + m_Effect.constant.level = (Sint16)(((StateLeft + StateRight) / 2) * 0x7FFF); + } + + void SdlJoystick::RampEffect::SetSDLHapticEffect(ControlState StateLeft, ControlState StateRight) + { + m_Effect.type = SDL_HAPTIC_RAMP; + m_Effect.ramp.length = RUMBLE_LENGTH_MAX; + m_Effect.ramp.start = (Sint16)(((StateLeft + StateRight) / 2) * 0x7FFF); + } + + void SdlJoystick::SineEffect::SetSDLHapticEffect(ControlState StateLeft, ControlState StateRight) + { + m_Effect.type = SDL_HAPTIC_SINE; + m_Effect.periodic.period = RUMBLE_PERIOD; + m_Effect.periodic.magnitude = (Sint16)(((StateLeft + StateRight) / 2) * 0x7FFF); + m_Effect.periodic.offset = 0; + m_Effect.periodic.phase = 18000; + m_Effect.periodic.length = RUMBLE_LENGTH_MAX; + m_Effect.periodic.delay = 0; + m_Effect.periodic.attack_length = 0; + } + + void SdlJoystick::TriangleEffect::SetSDLHapticEffect(ControlState StateLeft, ControlState StateRight) + { + m_Effect.type = SDL_HAPTIC_TRIANGLE; + m_Effect.periodic.period = RUMBLE_PERIOD; + m_Effect.periodic.magnitude = (Sint16)(((StateLeft + StateRight) / 2) * 0x7FFF); + m_Effect.periodic.offset = 0; + m_Effect.periodic.phase = 18000; + m_Effect.periodic.length = RUMBLE_LENGTH_MAX; + m_Effect.periodic.delay = 0; + m_Effect.periodic.attack_length = 0; + } + + void SdlJoystick::LeftRightEffect::SetSDLHapticEffect(ControlState StateLeft, ControlState StateRight) + { + m_Effect.type = SDL_HAPTIC_LEFTRIGHT; + m_Effect.leftright.length = RUMBLE_LENGTH_MAX; + // max ranges tuned to 'feel' similar in magnitude to triangle/sine on xbox360 controller + m_Effect.leftright.large_magnitude = (Uint16)(StateRight * 0x4000); + m_Effect.leftright.small_magnitude = (Uint16)(StateLeft * 0xFFFF); + } +} diff --git a/src/common/input/SdlJoystick.h b/src/common/input/SdlJoystick.h new file mode 100644 index 0000000000..be26580013 --- /dev/null +++ b/src/common/input/SdlJoystick.h @@ -0,0 +1,218 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +#ifndef SDL_H_ +#define SDL_H_ + +#include "InputDevice.h" +#include + + +namespace Sdl +{ + typedef enum _SDL_INIT_STATUS : int + { + SDL_NOT_INIT = -2, + SDL_INIT_ERROR, + SDL_INIT_SUCCESS, + } + SDL_INIT_STATUS; + + extern uint32_t ExitEvent_t; + extern uint32_t PopulateEvent_t; + extern uint32_t UpdateInputEvent_t; + extern uint32_t DeviceRemoveAck_t; + extern int SdlInitStatus; + extern bool SdlPopulateOK; + + // initialize SDL + void Init(std::mutex& Mtx, std::condition_variable& Cv); + // shutdown SDL + void DeInit(std::thread& Thr); + // open the sdl joystick with the specified index + void OpenSdlDevice(const int Index); + // close the sdl joystick with the specified index + void CloseSdlDevice(const int Index); + // refresh the device list in response to a refresh command from the input GUI + void PopulateDevices(); + + class SdlJoystick : public InputDevice + { + public: + SdlJoystick(SDL_Joystick* const Joystick, const int Index); + ~SdlJoystick(); + // retrieves the name of the device + std::string GetDeviceName() const override; + // returns "SDL" + std::string GetAPI() const override; + // retrieves the joystick identifier used by SDL + SDL_Joystick* GetSDLJoystick() const; + // updates the state of this joystick + bool UpdateInput() override; + // retrieves the sdl id of this device + SDL_JoystickID GetId(SDL_JoystickID id) const override; + // sets dirty flag + void SetDirty() { m_bDirty = true; } + // checks if the device supports xinput + bool IsXInput() const { return m_bIsXInput; } + + private: + class Button : public InputDevice::Input + { + public: + Button(uint8_t Index, SDL_Joystick* Js) : m_Index(Index), m_Js(Js) {} + std::string GetName() const override; + ControlState GetState() const override; + + private: + // pointer to the device this button belongs to + SDL_Joystick* const m_Js; + // arbitrary index assigned to this button + const uint8_t m_Index; + }; + + class Hat : public InputDevice::Input + { + public: + Hat(uint8_t Index, SDL_Joystick* Js, uint8_t Direction) : m_Index(Index), m_Js(Js), m_Direction(Direction) {} + std::string GetName() const override; + ControlState GetState() const override; + + private: + // pointer to the device this hat button belongs to + SDL_Joystick* const m_Js; + // identifies the direction of the hat button (arbitrary, assigned by us) + const uint8_t m_Direction; + // arbitrary index assigned to this hat button + const uint8_t m_Index; + }; + + class Axis : public InputDevice::Input + { + public: + std::string GetName() const override; + Axis(uint8_t Index, SDL_Joystick* Js, int16_t Range) : m_Index(Index), m_Js(Js), m_Range(Range) {} + ControlState GetState() const override; + + private: + // pointer to the device this axis belongs to + SDL_Joystick* const m_Js; + // max value of this axis + const int16_t m_Range; + // arbitrary index assigned to this axis + const uint8_t m_Index; + }; + + class HapticEffect : public Output + { + public: + HapticEffect(SDL_Haptic* Haptic) : m_Haptic(Haptic), m_ID(-1) {} + ~HapticEffect() + { + m_Effect.type = 0; + Update(); + } + + protected: + void Update(); + virtual void SetSDLHapticEffect(ControlState StateLeft, ControlState StateRight) = 0; + + // the type of haptic effect + SDL_HapticEffect m_Effect; + // haptic device identifier as assigned by SDL, if available + SDL_Haptic* m_Haptic; + // id of the effect as returned by SDL + int m_ID; + + private: + virtual void SetState(ControlState StateLeft, ControlState StateRight) override final; + }; + + class ConstantEffect : public HapticEffect + { + public: + ConstantEffect(SDL_Haptic* Haptic) : HapticEffect(Haptic) {} + std::string GetName() const override; + + private: + void SetSDLHapticEffect(ControlState StateLeft, ControlState StateRight) override; + }; + + class RampEffect : public HapticEffect + { + public: + RampEffect(SDL_Haptic* Haptic) : HapticEffect(Haptic) {} + std::string GetName() const override; + + private: + void SetSDLHapticEffect(ControlState StateLeft, ControlState StateRight) override; + }; + + class SineEffect : public HapticEffect + { + public: + SineEffect(SDL_Haptic* Haptic) : HapticEffect(Haptic) {} + std::string GetName() const override; + + private: + void SetSDLHapticEffect(ControlState StateLeft, ControlState StateRight) override; + }; + + class TriangleEffect : public HapticEffect + { + public: + TriangleEffect(SDL_Haptic* Haptic) : HapticEffect(Haptic) {} + std::string GetName() const override; + + private: + void SetSDLHapticEffect(ControlState StateLeft, ControlState StateRight) override; + }; + + class LeftRightEffect : public HapticEffect + { + public: + LeftRightEffect(SDL_Haptic* Haptic) : HapticEffect(Haptic) {} + std::string GetName() const override; + + private: + void SetSDLHapticEffect(ControlState StateLeft, ControlState StateRight) override; + }; + + // the friendly name of the device + std::string m_DeviceName; + // pointer to the device as assigned by SDL + SDL_Joystick* m_Joystick; + // sdl-assigned id to this device + SDL_JoystickID m_Sdl_ID; + // haptic device identifier as assigned by SDL, if available + SDL_Haptic* m_Haptic; + // indicates if the device supports xinput + bool m_bIsXInput; + }; +} + +#endif diff --git a/src/common/input/XInputPad.cpp b/src/common/input/XInputPad.cpp new file mode 100644 index 0000000000..9382483442 --- /dev/null +++ b/src/common/input/XInputPad.cpp @@ -0,0 +1,320 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +// Copyright 2010 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file of Dolphin at https://github.com/dolphin-emu/dolphin/blob/master/license.txt. + +// Derived from XInput.cpp of Dolphin emulator +// https://github.com/dolphin-emu/dolphin + +#define LOG_PREFIX CXBXR_MODULE::XINP + +#include "XInputPad.h" +#include "core\kernel\support\Emu.h" +#include "InputManager.h" + +#ifndef XINPUT_GAMEPAD_GUIDE +#define XINPUT_GAMEPAD_GUIDE 0x0400 +#endif + +// These are defined in the Xinput.h header supplied by Windows, but because we use _WIN32_WINNT=0x0601, they are greyed out. +// If the init function loads succesfully the 1.3 library version, then XInputGetCapabilities can return these subtypes too. +#ifndef XINPUT_DEVSUBTYPE_FLIGHT_STICK +#define XINPUT_DEVSUBTYPE_UNKNOWN 0x00 +#define XINPUT_DEVSUBTYPE_WHEEL 0x02 +#define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03 +#define XINPUT_DEVSUBTYPE_FLIGHT_STICK 0x04 +#define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05 +#define XINPUT_DEVSUBTYPE_GUITAR 0x06 +#define XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE 0x07 +#define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08 +#define XINPUT_DEVSUBTYPE_GUITAR_BASS 0x0B +#define XINPUT_DEVSUBTYPE_ARCADE_PAD 0x13 +#endif + + +namespace XInput +{ + typedef decltype(&XInputGetCapabilities) XInputGetCapabilities_t; + typedef decltype(&XInputSetState) XInputSetState_t; + typedef decltype(&XInputGetState) XInputGetState_t; + + static HMODULE hXInput = nullptr; + static XInputGetCapabilities_t PXInputGetCapabilities = nullptr; + static XInputSetState_t PXInputSetState = nullptr; + static XInputGetState_t PXInputGetState = nullptr; + + static bool haveGuideButton = false; + int XInputInitStatus = XINPUT_NOT_INIT; + uint8_t DevicesConnected = 0; + + static const struct + { + const char* const name; + const WORD bitmask; + } named_buttons[] = { { "Button A", XINPUT_GAMEPAD_A }, + { "Button B", XINPUT_GAMEPAD_B }, + { "Button X", XINPUT_GAMEPAD_X }, + { "Button Y", XINPUT_GAMEPAD_Y }, + { "Pad N", XINPUT_GAMEPAD_DPAD_UP }, + { "Pad S", XINPUT_GAMEPAD_DPAD_DOWN }, + { "Pad W", XINPUT_GAMEPAD_DPAD_LEFT }, + { "Pad E", XINPUT_GAMEPAD_DPAD_RIGHT }, + { "Start", XINPUT_GAMEPAD_START }, + { "Back", XINPUT_GAMEPAD_BACK }, + { "Shoulder L", XINPUT_GAMEPAD_LEFT_SHOULDER }, + { "Shoulder R", XINPUT_GAMEPAD_RIGHT_SHOULDER }, + { "Guide", XINPUT_GAMEPAD_GUIDE }, + { "Thumb L", XINPUT_GAMEPAD_LEFT_THUMB }, + { "Thumb R", XINPUT_GAMEPAD_RIGHT_THUMB } }; + + static const char* const named_triggers[] = { "Trigger L", "Trigger R" }; + + static const char* const named_axes[] = { "Left X", "Left Y", "Right X", "Right Y" }; + + void Init(std::mutex& Mtx) + { + std::unique_lock lck(Mtx); + + // Because we use _WIN32_WINNT=0x0601, this will load the XInput 9.1.0 library + // The 9.1.0 (Win7) doesn't provide support for the guide button, but the legacy 1.3 does. Unfortunately, it requires + // that the user has installed the June 2010 release of the DirectX SDK to be available. If they didn't, we will default + // to the 9.1.0 instead of failing the initialization + if (std::string(XINPUT_DLL).compare(TEXT("xinput9_1_0.dll")) == 0) { + hXInput = ::LoadLibrary(TEXT("xinput1_3.dll")); + } + if (!hXInput) { + hXInput = ::LoadLibrary(XINPUT_DLL); + if (!hXInput) { + EmuLog(LOG_LEVEL::ERROR2, "Failed to initialize XInput subsystem!"); + XInputInitStatus = XINPUT_INIT_ERROR; + return; + } + } + + PXInputGetCapabilities = + (XInputGetCapabilities_t)::GetProcAddress(hXInput, "XInputGetCapabilities"); + PXInputSetState = (XInputSetState_t)::GetProcAddress(hXInput, "XInputSetState"); + + // Ordinal 100 is the same as XInputGetState, except it doesn't dummy out the guide + // button info. Try loading it and fall back if needed. + PXInputGetState = (XInputGetState_t)::GetProcAddress(hXInput, (LPCSTR)100); + if (PXInputGetState) { + haveGuideButton = true; + } + else { + PXInputGetState = (XInputGetState_t)::GetProcAddress(hXInput, "XInputGetState"); + } + + if (!PXInputGetCapabilities || !PXInputSetState || !PXInputGetState) + { + ::FreeLibrary(hXInput); + hXInput = nullptr; + EmuLog(LOG_LEVEL::ERROR2, "Failed to find XInput functions!"); + XInputInitStatus = XINPUT_INIT_ERROR; + return; + } + XInputInitStatus = XINPUT_INIT_SUCCESS; + } + + void DeInit() + { + XInputInitStatus = XINPUT_NOT_INIT; + if (hXInput) + { + ::FreeLibrary(hXInput); + hXInput = nullptr; + } + } + + void GetDeviceChanges() + { + XINPUT_CAPABILITIES caps; + DWORD ret; + for (uint8_t i = 0, mask = 1; i != 4; ++i, mask <<= 1) { + ret = PXInputGetCapabilities(i, 0, &caps); + if ((ERROR_SUCCESS == ret) && !(DevicesConnected & mask)) { + auto Device = std::make_shared(caps, i); + // only add the device if it has some I/O controls + if (!Device->GetInputs().empty() || !Device->GetOutputs().empty()) { + g_InputDeviceManager.AddDevice(std::move(Device)); + } + else { + EmuLog(LOG_LEVEL::INFO, "Rejected XInput device %i. No controls detected", i); + } + DevicesConnected |= mask; + } + else if ((ERROR_DEVICE_NOT_CONNECTED == ret) && (DevicesConnected & mask)) { + g_InputDeviceManager.RemoveDevice([&i](const auto& Device) { + const XDevice* dev = dynamic_cast(Device); + return dev && (dev->GetXInputDevice() == i); + }); + DevicesConnected &= ~mask; + } + } + } + + void PopulateDevices() + { + DevicesConnected = 0; + GetDeviceChanges(); + } + + XDevice::XDevice(const XINPUT_CAPABILITIES& Capabilities, uint8_t Index) : m_Subtype(Capabilities.SubType), m_Index(Index), + m_dwPacketNumber(0) + { + // XInputGetCaps can be broken on some devices, so we'll just ignore it + // and assume all gamepad + vibration capabilities are supported + + // get supported buttons + for (int i = 0; i != sizeof(named_buttons) / sizeof(*named_buttons); ++i) { + // Only add guide button if we have the 100 ordinal XInputGetState + if (!(named_buttons[i].bitmask & XINPUT_GAMEPAD_GUIDE) || haveGuideButton) { + AddInput(new Button(i, m_state_in.Gamepad.wButtons)); + } + } + + // get supported triggers + for (int i = 0; i != sizeof(named_triggers) / sizeof(*named_triggers); ++i) { + AddInput(new Trigger(i, (&m_state_in.Gamepad.bLeftTrigger)[i], 255)); + } + + // get supported axes + for (int i = 0; i != sizeof(named_axes) / sizeof(*named_axes); ++i) { + const SHORT& ax = (&m_state_in.Gamepad.sThumbLX)[i]; + + // each axis gets a negative and a positive input instance associated with it + AddInput(new Axis(i, ax, -32768)); + AddInput(new Axis(i, ax, 32767)); + } + + // get supported motors + AddOutput(new Motor(this, m_state_out.wLeftMotorSpeed, m_state_out.wRightMotorSpeed, 65535)); + + memset(&m_state_in, 0, sizeof(m_state_in)); + } + + std::string XDevice::GetDeviceName() const + { + switch (m_Subtype) + { + case XINPUT_DEVSUBTYPE_GAMEPAD: + return "Gamepad"; + case XINPUT_DEVSUBTYPE_WHEEL: + return "Wheel"; + case XINPUT_DEVSUBTYPE_ARCADE_STICK: + return "Arcade Stick"; + case XINPUT_DEVSUBTYPE_FLIGHT_STICK: + return "Flight Stick"; + case XINPUT_DEVSUBTYPE_DANCE_PAD: + return "Dance Pad"; + case XINPUT_DEVSUBTYPE_GUITAR: + return "Guitar"; + case XINPUT_DEVSUBTYPE_DRUM_KIT: + return "Drum Kit"; + default: + return "Device"; + } + } + + std::string XDevice::GetAPI() const + { + return "XInput"; + } + + uint8_t XDevice::GetXInputDevice() const + { + return m_Index; + } + + // Update I/O + + bool XDevice::UpdateInput() + { + if (PXInputGetState(m_Index, &m_state_in) != ERROR_SUCCESS) { + return false; + } + DWORD packet_number = m_state_in.dwPacketNumber; + if (packet_number != m_dwPacketNumber) { + m_dwPacketNumber = packet_number; + return true; + } + return false; + } + + void XDevice::UpdateMotors() + { + PXInputSetState(m_Index, &m_state_out); + } + + // GET name/source/id + + std::string XDevice::Button::GetName() const + { + return named_buttons[m_Index].name; + } + + std::string XDevice::Axis::GetName() const + { + return std::string(named_axes[m_Index]) + (m_Range < 0 ? '-' : '+'); + } + + std::string XDevice::Trigger::GetName() const + { + return named_triggers[m_Index]; + } + + std::string XDevice::Motor::GetName() const + { + return "LeftRight"; + } + + // GET / SET STATES + + ControlState XDevice::Button::GetState() const + { + return (m_Buttons & named_buttons[m_Index].bitmask) > 0; + } + + ControlState XDevice::Trigger::GetState() const + { + return ControlState(m_Trigger) / m_Range; + } + + ControlState XDevice::Axis::GetState() const + { + return std::max(0.0, ControlState(m_Axis) / m_Range); + } + + void XDevice::Motor::SetState(ControlState StateLeft, ControlState StateRight) + { + m_MotorLeft = (WORD)(StateLeft * m_Range); + m_MotorRight = (WORD)(StateRight * m_Range); + m_Parent->UpdateMotors(); + } +} diff --git a/src/common/input/XInputPad.h b/src/common/input/XInputPad.h new file mode 100644 index 0000000000..f6faae243d --- /dev/null +++ b/src/common/input/XInputPad.h @@ -0,0 +1,144 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +#pragma once + +#include +#include +#include "InputDevice.h" + + +namespace XInput +{ + typedef enum _XINPUT_INIT_STATUS : int + { + XINPUT_NOT_INIT = -2, + XINPUT_INIT_ERROR, + XINPUT_INIT_SUCCESS, + } + XINPUT_INIT_STATUS; + + extern int XInputInitStatus; + extern uint8_t DevicesConnected; + + // initialize XInput + void Init(std::mutex& Mtx); + // shutdown XInput + void DeInit(); + // refresh the device list in response to a refresh command from the input GUI + void PopulateDevices(); + // update the device list + void GetDeviceChanges(); + + class XDevice : public InputDevice + { + private: + class Button : public InputDevice::Input + { + public: + Button(uint8_t Index, const WORD& Buttons) : m_Buttons(Buttons), m_Index(Index) {} + std::string GetName() const override; + ControlState GetState() const override; + + private: + // button state + const WORD& m_Buttons; + // button index + uint8_t m_Index; + }; + + class Axis : public InputDevice::Input + { + public: + Axis(uint8_t Index, const SHORT& Axis, SHORT Range) : m_Index(Index), m_Axis(Axis), m_Range(Range) {} + std::string GetName() const override; + ControlState GetState() const override; + + private: + // axis state + const SHORT& m_Axis; + // max value of the axis + const SHORT m_Range; + // axis index + const uint8_t m_Index; + }; + + class Trigger : public InputDevice::Input + { + public: + Trigger(uint8_t Index, const BYTE& Trigger, BYTE Range) + : m_Trigger(Trigger), m_Range(Range), m_Index(Index) {} + std::string GetName() const override; + ControlState GetState() const override; + + private: + // trigger state + const BYTE& m_Trigger; + // max value of the trigger + const BYTE m_Range; + // trigger index + const uint8_t m_Index; + }; + + class Motor : public InputDevice::Output + { + public: + Motor(XDevice* Parent, WORD& MotorLeft, WORD& MotorRight, WORD Range) + : m_MotorLeft(MotorLeft), m_MotorRight(MotorRight), m_Range(Range), m_Parent(Parent) {} + std::string GetName() const override; + void SetState(ControlState StateLeft, ControlState StateRight) override; + + private: + // left motor state + WORD& m_MotorLeft; + // right motor state + WORD& m_MotorRight; + // max value of the motor strength + const WORD m_Range; + // parent object of the motor + XDevice* m_Parent; + }; + + public: + bool UpdateInput() override; + + XDevice(const XINPUT_CAPABILITIES& Capabilities, uint8_t Index); + + std::string GetDeviceName() const override; + std::string GetAPI() const override; + uint8_t GetXInputDevice() const; + + void UpdateMotors(); + + private: + XINPUT_STATE m_state_in; + XINPUT_VIBRATION m_state_out{}; + const BYTE m_Subtype; + const uint8_t m_Index; + DWORD m_dwPacketNumber; + }; +} diff --git a/src/common/util/CxbxUtil.cpp b/src/common/util/CxbxUtil.cpp index 1e48d7ea46..555bb33f53 100644 --- a/src/common/util/CxbxUtil.cpp +++ b/src/common/util/CxbxUtil.cpp @@ -255,3 +255,21 @@ void unix2dos(std::string& string) position += 2; } } + +// Copyright 2008 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file of Dolphin at https://github.com/dolphin-emu/dolphin/blob/master/license.txt. + +// Source: StringUtil.cpp of Dolphin emulator +/* Turns " hello " into "hello". Also handles tabs */ +std::string StripSpaces(const std::string& str) +{ + const size_t s = str.find_first_not_of(" \t\r\n"); + + if (str.npos != s) { + return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1); + } + else { + return ""; + } +} diff --git a/src/common/util/CxbxUtil.h b/src/common/util/CxbxUtil.h index 443ef64689..0da5beda81 100644 --- a/src/common/util/CxbxUtil.h +++ b/src/common/util/CxbxUtil.h @@ -63,6 +63,7 @@ bool Memory_W(void* Addr, void* Buf, size_t Num); bool Memory_RW(void* Addr, void* Buf, size_t Num, bool bIsWrite); void unix2dos(std::string& string); +std::string StripSpaces(const std::string& str); // Retrieves the underlying integer value of a scoped enumerator. It allows to avoid using static_cast every time template @@ -73,6 +74,22 @@ constexpr typename std::underlying_type::type to_underlying(E e) noexcept #define GET_WORD_LOW(value) (uint8_t)((value) & 0xFF) #define GET_WORD_HIGH(value) (uint8_t)(((value) >> 8) & 0xFF) + +#ifdef __cplusplus +template struct ArraySizeHelper { char _[N]; }; +template +ArraySizeHelper makeArraySizeHelper(T(&)[N]); +# define ARRAY_SIZE(a) sizeof(makeArraySizeHelper(a)) +#else +// The expression ARRAY_SIZE(a) is a compile-time constant of type +// size_t which represents the number of elements of the given +// array. You should only use ARRAY_SIZE on statically allocated +// arrays. + +#define ARRAY_SIZE(a) \ + ((sizeof(a) / sizeof(*(a))) / \ + static_cast(!(sizeof(a) % sizeof(*(a))))) +#endif /*! round dwValue to the nearest multiple of dwMult */ static uint32_t RoundUp(uint32_t dwValue, uint32_t dwMult) diff --git a/src/common/win32/DInputController.cpp b/src/common/win32/DInputController.cpp deleted file mode 100644 index 5d5a60ed6b..0000000000 --- a/src/common/win32/DInputController.cpp +++ /dev/null @@ -1,978 +0,0 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -// ****************************************************************** -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2002-2003 Aaron Robinson -// * -// * All rights reserved -// * -// ****************************************************************** - -// Without this, you'll get a ton of errors from the std library for some unknown reason... -#include "Logging.h" - -#include "DInputController.h" - -#include "EmuShared.h" -#include "core\kernel\support\EmuXTL.h" - -// This is ridiculous -#define FIELD_OFFSET(type,field) ((ULONG)&(((type *)0)->field)) - -// ****************************************************************** -// * func: DInputController::DInputController -// ****************************************************************** -DInputController::DInputController() -{ - m_CurrentState = XBCTRL_STATE_NONE; - - int v=0; - - for(v=0;v=0;v--) - { - // ****************************************************************** - // * Poll the current device - // ****************************************************************** - { - HRESULT hRet = m_InputDevice[v].m_Device->Poll(); - - if(FAILED(hRet)) - { - hRet = m_InputDevice[v].m_Device->Acquire(); - - while(hRet == DIERR_INPUTLOST) - hRet = m_InputDevice[v].m_Device->Acquire(); - } - } - - DWORD dwHow = -1, dwFlags = m_InputDevice[v].m_Flags; - - // ****************************************************************** - // * Detect Joystick Input - // ****************************************************************** - if(m_InputDevice[v].m_Flags & DEVICE_FLAG_JOYSTICK) - { - XTL::DIJOYSTATE JoyState; - - // ****************************************************************** - // * Get Joystick State - // ****************************************************************** - { - HRESULT hRet = m_InputDevice[v].m_Device->GetDeviceState(sizeof(XTL::DIJOYSTATE), &JoyState); - - if(FAILED(hRet)) - continue; - } - - dwFlags = DEVICE_FLAG_JOYSTICK; - - if(abs(JoyState.lX) > DETECT_SENSITIVITY_JOYSTICK) - { - dwHow = FIELD_OFFSET(XTL::DIJOYSTATE, lX); - dwFlags |= (JoyState.lX > 0) ? (DEVICE_FLAG_AXIS | DEVICE_FLAG_POSITIVE) : (DEVICE_FLAG_AXIS | DEVICE_FLAG_NEGATIVE); - } - else if(abs(JoyState.lY) > DETECT_SENSITIVITY_JOYSTICK) - { - dwHow = FIELD_OFFSET(XTL::DIJOYSTATE, lY); - dwFlags |= (JoyState.lY > 0) ? (DEVICE_FLAG_AXIS | DEVICE_FLAG_POSITIVE) : (DEVICE_FLAG_AXIS | DEVICE_FLAG_NEGATIVE); - } - else if(abs(JoyState.lZ) > DETECT_SENSITIVITY_JOYSTICK) - { - dwHow = FIELD_OFFSET(XTL::DIJOYSTATE, lZ); - dwFlags |= (JoyState.lZ > 0) ? (DEVICE_FLAG_AXIS | DEVICE_FLAG_POSITIVE) : (DEVICE_FLAG_AXIS | DEVICE_FLAG_NEGATIVE); - } - else if(abs(JoyState.lRx) > DETECT_SENSITIVITY_JOYSTICK) - { - dwHow = FIELD_OFFSET(XTL::DIJOYSTATE, lRx); - dwFlags |= (JoyState.lRx > 0) ? (DEVICE_FLAG_AXIS | DEVICE_FLAG_POSITIVE) : (DEVICE_FLAG_AXIS | DEVICE_FLAG_NEGATIVE); - } - else if(abs(JoyState.lRy) > DETECT_SENSITIVITY_JOYSTICK) - { - dwHow = FIELD_OFFSET(XTL::DIJOYSTATE, lRy); - dwFlags |= (JoyState.lRy > 0) ? (DEVICE_FLAG_AXIS | DEVICE_FLAG_POSITIVE) : (DEVICE_FLAG_AXIS | DEVICE_FLAG_NEGATIVE); - } - else if(abs(JoyState.lRz) > DETECT_SENSITIVITY_JOYSTICK) - { - dwHow = FIELD_OFFSET(XTL::DIJOYSTATE, lRz); - dwFlags |= (JoyState.lRz > 0) ? (DEVICE_FLAG_AXIS | DEVICE_FLAG_POSITIVE) : (DEVICE_FLAG_AXIS | DEVICE_FLAG_NEGATIVE); - } - else - { - for(int b=0;b<2;b++) - { - if(abs(JoyState.rglSlider[b]) > DETECT_SENSITIVITY_JOYSTICK) - { - dwHow = FIELD_OFFSET(XTL::DIJOYSTATE, rglSlider[b]); - dwFlags |= (JoyState.rglSlider[b] > 0) ? (DEVICE_FLAG_AXIS | DEVICE_FLAG_POSITIVE) : (DEVICE_FLAG_AXIS | DEVICE_FLAG_NEGATIVE); - } - } - } - - /* temporarily disabled - if(dwHow == -1) - { - for(int b=0;b<4;b++) - { - if(abs(JoyState.rgdwPOV[b]) > DETECT_SENSITIVITY_POV) - { - dwHow = FIELD_OFFSET(XTL::DIJOYSTATE, rgdwPOV[b]); - } - } - } - //*/ - - if(dwHow == -1) - { - for(int b=0;b<32;b++) - { - if(JoyState.rgbButtons[b] > DETECT_SENSITIVITY_BUTTON) - { - dwHow = FIELD_OFFSET(XTL::DIJOYSTATE, rgbButtons[b]); - dwFlags |= DEVICE_FLAG_BUTTON; - } - } - } - - // ****************************************************************** - // * Retrieve Object Info - // ****************************************************************** - if(dwHow != -1) - { - const char *szDirection = (dwFlags & DEVICE_FLAG_AXIS) ? (dwFlags & DEVICE_FLAG_POSITIVE) ? "Positive " : "Negative " : ""; - - m_InputDevice[v].m_Device->GetDeviceInfo(&DeviceInstance); - - m_InputDevice[v].m_Device->GetObjectInfo(&ObjectInstance, dwHow, DIPH_BYOFFSET); - - Map(CurConfigObject, DeviceInstance.tszInstanceName, dwHow, dwFlags); - - printf("Cxbx-Reloaded: Detected %s%s on %s%lu\n", szDirection, ObjectInstance.tszName, DeviceInstance.tszInstanceName, ObjectInstance.dwType); - - sprintf(szStatus, "Success: %s Mapped to '%s%s' on '%s'!", Settings::s_controller_dinput::XboxControllerObjectNameLookup[CurConfigObject], szDirection, ObjectInstance.tszName, DeviceInstance.tszInstanceName); - - return true; - } - } - // ****************************************************************** - // * Detect Keyboard Input - // ****************************************************************** - else if(m_InputDevice[v].m_Flags & DEVICE_FLAG_KEYBOARD) - { - BYTE KeyState[256]; - - m_InputDevice[v].m_Device->GetDeviceState(256, KeyState); - - dwFlags = DEVICE_FLAG_KEYBOARD; - - // ****************************************************************** - // * Check for Keyboard State Change - // ****************************************************************** - for(int r=0;r<256;r++) - { - if(KeyState[r] != 0) - { - dwHow = r; - break; - } - } - - // ****************************************************************** - // * Check for Success - // ****************************************************************** - if(dwHow != -1) - { - Map(CurConfigObject, "SysKeyboard", dwHow, dwFlags); - - printf("Cxbx-Reloaded: Detected Key %d on SysKeyboard\n", dwHow); - - sprintf(szStatus, "Success: %s Mapped to Key %d on SysKeyboard", Settings::s_controller_dinput::XboxControllerObjectNameLookup[CurConfigObject], dwHow); - - return true; - } - } - } - - return false; -} - -// ****************************************************************** -// * func: DInputController::ConfigEnd -// ****************************************************************** -void DInputController::ConfigEnd() -{ - if(m_CurrentState != XBCTRL_STATE_CONFIG) - { - SetError("Invalid State"); - return; - } - - DInputCleanup(); - - m_CurrentState = XBCTRL_STATE_NONE; - - return; -} - -// ****************************************************************** -// * func: DInputController::ListenBegin -// ****************************************************************** -void DInputController::ListenBegin(HWND hwnd) -{ - int v=0; - - if(m_CurrentState != XBCTRL_STATE_NONE) - { - SetError("Invalid State"); - return; - } - - m_CurrentState = XBCTRL_STATE_LISTEN; - - DInputInit(hwnd); - - for(v=XBCTRL_MAX_DEVICES-1;v>=m_dwInputDeviceCount;v--) - m_settings.DeviceName[v][0] = '\0'; - - for(v=0;v= m_dwInputDeviceCount) - { - printf("Warning: Device Mapped to %s was not found!\n", Settings::s_controller_dinput::XboxControllerObjectNameLookup[v]); - m_settings.ObjectConfig[v].dwDevice = -1; - } - } - - return; -} - -// ****************************************************************** -// * func: DInputController::ListenPoll -// ****************************************************************** -void DInputController::ListenPoll(XTL::X_XINPUT_STATE *Controller) -{ - if(Controller == NULL) - return; - - XTL::LPDIRECTINPUTDEVICE8 pDevice=NULL; - XTL::LPDIRECTINPUTDEVICE8 pPrevDevice=(XTL::LPDIRECTINPUTDEVICE8)-1; - - HRESULT hRet=0; - DWORD dwFlags=0; - - // Test case: Smashing Drive, pointer of X_XINPUT_STATE is reused for other controller ports. - // By setting Gamepad to zero'd no longer have conflict with input changes from other controller port. - // ****************************************************************** - // * Set default values - // ****************************************************************** - Controller->Gamepad = { 0 }; - - XTL::DIJOYSTATE JoyState = { 0 }; - BYTE KeyboardState[256] = { 0 }; - XTL::DIMOUSESTATE2 MouseState = { 0 }; - - // ****************************************************************** - // * Poll all devices - // ****************************************************************** - for(int v=0;vPoll(); - if (FAILED(hRet)) { - hRet = pDevice->Acquire(); - while (hRet == DIERR_INPUTLOST) - hRet = pDevice->Acquire(); - } - - if (dwFlags & DEVICE_FLAG_JOYSTICK) { - JoyState = { 0 }; - if (pDevice->GetDeviceState(sizeof(JoyState), &JoyState) != DI_OK) - continue; - } - else if (dwFlags & DEVICE_FLAG_KEYBOARD) { - memset(KeyboardState, 0, sizeof(KeyboardState)); - if (pDevice->GetDeviceState(sizeof(KeyboardState), &KeyboardState) != DI_OK) - continue; - } - else if (dwFlags & DEVICE_FLAG_MOUSE) { - MouseState = { 0 }; - - if (pDevice->GetDeviceState(sizeof(MouseState), &MouseState) != DI_OK) - continue; - } - } - - SHORT wValue = 0; - - // ****************************************************************** - // * Interpret PC Joystick Input - // ****************************************************************** - if(dwFlags & DEVICE_FLAG_JOYSTICK) - { - if(dwFlags & DEVICE_FLAG_AXIS) - { - LONG *pdwAxis = (LONG*)((uint32_t)&JoyState + dwInfo); - wValue = (SHORT)(*pdwAxis); - - if(dwFlags & DEVICE_FLAG_NEGATIVE) - { - if(wValue < 0) - wValue = abs(wValue+1); - else - wValue = 0; - } - else if(dwFlags & DEVICE_FLAG_POSITIVE) - { - if(wValue < 0) - wValue = 0; - } - } - else if(dwFlags & DEVICE_FLAG_BUTTON) - { - BYTE *pbButton = (BYTE*)((uint32_t)&JoyState + dwInfo); - - if(*pbButton & 0x80) - wValue = 32767; - else - wValue = 0; - } - } - // ****************************************************************** - // * Interpret PC KeyBoard Input - // ****************************************************************** - else if(dwFlags & DEVICE_FLAG_KEYBOARD) - { - BYTE bKey = KeyboardState[dwInfo]; - - if(bKey & 0x80) - wValue = 32767; - else - wValue = 0; - } - // ****************************************************************** - // * Interpret PC Mouse Input - // ****************************************************************** - else if(dwFlags & DEVICE_FLAG_MOUSE) - { - if(dwFlags & DEVICE_FLAG_MOUSE_CLICK) - { - if(MouseState.rgbButtons[dwInfo] & 0x80) - wValue = 32767; - else - wValue = 0; - } - else if(dwFlags & DEVICE_FLAG_AXIS) - { - static LONG lAccumX = 0; - static LONG lAccumY = 0; - static LONG lAccumZ = 0; - - lAccumX += MouseState.lX * 300; - lAccumY += MouseState.lY * 300; - lAccumZ += MouseState.lZ * 300; - - if(lAccumX > 32767) - lAccumX = 32767; - else if(lAccumX < -32768) - lAccumX = -32768; - - if(lAccumY > 32767) - lAccumY = 32767; - else if(lAccumY < -32768) - lAccumY = -32768; - - if(lAccumZ > 32767) - lAccumZ = 32767; - else if(lAccumZ < -32768) - lAccumZ = -32768; - - if(dwInfo == FIELD_OFFSET(XTL::DIMOUSESTATE, lX)) - wValue = (WORD)lAccumX; - else if(dwInfo == FIELD_OFFSET(XTL::DIMOUSESTATE, lY)) - wValue = (WORD)lAccumY; - else if(dwInfo == FIELD_OFFSET(XTL::DIMOUSESTATE, lZ)) - wValue = (WORD)lAccumZ; - - if(dwFlags & DEVICE_FLAG_NEGATIVE) - { - if(wValue < 0) - wValue = abs(wValue+1); - else - wValue = 0; - } - else if(dwFlags & DEVICE_FLAG_POSITIVE) - { - if(wValue < 0) - wValue = 0; - } - } - } - - // ****************************************************************** - // * Map Xbox Joystick Input - // ****************************************************************** - if(v >= XBCTRL_OBJECT_LTHUMBPOSX && v <= XBCTRL_OBJECT_RTHUMB) - { - switch(v) - { - case XBCTRL_OBJECT_LTHUMBPOSY: - Controller->Gamepad.sThumbLY += wValue; - break; - case XBCTRL_OBJECT_LTHUMBNEGY: - Controller->Gamepad.sThumbLY -= wValue; - break; - case XBCTRL_OBJECT_RTHUMBPOSY: - Controller->Gamepad.sThumbRY += wValue; - break; - case XBCTRL_OBJECT_RTHUMBNEGY: - Controller->Gamepad.sThumbRY -= wValue; - break; - case XBCTRL_OBJECT_LTHUMBPOSX: - Controller->Gamepad.sThumbLX += wValue; - break; - case XBCTRL_OBJECT_LTHUMBNEGX: - Controller->Gamepad.sThumbLX -= wValue; - break; - case XBCTRL_OBJECT_RTHUMBPOSX: - Controller->Gamepad.sThumbRX += wValue; - break; - case XBCTRL_OBJECT_RTHUMBNEGX: - Controller->Gamepad.sThumbRX -= wValue; - break; - case XBCTRL_OBJECT_A: - Controller->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_A] = (wValue / 128); - break; - case XBCTRL_OBJECT_B: - Controller->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_B] = (wValue / 128); - break; - case XBCTRL_OBJECT_X: - Controller->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_X] = (wValue / 128); - break; - case XBCTRL_OBJECT_Y: - Controller->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_Y] = (wValue / 128); - break; - case XBCTRL_OBJECT_WHITE: - Controller->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_WHITE] = (wValue / 128); - break; - case XBCTRL_OBJECT_BLACK: - Controller->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_BLACK] = (wValue / 128); - break; - case XBCTRL_OBJECT_LTRIGGER: - Controller->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_LEFT_TRIGGER] = (wValue / 128); - break; - case XBCTRL_OBJECT_RTRIGGER: - Controller->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_RIGHT_TRIGGER] = (wValue / 128); - break; - case XBCTRL_OBJECT_DPADUP: - if(wValue > 0) - Controller->Gamepad.wButtons |= X_XINPUT_GAMEPAD_DPAD_UP; - else - Controller->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_DPAD_UP; - break; - case XBCTRL_OBJECT_DPADDOWN: - if(wValue > 0) - Controller->Gamepad.wButtons |= X_XINPUT_GAMEPAD_DPAD_DOWN; - else - Controller->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_DPAD_DOWN; - break; - case XBCTRL_OBJECT_DPADLEFT: - if(wValue > 0) - Controller->Gamepad.wButtons |= X_XINPUT_GAMEPAD_DPAD_LEFT; - else - Controller->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_DPAD_LEFT; - break; - case XBCTRL_OBJECT_DPADRIGHT: - if(wValue > 0) - Controller->Gamepad.wButtons |= X_XINPUT_GAMEPAD_DPAD_RIGHT; - else - Controller->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_DPAD_RIGHT; - break; - case XBCTRL_OBJECT_BACK: - if(wValue > 0) - Controller->Gamepad.wButtons |= X_XINPUT_GAMEPAD_BACK; - else - Controller->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_BACK; - break; - case XBCTRL_OBJECT_START: - if(wValue > 0) - Controller->Gamepad.wButtons |= X_XINPUT_GAMEPAD_START; - else - Controller->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_START; - break; - case XBCTRL_OBJECT_LTHUMB: - if(wValue > 0) - Controller->Gamepad.wButtons |= X_XINPUT_GAMEPAD_LEFT_THUMB; - else - Controller->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_LEFT_THUMB; - break; - case XBCTRL_OBJECT_RTHUMB: - if(wValue > 0) - Controller->Gamepad.wButtons |= X_XINPUT_GAMEPAD_RIGHT_THUMB; - else - Controller->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_RIGHT_THUMB; - break; - } - } - } - - return; -} - -// ****************************************************************** -// * func: DInputController::ListenEnd -// ****************************************************************** -void DInputController::ListenEnd() -{ - if(m_CurrentState != XBCTRL_STATE_LISTEN) - { - SetError("Invalid State"); - return; - } - - DInputCleanup(); - - m_CurrentState = XBCTRL_STATE_NONE; - - return; -} - -// ****************************************************************** -// * func: DInputController::DeviceIsUsed -// ****************************************************************** -bool DInputController::DeviceIsUsed(const char *szDeviceName) -{ - for(int v=0;vEnumDevices - ( - DI8DEVCLASS_GAMECTRL, - WrapEnumGameCtrlCallback, - this, - DIEDFL_ATTACHEDONLY - ); - - if(m_CurrentState == XBCTRL_STATE_CONFIG || DeviceIsUsed("SysKeyboard")) - { - hRet = m_pDirectInput8->CreateDevice(XTL::GUID_SysKeyboard, &m_InputDevice[m_dwInputDeviceCount].m_Device, NULL); - - if(!FAILED(hRet)) - { - m_InputDevice[m_dwInputDeviceCount].m_Flags = DEVICE_FLAG_KEYBOARD; - - m_InputDevice[m_dwInputDeviceCount++].m_Device->SetDataFormat(&XTL::c_dfDIKeyboard); - } - - if(m_CurrentState == XBCTRL_STATE_LISTEN) - ReorderObjects("SysKeyboard", m_dwInputDeviceCount - 1); - } - - if(m_CurrentState == XBCTRL_STATE_CONFIG || DeviceIsUsed("SysMouse")) - { - hRet = m_pDirectInput8->CreateDevice(XTL::GUID_SysMouse, &m_InputDevice[m_dwInputDeviceCount].m_Device, NULL); - - if(!FAILED(hRet)) - { - m_InputDevice[m_dwInputDeviceCount].m_Flags = DEVICE_FLAG_MOUSE; - - m_InputDevice[m_dwInputDeviceCount++].m_Device->SetDataFormat(&XTL::c_dfDIMouse2); - } - - if(m_CurrentState == XBCTRL_STATE_LISTEN) - ReorderObjects("SysMouse", m_dwInputDeviceCount - 1); - } - } - - // ****************************************************************** - // * Enumerate Controller objects - // ****************************************************************** - for(m_dwCurObject=0;m_dwCurObjectEnumObjects(WrapEnumObjectsCallback, this, DIDFT_ALL); - - // ****************************************************************** - // * Set cooperative level and acquire - // ****************************************************************** - { - for(int v=m_dwInputDeviceCount-1;v>=0;v--) - { - m_InputDevice[v].m_Device->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); - m_InputDevice[v].m_Device->Acquire(); - - HRESULT hRet = m_InputDevice[v].m_Device->Poll(); - - if(FAILED(hRet)) - { - hRet = m_InputDevice[v].m_Device->Acquire(); - - while(hRet == DIERR_INPUTLOST) - hRet = m_InputDevice[v].m_Device->Acquire(); - - if(hRet != DIERR_INPUTLOST) - break; - } - } - } -} - -// ****************************************************************** -// * func: DInputController::DInputCleanup -// ****************************************************************** -void DInputController::DInputCleanup() -{ - for(int v=m_dwInputDeviceCount-1;v>=0;v--) - { - m_InputDevice[v].m_Device->Unacquire(); - m_InputDevice[v].m_Device->Release(); - m_InputDevice[v].m_Device = 0; - } - - m_dwInputDeviceCount = 0; - - if(m_pDirectInput8 != 0) - { - m_pDirectInput8->Release(); - m_pDirectInput8 = 0; - } - - return; -} - -// ****************************************************************** -// * func: DInputController::Map -// ****************************************************************** -void DInputController::Map(XBCtrlObject object, const char *szDeviceName, int dwInfo, int dwFlags) -{ - // Initialize InputMapping instance - m_settings.ObjectConfig[object].dwDevice = Insert(szDeviceName); - m_settings.ObjectConfig[object].dwInfo = dwInfo; - m_settings.ObjectConfig[object].dwFlags = dwFlags; - - // Purge unused device slots - for(int v=0;vtszInstanceName)) - return DIENUM_CONTINUE; - - HRESULT hRet = m_pDirectInput8->CreateDevice(lpddi->guidInstance, &m_InputDevice[m_dwInputDeviceCount].m_Device, NULL); - - if(!FAILED(hRet)) - { - m_InputDevice[m_dwInputDeviceCount].m_Flags = DEVICE_FLAG_JOYSTICK; - - m_InputDevice[m_dwInputDeviceCount++].m_Device->SetDataFormat(&XTL::c_dfDIJoystick); - - if(m_CurrentState == XBCTRL_STATE_LISTEN) - ReorderObjects(lpddi->tszInstanceName, m_dwInputDeviceCount - 1); - } - - return DIENUM_CONTINUE; -} - -// ****************************************************************** -// * func: DInputController::EnumObjectsCallback -// ****************************************************************** -BOOL DInputController::EnumObjectsCallback(XTL::LPCDIDEVICEOBJECTINSTANCE lpddoi) -{ - if(lpddoi->dwType & DIDFT_AXIS) - { - XTL::DIPROPRANGE diprg; - - diprg.diph.dwSize = sizeof(XTL::DIPROPRANGE); - diprg.diph.dwHeaderSize = sizeof(XTL::DIPROPHEADER); - diprg.diph.dwHow = DIPH_BYID; - diprg.diph.dwObj = lpddoi->dwType; - diprg.lMin = 0 - 32768; - diprg.lMax = 0 + 32767; - - HRESULT hRet = m_InputDevice[m_dwCurObject].m_Device->SetProperty(DIPROP_RANGE, &diprg.diph); - - if(FAILED(hRet)) - { - if(hRet == E_NOTIMPL) - return DIENUM_CONTINUE; - else - return DIENUM_STOP; - } - } - else if(lpddoi->dwType & DIDFT_BUTTON) - { - XTL::DIPROPRANGE diprg; - - diprg.diph.dwSize = sizeof(XTL::DIPROPRANGE); - diprg.diph.dwHeaderSize = sizeof(XTL::DIPROPHEADER); - diprg.diph.dwHow = DIPH_BYID; - diprg.diph.dwObj = lpddoi->dwType; - diprg.lMin = 0; - diprg.lMax = 255; - - HRESULT hRet = m_InputDevice[m_dwCurObject].m_Device->SetProperty(DIPROP_RANGE, &diprg.diph); - - if(FAILED(hRet)) - { - if(hRet == E_NOTIMPL) - return DIENUM_CONTINUE; - else - return DIENUM_STOP; - } - } - - return DIENUM_CONTINUE; -} - -// ****************************************************************** -// * func: WrapEnumGameCtrlCallback -// ****************************************************************** -BOOL CALLBACK WrapEnumGameCtrlCallback(XTL::LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) -{ - DInputController *context = (DInputController*)pvRef; - - return context->EnumGameCtrlCallback(lpddi); -} - -// ****************************************************************** -// * func: WrapEnumObjectsCallback -// ****************************************************************** -BOOL CALLBACK WrapEnumObjectsCallback(XTL::LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) -{ - DInputController *context = (DInputController*)pvRef; - - return context->EnumObjectsCallback(lpddoi); -} diff --git a/src/common/win32/DInputController.h b/src/common/win32/DInputController.h deleted file mode 100644 index 05c48fd9b9..0000000000 --- a/src/common/win32/DInputController.h +++ /dev/null @@ -1,234 +0,0 @@ -// ****************************************************************** -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2002-2003 Aaron Robinson -// * -// * All rights reserved -// * -// ****************************************************************** -#ifndef DINPUTCONTROLLER_H -#define DINPUTCONTROLLER_H - -#include "Cxbx.h" -#include "common\Error.h" -#include "Mutex.h" - -#include -#include -#include - -#include "core\kernel\support\EmuXTL.h" -#include "common\Settings.hpp" -/* -// ****************************************************************** -// * Xbox Controller Object IDs -// ****************************************************************** -enum XBCtrlObject -{ - // ****************************************************************** - // * Analog Axis - // ****************************************************************** - XBCTRL_OBJECT_LTHUMBPOSX = 0, - XBCTRL_OBJECT_LTHUMBNEGX, - XBCTRL_OBJECT_LTHUMBPOSY, - XBCTRL_OBJECT_LTHUMBNEGY, - XBCTRL_OBJECT_RTHUMBPOSX, - XBCTRL_OBJECT_RTHUMBNEGX, - XBCTRL_OBJECT_RTHUMBPOSY, - XBCTRL_OBJECT_RTHUMBNEGY, - // ****************************************************************** - // * Analog Buttons - // ****************************************************************** - XBCTRL_OBJECT_A, - XBCTRL_OBJECT_B, - XBCTRL_OBJECT_X, - XBCTRL_OBJECT_Y, - XBCTRL_OBJECT_BLACK, - XBCTRL_OBJECT_WHITE, - XBCTRL_OBJECT_LTRIGGER, - XBCTRL_OBJECT_RTRIGGER, - // ****************************************************************** - // * Digital Buttons - // ****************************************************************** - XBCTRL_OBJECT_DPADUP, - XBCTRL_OBJECT_DPADDOWN, - XBCTRL_OBJECT_DPADLEFT, - XBCTRL_OBJECT_DPADRIGHT, - XBCTRL_OBJECT_BACK, - XBCTRL_OBJECT_START, - XBCTRL_OBJECT_LTHUMB, - XBCTRL_OBJECT_RTHUMB, - // ****************************************************************** - // * Total number of components - // ****************************************************************** - XBCTRL_OBJECT_COUNT -}; - -// ****************************************************************** -// * Maximum number of devices allowed -// ****************************************************************** -#define XBCTRL_MAX_DEVICES XBCTRL_OBJECT_COUNT - -// ****************************************************************** -// * Xbox Controller Object Config -// ****************************************************************** -struct XBCtrlObjectCfg -{ - int dwDevice; // offset into m_InputDevice - int dwInfo; // extended information, depending on dwFlags - int dwFlags; // flags explaining the data format -};*/ - -// ****************************************************************** -// * class: DInputController -// ****************************************************************** -class DInputController : public Error -{ - public: - // ****************************************************************** - // * Initialization - // ****************************************************************** - DInputController(); - ~DInputController(); - - // ****************************************************************** - // * Configuration - // ****************************************************************** - void ConfigBegin(HWND hwnd, XBCtrlObject object); - bool ConfigPoll(char *szStatus); // true if polling detected a change - void ConfigEnd(); - - // ****************************************************************** - // * Listening - // ****************************************************************** - void ListenBegin(HWND hwnd); - void ListenPoll(XTL::X_XINPUT_STATE *Controller); - void ListenEnd(); - - // ****************************************************************** - // * DirectInput Init / Cleanup - // ****************************************************************** - void DInputInit(HWND hwnd); - void DInputCleanup(); - - // ****************************************************************** - // * Check if a device is currently in the configuration - // ****************************************************************** - bool DeviceIsUsed(const char *szDeviceName); - - // ****************************************************************** - // * Settings for DirectInput Device(s) - // ****************************************************************** - Settings::s_controller_dinput m_settings; - - private: - // ****************************************************************** - // * Object Mapping - // ****************************************************************** - void Map(XBCtrlObject object, const char *szDeviceName, int dwInfo, int dwFlags); - - // ****************************************************************** - // * Find the look-up value for a DeviceName (creating if needed) - // ****************************************************************** - int Insert(const char *szDeviceName); - - // ****************************************************************** - // * Update the object lookup offsets for a device - // ****************************************************************** - void ReorderObjects(const char *szDeviceName, int pos); - - // ****************************************************************** - // * Controller and Objects Enumeration - // ****************************************************************** - BOOL EnumGameCtrlCallback(XTL::LPCDIDEVICEINSTANCE lpddi); - BOOL EnumObjectsCallback(XTL::LPCDIDEVICEOBJECTINSTANCE lpddoi); - - // ****************************************************************** - // * Wrapper Function for Enumeration - // ****************************************************************** - friend BOOL CALLBACK WrapEnumGameCtrlCallback(XTL::LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef); - friend BOOL CALLBACK WrapEnumObjectsCallback(XTL::LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef); - - // ****************************************************************** - // * DirectInput - // ****************************************************************** - XTL::LPDIRECTINPUT8 m_pDirectInput8; - - // ****************************************************************** - // * DirectInput Devices - // ****************************************************************** - struct InputDevice - { - XTL::LPDIRECTINPUTDEVICE8 m_Device; - int m_Flags; - } - m_InputDevice[XBCTRL_MAX_DEVICES]; - - // ****************************************************************** - // * Current State - // ****************************************************************** - enum XBCtrlState m_CurrentState; - - // ****************************************************************** - // * Config State Variables - // ****************************************************************** - LONG lPrevMouseX, lPrevMouseY, lPrevMouseZ; - XBCtrlObject CurConfigObject; - - // ****************************************************************** - // * Etc State Variables - // ****************************************************************** - int m_dwInputDeviceCount; - int m_dwCurObject; -}; - -// ****************************************************************** -// * Device Flags -// ****************************************************************** -#define DEVICE_FLAG_JOYSTICK (1 << 0) -#define DEVICE_FLAG_KEYBOARD (1 << 1) -#define DEVICE_FLAG_MOUSE (1 << 2) -#define DEVICE_FLAG_AXIS (1 << 3) -#define DEVICE_FLAG_BUTTON (1 << 4) -#define DEVICE_FLAG_POSITIVE (1 << 5) -#define DEVICE_FLAG_NEGATIVE (1 << 6) -#define DEVICE_FLAG_MOUSE_CLICK (1 << 7) -#define DEVICE_FLAG_MOUSE_LX (1 << 8) -#define DEVICE_FLAG_MOUSE_LY (1 << 9) -#define DEVICE_FLAG_MOUSE_LZ (1 << 10) - -// ****************************************************************** -// * Detection Sensitivity -// ****************************************************************** -#define DETECT_SENSITIVITY_JOYSTICK 25000 -#define DETECT_SENSITIVITY_BUTTON 0 -#define DETECT_SENSITIVITY_MOUSE 5 -#define DETECT_SENSITIVITY_POV 50000 - -// ****************************************************************** -// * DirectInput Enumeration Types -// ****************************************************************** -enum XBCtrlState -{ - XBCTRL_STATE_NONE = 0, - XBCTRL_STATE_CONFIG, - XBCTRL_STATE_LISTEN -}; - -#endif diff --git a/src/common/win32/EmuShared.cpp b/src/common/win32/EmuShared.cpp index 8cfb736110..7210bd386d 100644 --- a/src/common/win32/EmuShared.cpp +++ b/src/common/win32/EmuShared.cpp @@ -140,6 +140,11 @@ EmuShared::EmuShared() m_Reserved6 = 0.0f; std::memset(m_Reserved7, 0, sizeof(m_Reserved7)); std::memset(m_Reserved99, 0, sizeof(m_Reserved99)); + std::memset(m_DeviceControlNames, '\0', sizeof(m_DeviceControlNames)); + std::memset(m_DeviceName, '\0', sizeof(m_DeviceName)); + for (auto& i : m_DeviceType) { + i = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); + } } // ****************************************************************** diff --git a/src/common/win32/EmuShared.h b/src/common/win32/EmuShared.h index cf9a7c6ef7..130e48e444 100644 --- a/src/common/win32/EmuShared.h +++ b/src/common/win32/EmuShared.h @@ -29,6 +29,7 @@ #include "common\Settings.hpp" #include "Mutex.h" #include "common\IPCHybrid.hpp" +#include "common\input\Button.h" #include @@ -115,13 +116,31 @@ class EmuShared : public Mutex void GetNetworkSettings(Settings::s_network *network) { Lock(); *network = m_network; Unlock(); } void SetNetworkSettings(const Settings::s_network *network) { Lock(); m_network = *network; Unlock(); } - // ****************************************************************** - // * Xbox Controller Accessors - // ****************************************************************** - void GetControllerDInputSettings( Settings::s_controller_dinput *ctrl) { Lock(); *ctrl = m_controller_dinput; Unlock(); } - void SetControllerDInputSettings(const Settings::s_controller_dinput *ctrl) { Lock(); m_controller_dinput = *ctrl; Unlock(); } - void GetControllerPortSettings( Settings::s_controller_port *ctrl) { Lock(); *ctrl = m_controller_port; Unlock(); } - void SetControllerPortSettings(const Settings::s_controller_port *ctrl) { Lock(); m_controller_port = *ctrl; Unlock(); } + // ****************************************************************** + // * Input config Accessors + // ****************************************************************** + void GetInputDevTypeSettings(int* type, int port) { Lock(); *type = m_DeviceType[port]; Unlock(); } + void SetInputDevTypeSettings(const int* type, int port) { Lock(); m_DeviceType[port] = *type; Unlock(); } + void GetInputDevNameSettings(char* name, int port) { Lock(); strncpy(name, m_DeviceName[port], 50); Unlock(); } + void SetInputDevNameSettings(const char* name, int port) { Lock(); strncpy(m_DeviceName[port], name, 50); Unlock(); } + void GetInputBindingsSettings(char button_str[][30], int max_num_buttons, int port) + { + assert(max_num_buttons <= XBOX_CTRL_NUM_BUTTONS); + Lock(); + for (int i = 0; i < max_num_buttons; i++) { + strncpy(button_str[i], m_DeviceControlNames[port][i], 30); + } + Unlock(); + } + void SetInputBindingsSettings(const char button_str[][30], int max_num_buttons, int port) + { + assert(max_num_buttons <= XBOX_CTRL_NUM_BUTTONS); + Lock(); + for (int i = 0; i < max_num_buttons; i++) { + strncpy(m_DeviceControlNames[port][i], button_str[i], 30); + } + Unlock(); + } // ****************************************************************** // * LLE Flags Accessors @@ -246,13 +265,14 @@ class EmuShared : public Mutex bool m_bReserved2; bool m_bReserved3; bool m_bReserved4; - unsigned int m_dwKrnlProcID; // Only used for kernel mode level. - int m_Reserved99[32]; // Reserve space + unsigned int m_dwKrnlProcID; // Only used for kernel mode level. + int m_DeviceType[4]; + char m_DeviceControlNames[4][XBOX_CTRL_NUM_BUTTONS][30]; // macro should be num of buttons of dev with highest num buttons + char m_DeviceName[4][50]; + int m_Reserved99[28]; // Reserve space // Settings class in memory should not be tampered by third-party. - // Third-party program should only be allow to edit settings.ini file. - Settings::s_controller_dinput m_controller_dinput; - Settings::s_controller_port m_controller_port; + // Third-party program should only be allow to edit settings.ini file. Settings::s_core m_core; Settings::s_video m_video; Settings::s_audio m_audio; diff --git a/src/common/win32/IPCWindows.cpp b/src/common/win32/IPCWindows.cpp index 9bf97c77b3..1f491b25d0 100644 --- a/src/common/win32/IPCWindows.cpp +++ b/src/common/win32/IPCWindows.cpp @@ -90,6 +90,10 @@ void ipc_send_kernel_update(IPC_UPDATE_KERNEL command, const unsigned int value, cmdParam = ID_SYNC_CONFIG_LOGGING; break; + case IPC_UPDATE_KERNEL::CONFIG_INPUT_SYNC: + cmdParam = ID_SYNC_CONFIG_INPUT; + break; + default: cmdParam = 0; break; diff --git a/src/common/win32/XBPortMapping.cpp b/src/common/win32/XBPortMapping.cpp deleted file mode 100644 index 23cb3285ed..0000000000 --- a/src/common/win32/XBPortMapping.cpp +++ /dev/null @@ -1,80 +0,0 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -// ****************************************************************** -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2002-2003 Aaron Robinson -// * -// * All rights reserved -// * -// ****************************************************************** -#define LOG_PREFIX CXBXR_MODULE::XBPM - -#undef FIELD_OFFSET // prevent macro redefinition warnings -/* prevent name collisions */ -namespace xboxkrnl -{ - #include -}; - -#include -#include "EmuShared.h" -#include "common\Settings.hpp" -#include "Logging.h" - -static Settings::s_controller_port g_ControllerPortMap; - -void XBPortMappingSet(Settings::s_controller_port &controller_port_settings) -{ - g_ControllerPortMap = controller_port_settings; -} - -// ****************************************************************** -// * func: Save -// ****************************************************************** -void XBPortMappingGet(Settings::s_controller_port &controller_port_settings) -{ - controller_port_settings = g_ControllerPortMap; -} - -//Set HostType and HostPort setting from global array per xbox port. The setted value will take effect from next time xbe loading. -void SetXboxPortToHostPort(DWORD dwXboxPort, DWORD dwHostType, DWORD dwHostPort) -{ - //set host type and host port in global array per xbox port, will be used when xbe get reloaded. - //only host type and host port can be set in this time. because the xbox DeviceType can only be determined when loading the xbe. - g_ControllerPortMap.XboxPortMapHostType[dwXboxPort] = dwHostType; - g_ControllerPortMap.XboxPortMapHostPort[dwXboxPort] = dwHostPort; -} -//retrieve HostType and HostPort setting from global array per xbox port. -void GetXboxPortToHostPort(DWORD dwXboxPort, DWORD &dwHostType, DWORD &dwHostPort) -{ - //get Host Type and Host Port per xbox port - dwHostType = g_ControllerPortMap.XboxPortMapHostType[dwXboxPort]; - dwHostPort = g_ControllerPortMap.XboxPortMapHostPort[dwXboxPort]; -} - -DWORD GetXboxPortMapHostType(DWORD dwXboxPort) -{ - return g_ControllerPortMap.XboxPortMapHostType[dwXboxPort]; -} - -DWORD GetXboxPortMapHostPort(DWORD dwXboxPort) -{ - return g_ControllerPortMap.XboxPortMapHostPort[dwXboxPort]; -} diff --git a/src/common/win32/XBPortMapping.h b/src/common/win32/XBPortMapping.h deleted file mode 100644 index 3b974fa1e6..0000000000 --- a/src/common/win32/XBPortMapping.h +++ /dev/null @@ -1,44 +0,0 @@ -// ****************************************************************** -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2002-2003 Aaron Robinson -// * -// * All rights reserved -// * -// ****************************************************************** -#ifndef XBPORTMAPPING_H -#define XBPORTMAPPING_H - -extern void SetXboxPortToHostPort(DWORD dwXboxPort, DWORD dwHostType, DWORD dwHostPort); - -extern void GetXboxPortToHostPort(DWORD dwXboxPort, DWORD &dwHostType, DWORD &dwHostPort); - -extern DWORD GetXboxPortMapHostType(DWORD dwXboxPort); - -extern DWORD GetXboxPortMapHostPort(DWORD dwXboxPort); -// ****************************************************************** -// * Set configuration -// ****************************************************************** -extern void XBPortMappingSet(Settings::s_controller_port &controller_port_settings); - -// ****************************************************************** -// * Get configuration -// ****************************************************************** -extern void XBPortMappingGet(Settings::s_controller_port &controller_port_settings); -#endif diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 7861850dca..d3f1a978c5 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -51,7 +51,8 @@ namespace xboxkrnl #include "devices\video\nv2a.h" // For GET_MASK, NV_PGRAPH_CONTROL_0 #include "gui\ResCxbx.h" #include "WalkIndexBuffer.h" -#include "core/kernel/common/strings.hpp" // For uem_str +#include "core\kernel\common\strings.hpp" // For uem_str +#include "common\input\SdlJoystick.h" #include #include @@ -1433,10 +1434,7 @@ VOID XTL::EmuD3DInit() } // cleanup Direct3D -VOID XTL::EmuD3DCleanup() -{ - XTL::EmuDInputCleanup(); -} +VOID XTL::EmuD3DCleanup() {} // enumeration procedure for locating display device GUIDs static BOOL WINAPI EmuEnumDisplayDevices(GUID FAR *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID lpContext, HMONITOR hm) @@ -1538,13 +1536,6 @@ static DWORD WINAPI EmuRenderWindow(LPVOID lpVoid) SetFocus(CxbxKrnl_hEmuParent); } - // initialize direct input only if LLE USB is off - if (!bLLE_USB) { - if (!XTL::EmuDInputInit()) { - CxbxKrnlCleanup("Could not initialize DirectInput!"); - } - } - EmuLog(LOG_LEVEL::DEBUG, "Message-Pump thread is running."); SetFocus(g_hEmuWindow); @@ -1679,6 +1670,16 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar } break; + case ID_SYNC_CONFIG_INPUT: + { + SDL_Event UpdateInputEvent; + SDL_memset(&UpdateInputEvent, 0, sizeof(SDL_Event)); + UpdateInputEvent.type = Sdl::UpdateInputEvent_t; + UpdateInputEvent.user.data1 = new int(lParam); + SDL_PushEvent(&UpdateInputEvent); + } + break; + default: break; } @@ -1852,34 +1853,6 @@ static DWORD WINAPI EmuUpdateTickCount(LPVOID) while(true) { SwitchToThread(); - // - // Poll input - // - int port; - for (port = 0; port < 4;port++) { - extern XTL::X_CONTROLLER_HOST_BRIDGE g_XboxControllerHostBridge[4]; - if (g_XboxControllerHostBridge[port].hXboxDevice == 0) - continue; - if (g_XboxControllerHostBridge[port].pXboxFeedbackHeader == 0) - continue; - DWORD dwLatency = g_XboxControllerHostBridge[port].dwLatency++; - - if (dwLatency < XINPUT_SETSTATE_LATENCY) - continue; - - g_XboxControllerHostBridge[port].dwLatency = 0; - - if (g_XboxControllerHostBridge[port].pXboxFeedbackHeader->dwStatus != ERROR_SUCCESS) - { - if (g_XboxControllerHostBridge[port].pXboxFeedbackHeader->hEvent != 0) - { - SetEvent(g_XboxControllerHostBridge[port].pXboxFeedbackHeader->hEvent); - } - - g_XboxControllerHostBridge[port].pXboxFeedbackHeader->dwStatus = ERROR_SUCCESS; - } - - } // If VBlank Interval has passed, trigger VBlank callback // Note: This whole code block can be removed once NV2A interrupts are implemented diff --git a/src/core/hle/XAPI/OHCI/XInput/DInput.cpp b/src/core/hle/XAPI/OHCI/XInput/DInput.cpp deleted file mode 100644 index b366badfe3..0000000000 --- a/src/core/hle/XAPI/OHCI/XInput/DInput.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -// ****************************************************************** -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2002-2003 Aaron Robinson -// * -// * All rights reserved -// * -// ****************************************************************** - -#define LOG_PREFIX CXBXR_MODULE::DINP - -#include "core\kernel\support\Emu.h" -#include "core\kernel\support\EmuXTL.h" -#include "EmuShared.h" -#include "common\Win32\DInputController.h" -#include "Logging.h" - -// ****************************************************************** -// * Static Variable(s) -// ****************************************************************** -static DInputController g_DInputController; - -// ****************************************************************** -// * XTL::EmuDInputInit -// ****************************************************************** -bool XTL::EmuDInputInit() -{ - g_EmuShared->GetControllerDInputSettings(&g_DInputController.m_settings); - - g_DInputController.ListenBegin(g_hEmuWindow); - - if(g_DInputController.HasError()) - return false; - - return true; -} - -// ****************************************************************** -// * XTL::EmuDInputCleanup -// ****************************************************************** -void XTL::EmuDInputCleanup() -{ - g_DInputController.ListenEnd(); -} - -//emulated dwPacketNumber for DirectInput controller -DWORD dwPacketNumber_DirectInput = 0; - -// ****************************************************************** -// * XTL::EmuDInputPoll -// ****************************************************************** -void XTL::EmuDInputPoll(XTL::PX_XINPUT_STATE pXboxController) -{ - g_DInputController.ListenPoll(pXboxController); - //increment of emulated PacketNumber and report back to Controller. - dwPacketNumber_DirectInput++; - pXboxController->dwPacketNumber = dwPacketNumber_DirectInput; - - if(g_DInputController.HasError()) - MessageBox(NULL, g_DInputController.GetError().c_str(), "Cxbx-Reloaded [*UNHANDLED!*]", MB_OK); // TODO: Handle this! - - return; -} diff --git a/src/core/hle/XAPI/OHCI/XInput/DInput.h b/src/core/hle/XAPI/OHCI/XInput/DInput.h deleted file mode 100644 index b3c7a8af8d..0000000000 --- a/src/core/hle/XAPI/OHCI/XInput/DInput.h +++ /dev/null @@ -1,46 +0,0 @@ -// ****************************************************************** -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2002-2003 Aaron Robinson -// * -// * All rights reserved -// * -// ****************************************************************** -#ifndef DINPUT_H -#define DINPUT_H - -#define DIRECTINPUT_VERSION 0x0800 -#include - -// ****************************************************************** -// * patch: DInputInit -// ****************************************************************** -extern bool EmuDInputInit(); - -// ****************************************************************** -// * patch: DInputCleanup -// ****************************************************************** -extern void EmuDInputCleanup(); - -// ****************************************************************** -// * patch: DInputPoll -// ****************************************************************** -extern void EmuDInputPoll(PX_XINPUT_STATE Controller); - -#endif diff --git a/src/core/hle/XAPI/OHCI/XInput/XInput.cpp b/src/core/hle/XAPI/OHCI/XInput/XInput.cpp deleted file mode 100644 index a28d7b3794..0000000000 --- a/src/core/hle/XAPI/OHCI/XInput/XInput.cpp +++ /dev/null @@ -1,167 +0,0 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -// ****************************************************************** -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2002-2003 Aaron Robinson -// * -// * All rights reserved -// * -// ****************************************************************** - -#define LOG_PREFIX CXBXR_MODULE::XINP - -#include "core\kernel\support\Emu.h" -#include "core\kernel\support\EmuXTL.h" -#include "EmuShared.h" -#include "XInput.h" - -#include -#include "Logging.h" - - -// ****************************************************************** -// * Static Variable(s) -// ****************************************************************** -static XINPUT_STATE g_Controller;//global controller input state for host. -static BOOL g_bXInputInitialized = FALSE; - -// -// -// -DWORD XTL::XInputGamepad_Connected(void) -{ - DWORD dwResult; - DWORD gamepad_connected = 0; - for (DWORD i = 0; i< 4; i++) - { - ZeroMemory(&g_Controller, sizeof(XINPUT_STATE)); - - // query each port for gamepad state - dwResult = XInputGetState(i, &g_Controller); - - //success means gamepad is connected - if (dwResult == ERROR_SUCCESS) - { - gamepad_connected++; - } - } - return gamepad_connected; -} -// ****************************************************************** -// * patch: XInputPCPoll -// ****************************************************************** -void XTL::EmuXInputPCPoll( DWORD dwPort,XTL::PX_XINPUT_STATE pXboxController ) -{ - // - // Get the PC's XInput values - // - - if( XInputGetState( dwPort, &g_Controller ) != ERROR_SUCCESS ) - return; - - //Packet# must be updated to trigger the xbe processing the input state. - pXboxController->dwPacketNumber = g_Controller.dwPacketNumber; - - // - // Now convert those values to Xbox XInput - // - // Analog Sticks - pXboxController->Gamepad.sThumbLX = g_Controller.Gamepad.sThumbLX; - pXboxController->Gamepad.sThumbLY = g_Controller.Gamepad.sThumbLY; - pXboxController->Gamepad.sThumbRX = g_Controller.Gamepad.sThumbRX; - pXboxController->Gamepad.sThumbRY = g_Controller.Gamepad.sThumbRY; - - // Analog Buttons - pXboxController->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_A] = (g_Controller.Gamepad.wButtons & XINPUT_GAMEPAD_A) ? 255 : 0; - pXboxController->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_B] = (g_Controller.Gamepad.wButtons & XINPUT_GAMEPAD_B) ? 255 : 0; - pXboxController->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_X] = (g_Controller.Gamepad.wButtons & XINPUT_GAMEPAD_X) ? 255 : 0; - pXboxController->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_Y] = (g_Controller.Gamepad.wButtons & XINPUT_GAMEPAD_Y) ? 255 : 0; - pXboxController->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_WHITE] = (g_Controller.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) ? 255 : 0; - pXboxController->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_BLACK] = (g_Controller.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) ? 255 : 0; - pXboxController->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_LEFT_TRIGGER] = g_Controller.Gamepad.bLeftTrigger; - pXboxController->Gamepad.bAnalogButtons[X_XINPUT_GAMEPAD_RIGHT_TRIGGER] = g_Controller.Gamepad.bRightTrigger; - - // Digital Buttons - if (g_Controller.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) { - pXboxController->Gamepad.wButtons |= X_XINPUT_GAMEPAD_BACK; - } else { - pXboxController->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_BACK; - } - - if (g_Controller.Gamepad.wButtons & XINPUT_GAMEPAD_START) { - pXboxController->Gamepad.wButtons |= X_XINPUT_GAMEPAD_START; - } else { - pXboxController->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_START; - } - - if (g_Controller.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) { - pXboxController->Gamepad.wButtons |= X_XINPUT_GAMEPAD_LEFT_THUMB; - } else { - pXboxController->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_LEFT_THUMB; - } - - if (g_Controller.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) { - pXboxController->Gamepad.wButtons |= X_XINPUT_GAMEPAD_RIGHT_THUMB; - } else { - pXboxController->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_RIGHT_THUMB; - } - - if (g_Controller.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) { - pXboxController->Gamepad.wButtons |= X_XINPUT_GAMEPAD_DPAD_UP; - } else { - pXboxController->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_DPAD_UP; - } - - if (g_Controller.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) { - pXboxController->Gamepad.wButtons |= X_XINPUT_GAMEPAD_DPAD_DOWN; - } else { - pXboxController->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_DPAD_DOWN; - } - - if (g_Controller.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) { - pXboxController->Gamepad.wButtons |= X_XINPUT_GAMEPAD_DPAD_LEFT; - } else { - pXboxController->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_DPAD_LEFT; - } - - if (g_Controller.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) { - pXboxController->Gamepad.wButtons |= X_XINPUT_GAMEPAD_DPAD_RIGHT; - } else { - pXboxController->Gamepad.wButtons &= ~X_XINPUT_GAMEPAD_DPAD_RIGHT; - } -} - - -// ****************************************************************** -// * Native implementation of XInputSetState -// ****************************************************************** -void XTL::EmuXInputSetState(DWORD dwPort, XTL::PX_XINPUT_FEEDBACK Feedback) -{ - XINPUT_VIBRATION FrameVibration = - { - Feedback->Rumble.wLeftMotorSpeed, - Feedback->Rumble.wRightMotorSpeed - }; - - // - // Set the PC XInput state - - XInputSetState(dwPort, &FrameVibration); -} diff --git a/src/core/hle/XAPI/Xapi.cpp b/src/core/hle/XAPI/Xapi.cpp index 92158e79ec..8cdbebe7f0 100644 --- a/src/core/hle/XAPI/Xapi.cpp +++ b/src/core/hle/XAPI/Xapi.cpp @@ -33,7 +33,9 @@ namespace xboxkrnl { #include }; - + +#include "common\input\SdlJoystick.h" +#include "common\input\InputManager.h" #include #include "core\kernel\init\CxbxKrnl.h" #include "Logging.h" @@ -43,19 +45,12 @@ namespace xboxkrnl #include "core\kernel\support\EmuFS.h" #include "core\kernel\support\EmuXTL.h" #include "EmuShared.h" -#include "..\common\win32\XBPortMapping.h" #include "core\hle\Intercept.hpp" #include "vsbc\CxbxVSBC.h" #include "Windef.h" -#include - -// XInputSetState status waiters -extern XInputSetStateStatus g_pXInputSetStateStatus[XINPUT_SETSTATE_SLOTS] = {0}; +#include +#include "core\hle\XAPI\XapiCxbxr.h" -// XInputOpen handles -extern HANDLE g_hInputHandle[XINPUT_HANDLE_SLOTS] = {0}; - -bool g_bXInputOpenCalled = false; bool g_bCxbxVSBCLoaded = false; HINSTANCE g_module; typedef int (FAR WINAPI *PFARPROC1)(int); @@ -75,91 +70,100 @@ XTL::PXPP_DEVICE_TYPE g_DeviceType_Gamepad = nullptr; // Flag is set after gamepad state has been queried by the title. Supports defer gamepad connection hack bool g_gamepadStateQueriedHackFlag = false; -XTL::X_POLLING_PARAMETERS_HANDLE g_pph[4]; -XTL::X_XINPUT_POLLING_PARAMETERS g_pp[4]; -//for host connected gamepad -DWORD total_xinput_gamepad = 0; //global bridge for xbox controller to host, 4 elements for 4 ports. -XTL::X_CONTROLLER_HOST_BRIDGE g_XboxControllerHostBridge[4] = {}; -//global xbox xinput device info from interpreting device table. -std::vector g_XboxInputDeviceInfo; - - - -//look for xbox Device info from global info vector, and return the found index. return -1 for not found. -int FindDeviceInfoIndexByXboxType(UCHAR ucType) -{ - size_t i; - for (i = 0; i < g_XboxInputDeviceInfo.size(); i++) { - if (g_XboxInputDeviceInfo[i].ucType == ucType) { - return i; - } - } - return -1; -} +X_CONTROLLER_HOST_BRIDGE g_XboxControllerHostBridge[4] = { + { NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, nullptr, false, false, false, { 0, 0, 0, 0, 0 } }, + { NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, nullptr, false, false, false, { 0, 0, 0, 0, 0 } }, + { NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, nullptr, false, false, false, { 0, 0, 0, 0, 0 } }, + { NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, nullptr, false, false, false, { 0, 0, 0, 0, 0 } }, +}; -//look for xbox Device info from global info vector, and return the found index. return -1 for not found. -int FindDeviceInfoIndexByDeviceType(XTL::PXPP_DEVICE_TYPE DeviceType) -{ - size_t i; - for (i = 0; i < g_XboxInputDeviceInfo.size(); i++) { - if (g_XboxInputDeviceInfo[i].DeviceType == DeviceType) { - return i; - } - } - return -1; -} + +bool operator==(XTL::PXPP_DEVICE_TYPE XppType, XBOX_INPUT_DEVICE XidType) +{ + switch (XidType) + { + case XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE: { + if (XppType == g_DeviceType_Gamepad) { + return true; + } + } + break; + + case XBOX_INPUT_DEVICE::MS_CONTROLLER_S: + case XBOX_INPUT_DEVICE::LIGHT_GUN: + case XBOX_INPUT_DEVICE::STEERING_WHEEL: + case XBOX_INPUT_DEVICE::MEMORY_UNIT: + case XBOX_INPUT_DEVICE::IR_DONGLE: + case XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER: + default: + break; + } + return false; +} + +bool operator!=(XTL::PXPP_DEVICE_TYPE XppType, XBOX_INPUT_DEVICE XidType) +{ + return !(XppType == XidType); +} + +bool ConstructHleInputDevice(int Type, int Port) +{ + switch (Type) + { + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): { + g_XboxControllerHostBridge[Port].XboxPort = Port; + g_XboxControllerHostBridge[Port].XboxType = XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE; + g_XboxControllerHostBridge[Port].InState = new XpadInput(); + g_XboxControllerHostBridge[Port].bPendingRemoval = false; + g_XboxControllerHostBridge[Port].bSignaled = false; + g_XboxControllerHostBridge[Port].bIoInProgress = false; + g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucType = XINPUT_DEVTYPE_GAMEPAD; + g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD; + g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize = sizeof(XpadInput); + g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucFeedbackSize = sizeof(XpadOutput); + g_XboxControllerHostBridge[Port].XboxDeviceInfo.dwPacketNumber = 0; + } + break; + + case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): { + // TODO + } + break; + + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): + case to_underlying(XBOX_INPUT_DEVICE::LIGHT_GUN): + case to_underlying(XBOX_INPUT_DEVICE::STEERING_WHEEL): + case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT): + case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE): { + EmuLog(LOG_LEVEL::INFO, "%s: device %s is not yet supported", __func__, GetInputDeviceName(Type).c_str()); + return false; + } + + default: + EmuLog(LOG_LEVEL::WARNING, "Attempted to attach an unknown device type (type was %d)", Type); + return false; + } + + return true; +} + +void DestructHleInputDevice(int Port) +{ + g_XboxControllerHostBridge[Port].XboxType = XBOX_INPUT_DEVICE::DEVICE_INVALID; + g_XboxControllerHostBridge[Port].XboxPort = PORT_INVALID; + while (g_XboxControllerHostBridge[Port].bIoInProgress) {} + delete g_XboxControllerHostBridge[Port].InState; + g_XboxControllerHostBridge[Port].bPendingRemoval = false; + g_XboxControllerHostBridge[Port].bSignaled = false; + g_XboxControllerHostBridge[Port].bIoInProgress = false; + g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucType = 0; + g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucSubType = 0; + g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize = 0; + g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucFeedbackSize = 0; + g_XboxControllerHostBridge[Port].XboxDeviceInfo.dwPacketNumber = 0; +} -//init XboxControllerHostBridge's content, also put interpreted data from device table to it. -//this is called in the end of SetupXboxDeviceTypes(), later we'll move this code to accept user configuration. -void InitXboxControllerHostBridge(void) -{ - //load host type and port configuration from settings. - Settings::s_controller_port ControllerPortMap; - g_EmuShared->GetControllerPortSettings(&ControllerPortMap); - XBPortMappingSet(ControllerPortMap); - total_xinput_gamepad = XTL::XInputGamepad_Connected(); - - int port; - for (port = 0; port < 4; port++) { - g_XboxControllerHostBridge[port].dwHostType = GetXboxPortMapHostType(port); - g_XboxControllerHostBridge[port].dwHostPort = GetXboxPortMapHostPort(port); - g_XboxControllerHostBridge[port].XboxDeviceInfo.ucType = X_XINPUT_DEVTYPE_GAMEPAD; - switch (GetXboxPortMapHostType(port)) { - case X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT: - //disconnect to host if the host port of xinput exceeds the total xinput controller connected to host. - if (g_XboxControllerHostBridge[port].dwHostPort >= total_xinput_gamepad) { - g_XboxControllerHostBridge[port].dwHostType = X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_NOTCONNECT; - EmuLog(LOG_LEVEL::DEBUG, "InitXboxControllerHostBridge: Host XInput port greater then total xinput controller connected. disconnect xbox port from host!"); - } - break; - case X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_DINPUT: - break; - case X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_VIRTUAL_SBC: - g_XboxControllerHostBridge[port].XboxDeviceInfo.ucType = X_XINPUT_DEVTYPE_STEELBATALION; - break; - default: - break; - } - g_XboxControllerHostBridge[port].dwXboxPort = port; - //xbox device handle set to 0 before being open. - g_XboxControllerHostBridge[port].hXboxDevice = 0; - int index; - //find corresponding XboxDeviceInfo - index=FindDeviceInfoIndexByXboxType(g_XboxControllerHostBridge[port].XboxDeviceInfo.ucType); - if (index == -1) { - EmuLog(LOG_LEVEL::DEBUG, "XboxControllerHostBridge XboxDeviceInfo.ucType: %d not found in global XboxInputDeviceInfo vector!", g_XboxControllerHostBridge[port].XboxDeviceInfo.ucType); - } - //copy XboxDeviceInfo from the global vector. - g_XboxControllerHostBridge[port].XboxDeviceInfo.ucSubType = g_XboxInputDeviceInfo[index].ucSubType; - g_XboxControllerHostBridge[port].XboxDeviceInfo.DeviceType = g_XboxInputDeviceInfo[index].DeviceType; - g_XboxControllerHostBridge[port].XboxDeviceInfo.ucInputStateSize = g_XboxInputDeviceInfo[index].ucInputStateSize; - g_XboxControllerHostBridge[port].XboxDeviceInfo.ucFeedbackSize = g_XboxInputDeviceInfo[index].ucFeedbackSize; - //these two members are not used yet. - g_XboxControllerHostBridge[port].pXboxState = 0; - g_XboxControllerHostBridge[port].pXboxFeedbackHeader = 0; - } -} void SetupXboxDeviceTypes() { // If we don't yet have the offset to gDeviceType_Gamepad, work it out! @@ -194,35 +198,20 @@ void SetupXboxDeviceTypes() printf("----------------------------------------\n"); printf("DeviceTable[%u]->ucType = %d\n", i, deviceTable[i]->ucType); - printf("DeviceTable[%u]->XppType = 0x%08X (", i, deviceTable[i]->XppType); - - XTL::X_XINPUT_DEVICE_INFO CurrentInfo = {}; - CurrentInfo.ucType = deviceTable[i]->ucType; - CurrentInfo.DeviceType = deviceTable[i]->XppType; - if (deviceTable[i]->pInputStateDesc!=0) { - CurrentInfo.ucInputStateSize = deviceTable[i]->pInputStateDesc->ucSize; - } - if(deviceTable[i]->pFeedbackDesc!=0){ - CurrentInfo.ucFeedbackSize = deviceTable[i]->pFeedbackDesc->ucSize; - } + printf("DeviceTable[%u]->XppType = 0x%08X (", i, (uintptr_t)deviceTable[i]->XppType); switch (deviceTable[i]->ucType) { - case X_XINPUT_DEVTYPE_GAMEPAD: - g_DeviceType_Gamepad = deviceTable[i]->XppType; - CurrentInfo.ucSubType = X_XINPUT_DEVSUBTYPE_GC_GAMEPAD; - printf("XDEVICE_TYPE_GAMEPAD)\n"); - break; - case X_XINPUT_DEVTYPE_STEELBATALION: + case XINPUT_DEVTYPE_GAMEPAD: + g_DeviceType_Gamepad = deviceTable[i]->XppType; + printf("XDEVICE_TYPE_GAMEPAD)\n"); + break; + case XINPUT_DEVTYPE_STEELBATALION: printf("XDEVICE_TYPE_STEELBATALION)\n"); - CurrentInfo.ucSubType = X_XINPUT_DEVSUBTYPE_GC_GAMEPAD_ALT; break; default: printf("Unknown device type)\n"); continue; } - - //store the DeviceInfo in global vector. - g_XboxInputDeviceInfo.push_back(CurrentInfo); } } else { // XDKs without GetTypeInformation have the GamePad address hardcoded in XInputOpen @@ -230,18 +219,8 @@ void SetupXboxDeviceTypes() // so this works well for us. void* XInputOpenAddr = (void*)g_SymbolAddresses["XInputOpen"]; if (XInputOpenAddr != nullptr) { - printf("XAPI: Deriving XDEVICE_TYPE_GAMEPAD from XInputOpen (0x%08X)\n", XInputOpenAddr); + printf("XAPI: Deriving XDEVICE_TYPE_GAMEPAD from XInputOpen (0x%08X)\n", (uintptr_t)XInputOpenAddr); g_DeviceType_Gamepad = *(XTL::PXPP_DEVICE_TYPE*)((uint32_t)XInputOpenAddr + 0x0B); - - //only have one GAMEPAD device type. setup global DeviceInfo vector accordingly. - XTL::X_XINPUT_DEVICE_INFO CurrentInfo = {}; - CurrentInfo.ucType = X_XINPUT_DEVTYPE_GAMEPAD; - CurrentInfo.ucSubType = X_XINPUT_DEVSUBTYPE_GC_GAMEPAD; - CurrentInfo.DeviceType = g_DeviceType_Gamepad; - CurrentInfo.ucInputStateSize = sizeof(XTL::X_XINPUT_GAMEPAD); - CurrentInfo.ucFeedbackSize = sizeof(XTL::X_XINPUT_RUMBLE); - //store the DeviceInfo in global vector. - g_XboxInputDeviceInfo.push_back(CurrentInfo); } } @@ -250,7 +229,7 @@ void SetupXboxDeviceTypes() return; } - printf("XAPI: XDEVICE_TYPE_GAMEPAD Found at 0x%08X\n", g_DeviceType_Gamepad); + printf("XAPI: XDEVICE_TYPE_GAMEPAD Found at 0x%08X\n", (uintptr_t)g_DeviceType_Gamepad); } } @@ -263,27 +242,12 @@ VOID WINAPI XTL::EMUPATCH(XInitDevices) PXDEVICE_PREALLOC_TYPE PreallocTypes ) { - - LOG_FUNC_BEGIN LOG_FUNC_ARG(dwPreallocTypeCount) LOG_FUNC_ARG((DWORD)PreallocTypes) LOG_FUNC_END; -/* for(int v=0;vCurrentConnected == 0) { - for (int port = 0; port < 4; port++) { - // If the host controller is connected and the Xbox DeviceType matches, set the CurrentConnected flag. - if (g_XboxControllerHostBridge[port].XboxDeviceInfo.DeviceType == DeviceType && g_XboxControllerHostBridge[port].dwHostType > 0) { - DeviceType->CurrentConnected |= 1 << port; + int Port, PortMask; + for (Port = PORT_1, PortMask = 1; Port <= PORT_4; Port++, PortMask <<= 1) { + if (DeviceType == g_XboxControllerHostBridge[Port].XboxType) { + if (!g_XboxControllerHostBridge[Port].bPendingRemoval) { + DeviceType->CurrentConnected |= PortMask; + } + else { + if (!g_XboxControllerHostBridge[Port].bSignaled) { + g_XboxControllerHostBridge[Port].bSignaled = true; + SDL_Event DeviceRemoveEvent; + SDL_memset(&DeviceRemoveEvent, 0, sizeof(SDL_Event)); + DeviceRemoveEvent.type = Sdl::DeviceRemoveAck_t; + DeviceRemoveEvent.user.data1 = new int(Port); + SDL_PushEvent(&DeviceRemoveEvent); + } + DeviceType->CurrentConnected &= ~PortMask; } } - DeviceType->ChangeConnected = DeviceType->CurrentConnected; - } + else { + DeviceType->CurrentConnected &= ~PortMask; + } + } + DeviceType->ChangeConnected = DeviceType->PreviousConnected ^ DeviceType->CurrentConnected; } // ****************************************************************** @@ -323,8 +300,6 @@ DWORD WINAPI XTL::EMUPATCH(XGetDevices) PXPP_DEVICE_TYPE DeviceType ) { - - LOG_FUNC_ONE_ARG(DeviceType); UpdateConnectedDeviceState(DeviceType); @@ -354,9 +329,7 @@ BOOL WINAPI XTL::EMUPATCH(XGetDeviceChanges) PDWORD pdwInsertions, PDWORD pdwRemovals ) -{ - - +{ LOG_FUNC_BEGIN LOG_FUNC_ARG(DeviceType) LOG_FUNC_ARG(pdwInsertions) @@ -406,11 +379,9 @@ HANDLE WINAPI XTL::EMUPATCH(XInputOpen) IN PXPP_DEVICE_TYPE DeviceType, IN DWORD dwPort, IN DWORD dwSlot, - IN PX_XINPUT_POLLING_PARAMETERS pPollingParameters OPTIONAL + IN PXINPUT_POLLING_PARAMETERS pPollingParameters OPTIONAL ) { - - LOG_FUNC_BEGIN LOG_FUNC_ARG(DeviceType) LOG_FUNC_ARG(dwPort) @@ -418,63 +389,9 @@ HANDLE WINAPI XTL::EMUPATCH(XInputOpen) LOG_FUNC_ARG(pPollingParameters) LOG_FUNC_END; - X_POLLING_PARAMETERS_HANDLE *pph = 0; - //OLD_XINPUT - //rever back to return handle for port 0~3, this is for multi controller support. -/* if(dwPort >= 0 && (dwPort <= total_xinput_gamepad)) - { - if(g_hInputHandle[dwPort] == 0) - { - pph = (X_POLLING_PARAMETERS_HANDLE*) &g_pph[dwPort]; // new XB_POLLING_PARAMETERS_HANDLE(); - - if(pPollingParameters != NULL) - { - pph->pPollingParameters = (X_XINPUT_POLLING_PARAMETERS*) &g_pp[dwPort]; // new XINPUT_POLLING_PARAMETERS(); - - memcpy(pph->pPollingParameters, pPollingParameters, sizeof(X_XINPUT_POLLING_PARAMETERS)); - } - else - { - pph->pPollingParameters = NULL; - } - - g_hInputHandle[dwPort] = pph; - } - else - { - pph = (X_POLLING_PARAMETERS_HANDLE*)g_hInputHandle[dwPort]; - - if(pPollingParameters != 0) - { - if(pph->pPollingParameters == 0) - { - pph->pPollingParameters = (X_XINPUT_POLLING_PARAMETERS*) &g_pp[dwPort]; // new XINPUT_POLLING_PARAMETERS(); - } - - memcpy(pph->pPollingParameters, pPollingParameters, sizeof(X_XINPUT_POLLING_PARAMETERS)); - } - else - { - if(pph->pPollingParameters != 0) - { - //delete pph->pPollingParameters; - - pph->pPollingParameters = 0; - } - } - } - - pph->dwPort = dwPort; - } -*/ - g_bXInputOpenCalled = true; - - //RETURN((HANDLE)pph); - //code above are not used at all, in future we might remove them. - if (dwPort >= 0 && dwPort < 4) { - //check if the bridged xbox controller at this port matches the DeviceType, if matches, setup the device handle and return it. - if (g_XboxControllerHostBridge[dwPort].XboxDeviceInfo.DeviceType == DeviceType && g_XboxControllerHostBridge[dwPort].dwHostType!=0) { - //create the dialog for virtual SteelBatallion controller feedback status. + if (dwPort >= PORT_1 && dwPort <= PORT_4) { + if (DeviceType == g_XboxControllerHostBridge[dwPort].XboxType) { +#if 0 // TODO if(g_XboxControllerHostBridge[dwPort].dwHostType==X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_VIRTUAL_SBC){ //if DLL not loaded yet, load it. if (g_bCxbxVSBCLoaded != true) { @@ -498,14 +415,15 @@ HANDLE WINAPI XTL::EMUPATCH(XInputOpen) } //DWORD dwVXBCOpenResult = CxbxVSBC::MyCxbxVSBC::VSBCOpen(X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_VIRTUAL_SBC); - } - g_XboxControllerHostBridge[dwPort].hXboxDevice = &g_XboxControllerHostBridge[dwPort]; - return g_XboxControllerHostBridge[dwPort].hXboxDevice; + } +#endif + g_XboxControllerHostBridge[dwPort].hXboxDevice = &g_XboxControllerHostBridge[dwPort]; + RETURN(g_XboxControllerHostBridge[dwPort].hXboxDevice); } } - return 0; + RETURN(NULL); } // ****************************************************************** @@ -516,49 +434,13 @@ VOID WINAPI XTL::EMUPATCH(XInputClose) IN HANDLE hDevice ) { - - LOG_FUNC_ONE_ARG(hDevice); - X_POLLING_PARAMETERS_HANDLE *pph = (X_POLLING_PARAMETERS_HANDLE*)hDevice; - DWORD dwPort = pph->dwPort; - //NULL out the input handle corresponds to port. - g_hInputHandle[dwPort] = 0; - - if(pph != NULL) - { - int v; - - for(v=0;vpPollingParameters != NULL) - { - delete pph->pPollingParameters; - } - - delete pph; - */ - } - - //above code is not used at all, in future we might remove them. - //reset hXboxDevice handle if it matches the hDevice - int port; - for(port=0;port<4;port++){ - if (g_XboxControllerHostBridge[dwPort].hXboxDevice == hDevice) { - g_XboxControllerHostBridge[dwPort].hXboxDevice=0; - break; - } - } + PX_CONTROLLER_HOST_BRIDGE Device = (PX_CONTROLLER_HOST_BRIDGE)hDevice; + int Port = Device->XboxPort; + if (g_XboxControllerHostBridge[Port].hXboxDevice == hDevice) { + Device->hXboxDevice = NULL; + } } // ****************************************************************** @@ -569,68 +451,9 @@ DWORD WINAPI XTL::EMUPATCH(XInputPoll) IN HANDLE hDevice ) { - - - LOG_FUNC_ONE_ARG(hDevice); - - //OLD_XINPUT -/* X_POLLING_PARAMETERS_HANDLE *pph = (X_POLLING_PARAMETERS_HANDLE*)hDevice; - - // - // Poll input - // - - { - int v; - - for(v=0;vHeader.dwStatus != ERROR_SUCCESS) - { - if(pFeedback->Header.hEvent != 0) - { - SetEvent(pFeedback->Header.hEvent); - } - - pFeedback->Header.dwStatus = ERROR_SUCCESS; - } - } - } -*/ - int port; - for (port = 0; port<4; port++) { - if (g_XboxControllerHostBridge[port].hXboxDevice == hDevice) { - if (g_XboxControllerHostBridge[port].pXboxFeedbackHeader != 0) { - if (g_XboxControllerHostBridge[port].pXboxFeedbackHeader->dwStatus != ERROR_SUCCESS) { - if (g_XboxControllerHostBridge[port].pXboxFeedbackHeader->hEvent != 0) - { - SetEvent(g_XboxControllerHostBridge[port].pXboxFeedbackHeader->hEvent); - } - g_XboxControllerHostBridge[port].pXboxFeedbackHeader->dwStatus = ERROR_SUCCESS; - break; - } - } - else { - break; - } - } - } - - + LOG_FUNC_ONE_ARG(hDevice); + + // Nothing to do RETURN(ERROR_SUCCESS); } @@ -641,50 +464,22 @@ DWORD WINAPI XTL::EMUPATCH(XInputPoll) DWORD WINAPI XTL::EMUPATCH(XInputGetCapabilities) ( IN HANDLE hDevice, - OUT PX_XINPUT_CAPABILITIES pCapabilities + OUT PXINPUT_CAPABILITIES pCapabilities ) { - - LOG_FUNC_BEGIN LOG_FUNC_ARG(hDevice) LOG_FUNC_ARG_OUT(pCapabilities) LOG_FUNC_END; - DWORD ret = ERROR_DEVICE_NOT_CONNECTED; - - X_POLLING_PARAMETERS_HANDLE *pph = (X_POLLING_PARAMETERS_HANDLE*)hDevice; - //OLD_XINPUT -/* if(pph != NULL) - { - DWORD dwPort = pph->dwPort; - //return gamepad capabilities for port 0~3. - if(dwPort >= 0 && dwPort<=total_xinput_gamepad) - { - pCapabilities->SubType = X_XINPUT_DEVSUBTYPE_GC_GAMEPAD; - pCapabilities->In.Gamepad = {}; - pCapabilities->Out.Rumble = {}; - - ret = ERROR_SUCCESS; - } - } -*/ - //above code is not used any more, could be removed. - //find XboxControllerHostBridge per hDevice, and fill the Capabilities Structure per Device Info - int port; - for (port = 0; port < 4; port++) { - if (g_XboxControllerHostBridge[port].hXboxDevice == hDevice) { - pCapabilities->SubType = g_XboxControllerHostBridge[port].XboxDeviceInfo.ucSubType; - //ready to set the In and Out structure in pCapabilities, shall set all bit to 1 for enabling the capabilities. - UCHAR * pCapa = (UCHAR *)(&pCapabilities->In); - - memset( pCapa, - 0xFF, - g_XboxControllerHostBridge[port].XboxDeviceInfo.ucInputStateSize + g_XboxControllerHostBridge[port].XboxDeviceInfo.ucFeedbackSize); - - ret = ERROR_SUCCESS; - break; - } + DWORD ret = ERROR_DEVICE_NOT_CONNECTED; + PX_CONTROLLER_HOST_BRIDGE Device = (PX_CONTROLLER_HOST_BRIDGE)hDevice; + int Port = Device->XboxPort; + if (g_XboxControllerHostBridge[Port].hXboxDevice == hDevice && !g_XboxControllerHostBridge[Port].bPendingRemoval) { + pCapabilities->SubType = g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucSubType; + UCHAR* pCap = (UCHAR*)(&pCapabilities->In); + memset(pCap, 0xFF, g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize + g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucFeedbackSize); + ret = ERROR_SUCCESS; } RETURN(ret); @@ -736,7 +531,7 @@ char * XboxSBCFeedbackNames[] = { XTL::X_SBC_GAMEPAD XboxSBCGamepad = {}; //virtual SteelBatalion controller GetState, using port 0 from XInput and DirectInput to emulate virtual controller. -void EmuSBCGetState(XTL::PX_SBC_GAMEPAD pSBCGamepad, XTL::PX_XINPUT_GAMEPAD pXIGamepad, XTL::PX_XINPUT_GAMEPAD pDIGamepad) +void EmuSBCGetState(XTL::PX_SBC_GAMEPAD pSBCGamepad, XTL::PXINPUT_GAMEPAD pXIGamepad, XTL::PXINPUT_GAMEPAD pDIGamepad) { // Now convert those values to SteelBatalion Gamepad @@ -921,7 +716,7 @@ void EmuSBCGetState(XTL::PX_SBC_GAMEPAD pSBCGamepad, XTL::PX_XINPUT_GAMEPAD pXIG DWORD WINAPI XTL::EMUPATCH(XInputGetState) ( IN HANDLE hDevice, - OUT PX_XINPUT_STATE pState + OUT PXINPUT_STATE pState ) { @@ -931,75 +726,18 @@ DWORD WINAPI XTL::EMUPATCH(XInputGetState) LOG_FUNC_ARG_OUT(pState) LOG_FUNC_END; - DWORD ret = ERROR_INVALID_HANDLE; - //OLD_XINPUT - /* - X_POLLING_PARAMETERS_HANDLE *pph = (X_POLLING_PARAMETERS_HANDLE*)hDevice; - - if(pph != NULL) - { - if(pph->pPollingParameters != NULL) - { - if(pph->pPollingParameters->fAutoPoll == FALSE) - { - // - // TODO: uh.. - // - - EmuLog(LOG_LEVEL::WARNING, "EmuXInputGetState : fAutoPoll == FALSE"); - } - } - - DWORD dwPort = pph->dwPort; - - if((dwPort >= 0) && (dwPort <= total_xinput_gamepad)) - { - EmuLog(LOG_LEVEL::DEBUG, "EmuXInputGetState(): dwPort = %d", dwPort ); - - //for xinput, we query the state corresponds to port. - if (g_XInputEnabled) { - EmuXInputPCPoll(dwPort,pState); - } else { - EmuDInputPoll(pState); - } - - ret = ERROR_SUCCESS; - } - } - else - EmuLog(LOG_LEVEL::WARNING, "EmuXInputGetState(): pph == NULL!"); - */ - //above code is not used at all, in future we might remove them. - //get input state if hXboxDevice matches hDevice - int port; - for (port = 0; port<4; port++) { - if (g_XboxControllerHostBridge[port].hXboxDevice == hDevice) { - - //for xinput, we query the state corresponds to port. - switch (g_XboxControllerHostBridge[port].dwHostType) { - case X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT://using XInput - EmuXInputPCPoll(g_XboxControllerHostBridge[port].dwHostPort, pState); - ret = ERROR_SUCCESS; - break; - case X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_DINPUT://using directinput - EmuDInputPoll(pState); - ret = ERROR_SUCCESS; - break; - case X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_VIRTUAL_SBC://using virtual SteelBatalion Controller - //printf("SBC get state!\n"); - XTL::X_XINPUT_STATE InputState0, InputState1; - InputState0 = {}; - InputState1 = {}; - EmuXInputPCPoll(0, &InputState0); - EmuDInputPoll(&InputState1); - pState->dwPacketNumber = InputState0.dwPacketNumber; - EmuSBCGetState(XTL::PX_SBC_GAMEPAD(&pState->Gamepad), &InputState0.Gamepad, &InputState1.Gamepad); - break; - default: - break; - } - - break; + DWORD ret = ERROR_DEVICE_NOT_CONNECTED; + PX_CONTROLLER_HOST_BRIDGE Device = (PX_CONTROLLER_HOST_BRIDGE)hDevice; + int Port = Device->XboxPort; + if (g_XboxControllerHostBridge[Port].hXboxDevice == hDevice) { + if (!g_XboxControllerHostBridge[Port].bPendingRemoval) { + g_XboxControllerHostBridge[Port].bIoInProgress = true; + if (g_InputDeviceManager.UpdateXboxPortInput(Port, g_XboxControllerHostBridge[Port].InState, DIRECTION_IN, to_underlying(g_XboxControllerHostBridge[Port].XboxType))) { + pState->dwPacketNumber = g_XboxControllerHostBridge[Port].XboxDeviceInfo.dwPacketNumber++; + } + memcpy((void*)&pState->Gamepad, g_XboxControllerHostBridge[Port].InState, sizeof(pState->Gamepad)); + g_XboxControllerHostBridge[Port].bIoInProgress = false; + ret = ERROR_SUCCESS; } } @@ -1012,7 +750,7 @@ DWORD WINAPI XTL::EMUPATCH(XInputGetState) DWORD WINAPI XTL::EMUPATCH(XInputSetState) ( IN HANDLE hDevice, - IN OUT PX_XINPUT_FEEDBACK pFeedback + IN OUT PXINPUT_FEEDBACK pFeedback ) { @@ -1021,120 +759,23 @@ DWORD WINAPI XTL::EMUPATCH(XInputSetState) LOG_FUNC_ARG(hDevice) LOG_FUNC_ARG(pFeedback) LOG_FUNC_END; - - DWORD ret = ERROR_IO_PENDING; - //OLD_XINPUT -/* - X_POLLING_PARAMETERS_HANDLE *pph = (X_POLLING_PARAMETERS_HANDLE*)hDevice; - - if(pph != NULL) - { - int v; - - // - // Check if this device is already being polled - // - - bool found = false; - - for(v=0;vHeader.dwStatus == ERROR_SUCCESS) - { - //If the device was succesfully added to polling before, recycle the request - g_pXInputSetStateStatus[v].pFeedback = pFeedback; - pFeedback->Header.dwStatus = ERROR_IO_PENDING; - } - else { - //Ignore this request as another one is already pending - ret = ERROR_SUCCESS; - } - } - } - - // - // If device was not already slotted, queue it - // - - if(!found) - { - for(v=0;vHeader.dwStatus = ERROR_IO_PENDING; - - break; - } - } - - if(v == XINPUT_SETSTATE_SLOTS) - { - CxbxKrnlCleanup("Ran out of XInputSetStateStatus slots!"); - } - } - - if (g_XInputEnabled) - { - XTL::EmuXInputSetState(pph->dwPort, pFeedback); - } - } - */ - - //above code is not used at all, in future we might remove them. - //reset hXboxDevice handle if it matches the hDevice - int port; - for (port = 0; port<4; port++) { - if (g_XboxControllerHostBridge[port].hXboxDevice == hDevice) { - //if (g_XboxControllerHostBridge[port].pXboxFeedbackHeader == 0) { - g_XboxControllerHostBridge[port].pXboxFeedbackHeader = &pFeedback->Header; - g_XboxControllerHostBridge[port].dwLatency = 0; - pFeedback->Header.dwStatus = ERROR_IO_PENDING; - ret = ERROR_IO_PENDING; - //set XInput State if host type is Xinput. - switch (g_XboxControllerHostBridge[port].dwHostType) { - case 1://using XInput - XTL::EmuXInputSetState(port, pFeedback); - break; - case 2://using directinput - break; - case 0x80://using virtual SteelBatalion Controller - //printf("SBC setstate!\n"); - //EmuXSBCSetState((UCHAR *)&pFeedback->Rumble); - //UpdateVirtualSBCFeedbackDlg((UCHAR *)&pFeedback->Rumble); - //DWORD dwVXBCSetStateResult; - if (g_module != 0 && fnCxbxVSBCSetState == 0) { - fnCxbxVSBCSetState = (PFARPROC2)GetProcAddress(g_module, "VSBCSetState"); - //fnCxbxVSBCGetState = (PFARPROC2)GetProcAddress(g_module, "VSBCGetState"); - //fnCxbxVSBCOpen = (PFARPROC1)GetProcAddress(g_module, "VSBCOpen"); - } - if (fnCxbxVSBCSetState == 0) { - printf("EmuXapi: EmuXInputSetState: GetPRocAddress VSBCSetState failed!\n"); - } - else { - (*fnCxbxVSBCSetState)((UCHAR *)&pFeedback->Rumble); - } - - - //dwVXBCSetStateResult = CxbxVSBC::MyCxbxVSBC::VSBCSetState((UCHAR *)&pFeedback->Rumble); - break; - default: - break; - } - break; - //} + + PX_CONTROLLER_HOST_BRIDGE Device = (PX_CONTROLLER_HOST_BRIDGE)hDevice; + int Port = Device->XboxPort; + if (g_XboxControllerHostBridge[Port].hXboxDevice == hDevice && !g_XboxControllerHostBridge[Port].bPendingRemoval) { + pFeedback->Header.dwStatus = ERROR_IO_PENDING; + g_InputDeviceManager.UpdateXboxPortInput(Port, (void*)&pFeedback->Rumble, DIRECTION_OUT, to_underlying(g_XboxControllerHostBridge[Port].XboxType)); + pFeedback->Header.dwStatus = ERROR_SUCCESS; + if (pFeedback->Header.hEvent != NULL && + ObReferenceObjectByHandle(pFeedback->Header.hEvent, &xboxkrnl::ExEventObjectType, (PVOID*)&pFeedback->Header.IoCompletedEvent) == ERROR_SUCCESS) { + KeSetEvent((xboxkrnl::PKEVENT)pFeedback->Header.IoCompletedEvent, NULL, FALSE); } + } + else { + pFeedback->Header.dwStatus = ERROR_DEVICE_NOT_CONNECTED; } - RETURN(ret); + RETURN(pFeedback->Header.dwStatus); } diff --git a/src/core/hle/XAPI/Xapi.h b/src/core/hle/XAPI/Xapi.h index 06682ec72b..864a413e53 100644 --- a/src/core/hle/XAPI/Xapi.h +++ b/src/core/hle/XAPI/Xapi.h @@ -71,8 +71,7 @@ typedef ACCESS_MASK *PACCESS_MASK; typedef LONG *LONG_PTR; typedef ULONG *ULONG_PTR; typedef INT_PTR *PINT_PTR; -// Workaround for MAXULONG_PTR: in XTL, ULONG_PTR is defined as a pointer type instead of being an integer -static constexpr unsigned int XTL_MAXULONG_PTR = ~((::ULONG_PTR)0); + #ifndef VOID #define VOID void #endif @@ -106,7 +105,7 @@ typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; // ****************************************************************** // * XINPUT_POLLING_PARAMETERS // ****************************************************************** -typedef struct _X_XINPUT_POLLING_PARAMETERS +typedef struct _XINPUT_POLLING_PARAMETERS { BYTE fAutoPoll : 1; BYTE fInterruptOut : 1; @@ -115,18 +114,7 @@ typedef struct _X_XINPUT_POLLING_PARAMETERS BYTE bOutputInterval; BYTE ReservedMBZ2; } -X_XINPUT_POLLING_PARAMETERS, *PX_XINPUT_POLLING_PARAMETERS; - -// ****************************************************************** -// * POLLING_PARAMETERS_HANDLE -// ****************************************************************** -typedef struct _X_POLLING_PARAMETERS_HANDLE -{ - X_XINPUT_POLLING_PARAMETERS *pPollingParameters; - - DWORD dwPort; -} -X_POLLING_PARAMETERS_HANDLE, *PX_POLLING_PARAMETERS_HANDLE; +XINPUT_POLLING_PARAMETERS, *PXINPUT_POLLING_PARAMETERS; // ****************************************************************** // * XPP_DEVICE_TYPE @@ -188,9 +176,9 @@ typedef struct _XDEVICE_PREALLOC_TYPE XDEVICE_PREALLOC_TYPE, *PXDEVICE_PREALLOC_TYPE; // ****************************************************************** -// * XINPUT_GAMEPAD for xbox, xbox's GAMEPAD struc differs from PC's +// * XINPUT_GAMEPAD for xbox, xbox's GAMEPAD struct differs from PC's // ****************************************************************** -typedef struct _X_XINPUT_GAMEPAD +typedef struct _XINPUT_GAMEPAD { WORD wButtons; BYTE bAnalogButtons[8]; @@ -199,7 +187,7 @@ typedef struct _X_XINPUT_GAMEPAD SHORT sThumbRX; SHORT sThumbRY; } -X_XINPUT_GAMEPAD, *PX_XINPUT_GAMEPAD; +XINPUT_GAMEPAD, *PXINPUT_GAMEPAD; // ****************************************************************** // * X_SBC_GAMEPAD for xbox SteelBatalion GAMEPAD struc @@ -219,287 +207,107 @@ typedef struct _X_SBC_GAMEPAD { } X_SBC_GAMEPAD, *PX_SBC_GAMEPAD; -// ****************************************************************** -// * masks for digital buttons of X_SBC_GAMEPAD -// ****************************************************************** - -#define X_SBC_GAMEPAD_W0_RIGHTJOYMAINWEAPON 0x0001 -#define X_SBC_GAMEPAD_W0_RIGHTJOYFIRE 0x0002 -#define X_SBC_GAMEPAD_W0_RIGHTJOYLOCKON 0x0004 -#define X_SBC_GAMEPAD_W0_EJECT 0x0008 -#define X_SBC_GAMEPAD_W0_COCKPITHATCH 0x0010 -#define X_SBC_GAMEPAD_W0_IGNITION 0x0020 -#define X_SBC_GAMEPAD_W0_START 0x0040 -#define X_SBC_GAMEPAD_W0_MULTIMONOPENCLOSE 0x0080 -#define X_SBC_GAMEPAD_W0_MULTIMONMAPZOOMINOUT 0x0100 -#define X_SBC_GAMEPAD_W0_MULTIMONMODESELECT 0x0200 -#define X_SBC_GAMEPAD_W0_MULTIMONSUBMONITOR 0x0400 -#define X_SBC_GAMEPAD_W0_MAINMONZOOMIN 0x0800 -#define X_SBC_GAMEPAD_W0_MAINMONZOOMOUT 0x1000 -#define X_SBC_GAMEPAD_W0_FUNCTIONFSS 0x2000 -#define X_SBC_GAMEPAD_W0_FUNCTIONMANIPULATOR 0x4000 -#define X_SBC_GAMEPAD_W0_FUNCTIONLINECOLORCHANGE 0x8000 -#define X_SBC_GAMEPAD_W1_WASHING 0x0001 -#define X_SBC_GAMEPAD_W1_EXTINGUISHER 0x0002 -#define X_SBC_GAMEPAD_W1_CHAFF 0x0004 -#define X_SBC_GAMEPAD_W1_FUNCTIONTANKDETACH 0x0008 -#define X_SBC_GAMEPAD_W1_FUNCTIONOVERRIDE 0x0010 -#define X_SBC_GAMEPAD_W1_FUNCTIONNIGHTSCOPE 0x0020 -#define X_SBC_GAMEPAD_W1_FUNCTIONF1 0x0040 -#define X_SBC_GAMEPAD_W1_FUNCTIONF2 0x0080 -#define X_SBC_GAMEPAD_W1_FUNCTIONF3 0x0100 -#define X_SBC_GAMEPAD_W1_WEAPONCONMAIN 0x0200 -#define X_SBC_GAMEPAD_W1_WEAPONCONSUB 0x0400 -#define X_SBC_GAMEPAD_W1_WEAPONCONMAGAZINE 0x0800 -#define X_SBC_GAMEPAD_W1_COMM1 0x1000 -#define X_SBC_GAMEPAD_W1_COMM2 0x2000 -#define X_SBC_GAMEPAD_W1_COMM3 0x4000 -#define X_SBC_GAMEPAD_W1_COMM4 0x8000 -#define X_SBC_GAMEPAD_W2_COMM5 0x0001 -#define X_SBC_GAMEPAD_W2_LEFTJOYSIGHTCHANGE 0x0002 -#define X_SBC_GAMEPAD_W2_TOGGLEFILTERCONTROL 0x0004 -#define X_SBC_GAMEPAD_W2_TOGGLEOXYGENSUPPLY 0x0008 -#define X_SBC_GAMEPAD_W2_TOGGLEFUELFLOWRATE 0x0010 -#define X_SBC_GAMEPAD_W2_TOGGLEBUFFREMATERIAL 0x0020 -#define X_SBC_GAMEPAD_W2_TOGGLEVTLOCATION 0x0040 - -// ****************************************************************** -// * enum for feedback status variables of X_SBC_FEEDBACK, it's a byte array after FeedbackHeader, each variable take 1 nibble, that's half byte. -// ****************************************************************** -#define X_SBC_FEEDBACK_EMERGENCYEJECT 0 -#define X_SBC_FEEDBACK_COCKPITHATCH 1 -#define X_SBC_FEEDBACK_IGNITION 2 -#define X_SBC_FEEDBACK_START 3 -#define X_SBC_FEEDBACK_OPENCLOSE 4 -#define X_SBC_FEEDBACK_MAPZOOMINOUT 5 -#define X_SBC_FEEDBACK_MODESELECT 6 -#define X_SBC_FEEDBACK_SUBMONITORMODESELECT 7 -#define X_SBC_FEEDBACK_MAINMONITORZOOMIN 8 -#define X_SBC_FEEDBACK_MAINMONITORZOOMOUT 9 -#define X_SBC_FEEDBACK_FORECASTSHOOTINGSYSTEM 10 -#define X_SBC_FEEDBACK_MANIPULATOR 11 -#define X_SBC_FEEDBACK_LINECOLORCHANGE 12 -#define X_SBC_FEEDBACK_WASHING 13 -#define X_SBC_FEEDBACK_EXTINGUISHER 14 -#define X_SBC_FEEDBACK_CHAFF 15 -#define X_SBC_FEEDBACK_TANKDETACH 16 -#define X_SBC_FEEDBACK_OVERRIDE 17 -#define X_SBC_FEEDBACK_NIGHTSCOPE 18 -#define X_SBC_FEEDBACK_F1 19 -#define X_SBC_FEEDBACK_F2 20 -#define X_SBC_FEEDBACK_F3 21 -#define X_SBC_FEEDBACK_MAINWEAPONCONTROL 22 -#define X_SBC_FEEDBACK_SUBWEAPONCONTROL 23 -#define X_SBC_FEEDBACK_MAGAZINECHANGE 24 -#define X_SBC_FEEDBACK_COMM1 25 -#define X_SBC_FEEDBACK_COMM2 26 -#define X_SBC_FEEDBACK_COMM3 27 -#define X_SBC_FEEDBACK_COMM4 28 -#define X_SBC_FEEDBACK_COMM5 29 -#define X_SBC_FEEDBACK_UNKNOWN 30 -#define X_SBC_FEEDBACK_GEARR 31 -#define X_SBC_FEEDBACK_GEARN 32 -#define X_SBC_FEEDBACK_GEAR1 33 -#define X_SBC_FEEDBACK_GEAR2 34 -#define X_SBC_FEEDBACK_GEAR3 35 -#define X_SBC_FEEDBACK_GEAR4 36 -#define X_SBC_FEEDBACK_GEAR5 37 - -#define X_SBC_FEEDBACK_MAX 38 - // ****************************************************************** // * XINPUT_RUMBLE // ****************************************************************** -typedef struct _X_XINPUT_RUMBLE +typedef struct _XINPUT_RUMBLE { WORD wLeftMotorSpeed; WORD wRightMotorSpeed; } -X_XINPUT_RUMBLE, *PX_XINPUT_RUMBLE; +XINPUT_RUMBLE, *PXINPUT_RUMBLE; // ****************************************************************** // * XINPUT_CAPABILITIES // ****************************************************************** #include "AlignPrefix1.h" -typedef struct _X_XINPUT_CAPABILITIES +typedef struct _XINPUT_CAPABILITIES { BYTE SubType; WORD Reserved; union { - X_XINPUT_GAMEPAD Gamepad; + XINPUT_GAMEPAD Gamepad; } In; union { - X_XINPUT_RUMBLE Rumble; + XINPUT_RUMBLE Rumble; } Out; } #include "AlignPosfix1.h" -X_XINPUT_CAPABILITIES, *PX_XINPUT_CAPABILITIES; +XINPUT_CAPABILITIES, *PXINPUT_CAPABILITIES; // ****************************************************************** // * Device XBOX Input Device Types // ****************************************************************** // all game controller use 0x01 GAMEPAD device type. then specify the subtype in returned Capabilities when XInputGetCapabilities called. -#define X_XINPUT_DEVTYPE_GAMEPAD 0x01 +#define XINPUT_DEVTYPE_GAMEPAD 0x01 // SteelBatalion controller is the only one with special device type other than 1. -#define X_XINPUT_DEVTYPE_STEELBATALION 0x80 +#define XINPUT_DEVTYPE_STEELBATALION 0x80 // ****************************************************************** // * Device XBOX Input Device SubTypes, for use in XINPUT_CAPABILITIES // ****************************************************************** //general GAMEPAD uses subtype 0x01. -#define X_XINPUT_DEVSUBTYPE_GC_GAMEPAD 0x01 +#define XINPUT_DEVSUBTYPE_GC_GAMEPAD 0x01 //SteelBatallion controller uses subtype 0x02 -#define X_XINPUT_DEVSUBTYPE_GC_GAMEPAD_ALT 0x02 -#define X_XINPUT_DEVSUBTYPE_GC_WHEEL 0x10 -#define X_XINPUT_DEVSUBTYPE_GC_ARCADE_STICK 0x20 -#define X_XINPUT_DEVSUBTYPE_GC_DIGITAL_ARCADE_STICK 0x21 -#define X_XINPUT_DEVSUBTYPE_GC_FLIGHT_STICK 0x30 -#define X_XINPUT_DEVSUBTYPE_GC_SNOWBOARD 0x40 -#define X_XINPUT_DEVSUBTYPE_GC_LIGHTGUN 0x50 -#define X_XINPUT_DEVSUBTYPE_GC_RADIO_FLIGHT_CONTROL 0x60 -#define X_XINPUT_DEVSUBTYPE_GC_FISHING_ROD 0x70 -#define X_XINPUT_DEVSUBTYPE_GC_DANCEPAD 0x80 +#define XINPUT_DEVSUBTYPE_GC_GAMEPAD_ALT 0x02 +#define XINPUT_DEVSUBTYPE_GC_WHEEL 0x10 +#define XINPUT_DEVSUBTYPE_GC_ARCADE_STICK 0x20 +#define XINPUT_DEVSUBTYPE_GC_DIGITAL_ARCADE_STICK 0x21 +#define XINPUT_DEVSUBTYPE_GC_FLIGHT_STICK 0x30 +#define XINPUT_DEVSUBTYPE_GC_SNOWBOARD 0x40 +#define XINPUT_DEVSUBTYPE_GC_LIGHTGUN 0x50 +#define XINPUT_DEVSUBTYPE_GC_RADIO_FLIGHT_CONTROL 0x60 +#define XINPUT_DEVSUBTYPE_GC_FISHING_ROD 0x70 +#define XINPUT_DEVSUBTYPE_GC_DANCEPAD 0x80 // ****************************************************************** // * XINPUT_STATE for xbox, xbox uses different Gamepad struce. // ****************************************************************** -typedef struct _X_XINPUT_STATE +typedef struct _XINPUT_STATE { DWORD dwPacketNumber; union { - X_XINPUT_GAMEPAD Gamepad; + XINPUT_GAMEPAD Gamepad; }; } -X_XINPUT_STATE, *PX_XINPUT_STATE; - -// ****************************************************************** -// * offsets into analog button array -// ****************************************************************** -#define X_XINPUT_GAMEPAD_A 0 -#define X_XINPUT_GAMEPAD_B 1 -#define X_XINPUT_GAMEPAD_X 2 -#define X_XINPUT_GAMEPAD_Y 3 -#define X_XINPUT_GAMEPAD_BLACK 4 -#define X_XINPUT_GAMEPAD_WHITE 5 -#define X_XINPUT_GAMEPAD_LEFT_TRIGGER 6 -#define X_XINPUT_GAMEPAD_RIGHT_TRIGGER 7 - -// ****************************************************************** -// * masks for digital buttons -// ****************************************************************** -#define X_XINPUT_GAMEPAD_DPAD_UP 0x00000001 -#define X_XINPUT_GAMEPAD_DPAD_DOWN 0x00000002 -#define X_XINPUT_GAMEPAD_DPAD_LEFT 0x00000004 -#define X_XINPUT_GAMEPAD_DPAD_RIGHT 0x00000008 -#define X_XINPUT_GAMEPAD_START 0x00000010 -#define X_XINPUT_GAMEPAD_BACK 0x00000020 -#define X_XINPUT_GAMEPAD_LEFT_THUMB 0x00000040 -#define X_XINPUT_GAMEPAD_RIGHT_THUMB 0x00000080 +XINPUT_STATE, *PXINPUT_STATE; // ****************************************************************** // * XINPUT_FEEDBACK_HEADER // ****************************************************************** #include "AlignPrefix1.h" -typedef struct _X_XINPUT_FEEDBACK_HEADER +typedef struct _XINPUT_FEEDBACK_HEADER { - DWORD dwStatus; - HANDLE OPTIONAL hEvent; - BYTE Reserved[58]; + DWORD dwStatus; + HANDLE OPTIONAL hEvent; + BYTE Unknown1[4]; + PVOID IoCompletedEvent; // PKEVENT really + BYTE Unknown2[50]; } #include "AlignPosfix1.h" -X_XINPUT_FEEDBACK_HEADER, *PX_XINPUT_FEEDBACK_HEADER; +XINPUT_FEEDBACK_HEADER, *PXINPUT_FEEDBACK_HEADER; // ****************************************************************** // * XINPUT_FEEDBACK // ****************************************************************** -typedef struct _X_XINPUT_FEEDBACK +typedef struct _XINPUT_FEEDBACK { - X_XINPUT_FEEDBACK_HEADER Header; + XINPUT_FEEDBACK_HEADER Header; union { - X_XINPUT_RUMBLE Rumble; + XINPUT_RUMBLE Rumble; }; } -X_XINPUT_FEEDBACK, *PX_XINPUT_FEEDBACK; - -// ****************************************************************** -// * XINPUT_DEVICE_INFO -// ****************************************************************** - -typedef struct _X_XINPUT_DEVICE_INFO -{ - - UCHAR ucType; //xbox controller type - UCHAR ucSubType; //xbox controller subtype - UCHAR ucInputStateSize; //xbox controller input state size in bytes, not include dwPacketNumber - UCHAR ucFeedbackSize; //xbox controller feedback size in bytes, not include FeedbackHeader - PXPP_DEVICE_TYPE DeviceType; //pointer to DeviceType structure. -} -X_XINPUT_DEVICE_INFO, *PX_XINPUT_DEVICE_INFO; - -#define X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_NOTCONNECT 0x00000000 -#define X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT 0x00000001 -#define X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_DINPUT 0x00000002 -#define X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_VIRTUAL_SBC 0x00000080 - -//this structure is for use of tracking the xbox controllers assigned to 4 ports. -//user can specify the corresponding host input device -//whether it's XInput, directinput, or an virtual custom controller. -// ****************************************************************** -// * X_CONTROLLER_HOST_BRIDGE -// ****************************************************************** -typedef struct _X_CONTROLLER_HOST_BRIDGE -{ - HANDLE hXboxDevice; //xbox device handle to this controller, we use the address of this bridge as the handle, only set after opened. cleared after closed. - DWORD dwXboxPort; //xbox port# for this xbox controller - PX_XINPUT_POLLING_PARAMETERS pXboxXPP; //pointer to xbox polling parameter - DWORD dwHostType; //specify host input corresponding to this controller - //0 not connected, - //1 connect with XInput, - //2 connect with directinput, - //3 or above connect virtual custom controller - DWORD dwHostPort; //port of the host input device being bridged. - //if hostinputtype==1 for using XInput, and hostport==2, - //then bridge to XInput player 3 (port started from 0). - - //members listed below comes from interpreting xbe device table - X_XINPUT_DEVICE_INFO XboxDeviceInfo; - void * pXboxState; //not used currently, keep it just in case - PX_XINPUT_FEEDBACK_HEADER pXboxFeedbackHeader; //pointer to feedback header,keep this in track for IO_PENDING status tracking. - DWORD dwLatency; -} -X_CONTROLLER_HOST_BRIDGE, *PX_CONTROLLER_HOST_BRIDGE; - - -// ****************************************************************** -// * XBGAMEPAD // this structure seems unused at all. anyway, keep it here. -// ****************************************************************** -struct XBGAMEPAD : public X_XINPUT_GAMEPAD -{ - FLOAT fX1; - FLOAT fY1; - FLOAT fX2; - FLOAT fY2; - WORD wLastButtons; - BOOL bLastAnalogButtons[8]; - WORD wPressedButtons; - BOOL bPressedAnalogButtons[8]; - X_XINPUT_RUMBLE Rumble; - X_XINPUT_FEEDBACK Feedback; - X_XINPUT_CAPABILITIES caps; - HANDLE hDevice; - BOOL bInserted; - BOOL bRemoved; -}; +XINPUT_FEEDBACK, *PXINPUT_FEEDBACK; // ****************************************************************** // * RTL_HEAP_PARAMETERS @@ -624,7 +432,7 @@ HANDLE WINAPI EMUPATCH(XInputOpen) IN PXPP_DEVICE_TYPE DeviceType, IN DWORD dwPort, IN DWORD dwSlot, - IN PX_XINPUT_POLLING_PARAMETERS pPollingParameters OPTIONAL + IN PXINPUT_POLLING_PARAMETERS pPollingParameters OPTIONAL ); // ****************************************************************** @@ -649,7 +457,7 @@ DWORD WINAPI EMUPATCH(XInputPoll) DWORD WINAPI EMUPATCH(XInputGetCapabilities) ( IN HANDLE hDevice, - OUT PX_XINPUT_CAPABILITIES pCapabilities + OUT PXINPUT_CAPABILITIES pCapabilities ); // ****************************************************************** @@ -658,7 +466,7 @@ DWORD WINAPI EMUPATCH(XInputGetCapabilities) DWORD WINAPI EMUPATCH(XInputGetState) ( IN HANDLE hDevice, - OUT PX_XINPUT_STATE pState + OUT PXINPUT_STATE pState ); // ****************************************************************** @@ -667,7 +475,7 @@ DWORD WINAPI EMUPATCH(XInputGetState) DWORD WINAPI EMUPATCH(XInputSetState) ( IN HANDLE hDevice, - IN OUT PX_XINPUT_FEEDBACK pFeedback + IN OUT PXINPUT_FEEDBACK pFeedback ); diff --git a/src/core/hle/XAPI/XapiCxbxr.h b/src/core/hle/XAPI/XapiCxbxr.h new file mode 100644 index 0000000000..14d9b2d99b --- /dev/null +++ b/src/core/hle/XAPI/XapiCxbxr.h @@ -0,0 +1,175 @@ +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +// This file contains Xapi variables which are not part of the Xbox Xapi but are used by Cxbxr. They are prefixed with X_ to further distinguish them. + +#ifndef XAPI_CXBXR_H +#define XAPI_CXBXR_H + +// ****************************************************************** +// * XINPUT_DEVICE_INFO +// ****************************************************************** + +typedef struct _X_XINPUT_DEVICE_INFO +{ + + UCHAR ucType; //xbox controller type + UCHAR ucSubType; //xbox controller subtype + UCHAR ucInputStateSize; //xbox controller input state size in bytes, not include dwPacketNumber + UCHAR ucFeedbackSize; //xbox controller feedback size in bytes, not include FeedbackHeader + DWORD dwPacketNumber; +} +X_XINPUT_DEVICE_INFO, *PX_XINPUT_DEVICE_INFO; + +//this structure is for use of tracking the xbox controllers assigned to 4 ports. +// ****************************************************************** +// * X_CONTROLLER_HOST_BRIDGE +// ****************************************************************** +typedef struct _X_CONTROLLER_HOST_BRIDGE +{ + HANDLE hXboxDevice; //xbox device handle to this device, we use the address of this bridge as the handle, only set after opened. cleared after closed. + int XboxPort; //xbox port# for this xbox controller + XBOX_INPUT_DEVICE XboxType; //xbox device type + void* InState; + bool bPendingRemoval; + bool bSignaled; + bool bIoInProgress; + X_XINPUT_DEVICE_INFO XboxDeviceInfo; +} +X_CONTROLLER_HOST_BRIDGE, *PX_CONTROLLER_HOST_BRIDGE; + +// ****************************************************************** +// * offsets into analog button array +// ****************************************************************** +#define X_XINPUT_GAMEPAD_A 0 +#define X_XINPUT_GAMEPAD_B 1 +#define X_XINPUT_GAMEPAD_X 2 +#define X_XINPUT_GAMEPAD_Y 3 +#define X_XINPUT_GAMEPAD_BLACK 4 +#define X_XINPUT_GAMEPAD_WHITE 5 +#define X_XINPUT_GAMEPAD_LEFT_TRIGGER 6 +#define X_XINPUT_GAMEPAD_RIGHT_TRIGGER 7 + +// ****************************************************************** +// * masks for digital buttons +// ****************************************************************** +#define X_XINPUT_GAMEPAD_DPAD_UP 0x00000001 +#define X_XINPUT_GAMEPAD_DPAD_DOWN 0x00000002 +#define X_XINPUT_GAMEPAD_DPAD_LEFT 0x00000004 +#define X_XINPUT_GAMEPAD_DPAD_RIGHT 0x00000008 +#define X_XINPUT_GAMEPAD_START 0x00000010 +#define X_XINPUT_GAMEPAD_BACK 0x00000020 +#define X_XINPUT_GAMEPAD_LEFT_THUMB 0x00000040 +#define X_XINPUT_GAMEPAD_RIGHT_THUMB 0x00000080 + +// ****************************************************************** +// * masks for digital buttons of X_SBC_GAMEPAD +// ****************************************************************** + +#define X_SBC_GAMEPAD_W0_RIGHTJOYMAINWEAPON 0x0001 +#define X_SBC_GAMEPAD_W0_RIGHTJOYFIRE 0x0002 +#define X_SBC_GAMEPAD_W0_RIGHTJOYLOCKON 0x0004 +#define X_SBC_GAMEPAD_W0_EJECT 0x0008 +#define X_SBC_GAMEPAD_W0_COCKPITHATCH 0x0010 +#define X_SBC_GAMEPAD_W0_IGNITION 0x0020 +#define X_SBC_GAMEPAD_W0_START 0x0040 +#define X_SBC_GAMEPAD_W0_MULTIMONOPENCLOSE 0x0080 +#define X_SBC_GAMEPAD_W0_MULTIMONMAPZOOMINOUT 0x0100 +#define X_SBC_GAMEPAD_W0_MULTIMONMODESELECT 0x0200 +#define X_SBC_GAMEPAD_W0_MULTIMONSUBMONITOR 0x0400 +#define X_SBC_GAMEPAD_W0_MAINMONZOOMIN 0x0800 +#define X_SBC_GAMEPAD_W0_MAINMONZOOMOUT 0x1000 +#define X_SBC_GAMEPAD_W0_FUNCTIONFSS 0x2000 +#define X_SBC_GAMEPAD_W0_FUNCTIONMANIPULATOR 0x4000 +#define X_SBC_GAMEPAD_W0_FUNCTIONLINECOLORCHANGE 0x8000 +#define X_SBC_GAMEPAD_W1_WASHING 0x0001 +#define X_SBC_GAMEPAD_W1_EXTINGUISHER 0x0002 +#define X_SBC_GAMEPAD_W1_CHAFF 0x0004 +#define X_SBC_GAMEPAD_W1_FUNCTIONTANKDETACH 0x0008 +#define X_SBC_GAMEPAD_W1_FUNCTIONOVERRIDE 0x0010 +#define X_SBC_GAMEPAD_W1_FUNCTIONNIGHTSCOPE 0x0020 +#define X_SBC_GAMEPAD_W1_FUNCTIONF1 0x0040 +#define X_SBC_GAMEPAD_W1_FUNCTIONF2 0x0080 +#define X_SBC_GAMEPAD_W1_FUNCTIONF3 0x0100 +#define X_SBC_GAMEPAD_W1_WEAPONCONMAIN 0x0200 +#define X_SBC_GAMEPAD_W1_WEAPONCONSUB 0x0400 +#define X_SBC_GAMEPAD_W1_WEAPONCONMAGAZINE 0x0800 +#define X_SBC_GAMEPAD_W1_COMM1 0x1000 +#define X_SBC_GAMEPAD_W1_COMM2 0x2000 +#define X_SBC_GAMEPAD_W1_COMM3 0x4000 +#define X_SBC_GAMEPAD_W1_COMM4 0x8000 +#define X_SBC_GAMEPAD_W2_COMM5 0x0001 +#define X_SBC_GAMEPAD_W2_LEFTJOYSIGHTCHANGE 0x0002 +#define X_SBC_GAMEPAD_W2_TOGGLEFILTERCONTROL 0x0004 +#define X_SBC_GAMEPAD_W2_TOGGLEOXYGENSUPPLY 0x0008 +#define X_SBC_GAMEPAD_W2_TOGGLEFUELFLOWRATE 0x0010 +#define X_SBC_GAMEPAD_W2_TOGGLEBUFFREMATERIAL 0x0020 +#define X_SBC_GAMEPAD_W2_TOGGLEVTLOCATION 0x0040 + +// ****************************************************************** +// * enum for feedback status variables of X_SBC_FEEDBACK, it's a byte array after FeedbackHeader, each variable take 1 nibble, that's half byte. +// ****************************************************************** +#define X_SBC_FEEDBACK_EMERGENCYEJECT 0 +#define X_SBC_FEEDBACK_COCKPITHATCH 1 +#define X_SBC_FEEDBACK_IGNITION 2 +#define X_SBC_FEEDBACK_START 3 +#define X_SBC_FEEDBACK_OPENCLOSE 4 +#define X_SBC_FEEDBACK_MAPZOOMINOUT 5 +#define X_SBC_FEEDBACK_MODESELECT 6 +#define X_SBC_FEEDBACK_SUBMONITORMODESELECT 7 +#define X_SBC_FEEDBACK_MAINMONITORZOOMIN 8 +#define X_SBC_FEEDBACK_MAINMONITORZOOMOUT 9 +#define X_SBC_FEEDBACK_FORECASTSHOOTINGSYSTEM 10 +#define X_SBC_FEEDBACK_MANIPULATOR 11 +#define X_SBC_FEEDBACK_LINECOLORCHANGE 12 +#define X_SBC_FEEDBACK_WASHING 13 +#define X_SBC_FEEDBACK_EXTINGUISHER 14 +#define X_SBC_FEEDBACK_CHAFF 15 +#define X_SBC_FEEDBACK_TANKDETACH 16 +#define X_SBC_FEEDBACK_OVERRIDE 17 +#define X_SBC_FEEDBACK_NIGHTSCOPE 18 +#define X_SBC_FEEDBACK_F1 19 +#define X_SBC_FEEDBACK_F2 20 +#define X_SBC_FEEDBACK_F3 21 +#define X_SBC_FEEDBACK_MAINWEAPONCONTROL 22 +#define X_SBC_FEEDBACK_SUBWEAPONCONTROL 23 +#define X_SBC_FEEDBACK_MAGAZINECHANGE 24 +#define X_SBC_FEEDBACK_COMM1 25 +#define X_SBC_FEEDBACK_COMM2 26 +#define X_SBC_FEEDBACK_COMM3 27 +#define X_SBC_FEEDBACK_COMM4 28 +#define X_SBC_FEEDBACK_COMM5 29 +#define X_SBC_FEEDBACK_UNKNOWN 30 +#define X_SBC_FEEDBACK_GEARR 31 +#define X_SBC_FEEDBACK_GEARN 32 +#define X_SBC_FEEDBACK_GEAR1 33 +#define X_SBC_FEEDBACK_GEAR2 34 +#define X_SBC_FEEDBACK_GEAR3 35 +#define X_SBC_FEEDBACK_GEAR4 36 +#define X_SBC_FEEDBACK_GEAR5 37 + +#define X_SBC_FEEDBACK_MAX 38 + +#endif diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 7ca5c90c90..9baebfac8a 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -63,7 +63,7 @@ namespace xboxkrnl #include "devices\SMCDevice.h" // For SMC Access #include "common\crypto\EmuSha.h" // For the SHA1 functions #include "Timer.h" // For Timer_Init -#include "..\Common\Input\InputConfig.h" // For the InputDeviceManager +#include "common\input\InputManager.h" // For the InputDeviceManager /*! thread local storage */ Xbe::TLS *CxbxKrnl_TLS = NULL; @@ -1573,18 +1573,7 @@ __declspec(noreturn) void CxbxKrnlInit // Read Xbox video mode from the SMC, store it in HalBootSMCVideoMode xboxkrnl::HalReadSMBusValue(SMBUS_ADDRESS_SYSTEM_MICRO_CONTROLLER, SMC_COMMAND_AV_PACK, FALSE, &xboxkrnl::HalBootSMCVideoMode); - if (bLLE_USB) { -#if 0 // Reenable this when LLE USB actually works - int ret; - g_InputDeviceManager = new InputDeviceManager; - ret = g_InputDeviceManager->EnumSdl2Devices(); - g_InputDeviceManager->StartInputThread(); - if (ret > 0) { - // Temporary: the device type and bindings should be read from emushared, for now always assume one xbox controller - g_InputDeviceManager->ConnectDeviceToXbox(1, MS_CONTROLLER_DUKE); - } -#endif - } + g_InputDeviceManager.Initialize(false); // Now the hardware devices exist, couple the EEPROM buffer to it's device g_EEPROM->SetEEPROM((uint8_t*)EEPROM); @@ -1812,6 +1801,9 @@ void CxbxKrnlShutDown() // This is okay for now: It won't leak memory or resources since TerminateProcess will free everything // delete g_NV2A; // TODO : g_pXbox + // Shutdown the input device manager + g_InputDeviceManager.Shutdown(); + if (CxbxKrnl_hEmuParent != NULL) SendMessage(CxbxKrnl_hEmuParent, WM_PARENTNOTIFY, WM_DESTROY, 0); diff --git a/src/core/kernel/memory-manager/VMManager.cpp b/src/core/kernel/memory-manager/VMManager.cpp index cdeb72aa16..e91c444de4 100644 --- a/src/core/kernel/memory-manager/VMManager.cpp +++ b/src/core/kernel/memory-manager/VMManager.cpp @@ -32,7 +32,7 @@ // Copyright 2015 Citra Emulator Project // Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// Refer to the license.txt file of Citra at https://github.com/citra-emu/citra/blob/master/license.txt. #define LOG_PREFIX CXBXR_MODULE::VMEM diff --git a/src/core/kernel/support/Emu.h b/src/core/kernel/support/Emu.h index 9019f3abd0..124e7e51b3 100644 --- a/src/core/kernel/support/Emu.h +++ b/src/core/kernel/support/Emu.h @@ -69,24 +69,6 @@ extern HANDLE g_CurrentProcessHandle; // Set in CxbxKrnlMain // Delta added to host SystemTime, used in KiClockIsr and KeSetSystemTime extern std::atomic_int64_t HostSystemTimeDelta; -// NOTE: this is an arbitrary latency -#define XINPUT_SETSTATE_LATENCY 4 -#define XINPUT_SETSTATE_SLOTS 16 - -// XInputSetState status waiters -extern struct XInputSetStateStatus -{ - HANDLE hDevice; - DWORD dwLatency; - PVOID pFeedback; -} -g_pXInputSetStateStatus[XINPUT_SETSTATE_SLOTS]; - -// 4 controllers -#define XINPUT_HANDLE_SLOTS 4 - -extern HANDLE g_hInputHandle[XINPUT_HANDLE_SLOTS]; - typedef struct DUMMY_KERNEL { IMAGE_DOS_HEADER DosHeader; diff --git a/src/core/kernel/support/EmuXTL.h b/src/core/kernel/support/EmuXTL.h index 9c9e5a9f0d..21793da6e4 100644 --- a/src/core/kernel/support/EmuXTL.h +++ b/src/core/kernel/support/EmuXTL.h @@ -38,12 +38,10 @@ namespace XTL #include "core\hle\D3D8\XbVertexShader.h" #include "core\hle\D3D8\XbPixelShader.h" #include "core\hle\D3D8\XbState.h" - #include "core\hle\XAPI\OHCI\XInput\DInput.h" #include "core\hle\DSOUND\DirectSound\DirectSound.hpp" #include "core\hle\XONLINE\XOnline.h" #include "core\hle\XGRAPHIC\XGraphic.h" #include "core\hle\XACTENG\XactEng.h" - #include "core\hle\XAPI\OHCI\XInput\XInput.h" } extern XTL::IDirect3DDevice *g_pD3DDevice; diff --git a/src/devices/usb/XidGamepad.cpp b/src/devices/usb/XidGamepad.cpp index ef760c4adf..0901654b68 100644 --- a/src/devices/usb/XidGamepad.cpp +++ b/src/devices/usb/XidGamepad.cpp @@ -60,10 +60,10 @@ namespace xboxkrnl #include "XidGamepad.h" #include "USBDevice.h" -#include "common\Input\InputConfig.h" -#include "common\Input\SDL2_Device.h" +#include "common\input\InputManager.h" +#include "common\input\SdlJoystick.h" #include "OHCI.h" -#include "core\kernel\exports\EmuKrnl.h" // For EmuLog +#include "core\kernel\exports\EmuKrnl.h" #include "Logging.h" #define USB_CLASS_XID 0x58 diff --git a/src/devices/video/nv2a_int.h b/src/devices/video/nv2a_int.h index 646ba0f7d1..89aae84052 100644 --- a/src/devices/video/nv2a_int.h +++ b/src/devices/video/nv2a_int.h @@ -48,22 +48,6 @@ typedef xbaddr hwaddr; // Compatibility; Cxbx uses xbaddr, xqemu and OpenXbox use hwaddr typedef uint32_t value_t; // Compatibility; Cxbx values are uint32_t (xqemu and OpenXbox use uint64_t) -#ifdef __cplusplus -template struct ArraySizeHelper { char _[N]; }; -template -ArraySizeHelper makeArraySizeHelper(T(&)[N]); -# define ARRAY_SIZE(a) sizeof(makeArraySizeHelper(a)) -#else -// The expression ARRAY_SIZE(a) is a compile-time constant of type -// size_t which represents the number of elements of the given -// array. You should only use ARRAY_SIZE on statically allocated -// arrays. - -#define ARRAY_SIZE(a) \ - ((sizeof(a) / sizeof(*(a))) / \ - static_cast(!(sizeof(a) % sizeof(*(a))))) -#endif - #define NV_PMC_SIZE 0x001000 #define _NV_PFIFO_SIZE 0x002000 // Underscore prefix to prevent clash with NV_PFIFO_SIZE #define NV_PVIDEO_SIZE 0x001000 diff --git a/src/gui/DlgControllerConfig.cpp b/src/gui/DlgControllerConfig.cpp deleted file mode 100644 index 14059bbba5..0000000000 --- a/src/gui/DlgControllerConfig.cpp +++ /dev/null @@ -1,378 +0,0 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -// ****************************************************************** -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2002-2003 Aaron Robinson -// * -// * All rights reserved -// * -// ****************************************************************** - -// Without this, you'll get a ton of errors from the std library for some unknown reason... -#include "Logging.h" - -#include "common\Settings.hpp" // for g_Settings - -#include "DlgControllerConfig.h" -#include "ResCxbx.h" -#include "common\Win32\DInputController.h" - -#define DIRECTINPUT_VERSION 0x0800 -#include -#include - -/*! windows dialog procedure */ -static INT_PTR CALLBACK DlgControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); -/*! configure input for the specified controller object */ -static VOID ConfigureInput(HWND hWndDlg, HWND hWndButton, XBCtrlObject object); -/*! enable / disable button windows */ -static VOID EnableButtonWindows(HWND hWndDlg, HWND hExclude, BOOL bEnable); - -/*! controller configuration */ -static DInputController g_DInputController; -/*! changes flag */ -static BOOL g_bHasChanges = FALSE; - -VOID ShowControllerConfig(HWND hwnd) -{ - /*! reset changes flag */ - g_bHasChanges = FALSE; - - /*! retrieve controller configuration */ - g_DInputController.m_settings = g_Settings->m_controller_dinput; - - /*! show dialog box */ - DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_CONTROLLER_CFG), hwnd, DlgControllerConfigProc); -} - -INT_PTR CALLBACK DlgControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch(uMsg) - { - case WM_INITDIALOG: - { - /*! set window icon */ - SetClassLong(hWndDlg, GCL_HICON, (LONG)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_CXBX))); - - /*! set default focus to X button */ - SetFocus(GetDlgItem(hWndDlg, IDC_SET_X)); - } - break; - - case WM_CLOSE: - { - /*! if changes have been made, check if the user wants to save them */ - if(g_bHasChanges) - { - int ret = MessageBox(hWndDlg, "Do you wish to apply your changes?", "Cxbx-Reloaded", MB_ICONQUESTION | MB_YESNOCANCEL); - - switch(ret) - { - case IDYES: - PostMessage(hWndDlg, WM_COMMAND, IDC_INPUT_CONFIG_ACCEPT, 0); - break; - case IDNO: - PostMessage(hWndDlg, WM_COMMAND, IDC_INPUT_CONFIG_CANCEL, 0); - break; - } - break; - } - - PostMessage(hWndDlg, WM_COMMAND, IDC_INPUT_CONFIG_CANCEL, 0); - } - break; - - case WM_COMMAND: - { - HWND hWndButton = GetDlgItem(hWndDlg, LOWORD(wParam)); - - switch(LOWORD(wParam)) - { - case IDC_INPUT_CONFIG_CANCEL: - EndDialog(hWndDlg, wParam); - break; - - case IDC_INPUT_CONFIG_ACCEPT: - g_Settings->m_controller_dinput = g_DInputController.m_settings; - EndDialog(hWndDlg, wParam); - break; - - case IDC_SET_LEFT_POSY: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_LTHUMBPOSY); - break; - - case IDC_SET_LEFT_NEGY: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_LTHUMBNEGY); - break; - - case IDC_SET_LEFT_POSX: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_LTHUMBPOSX); - break; - - case IDC_SET_LEFT_NEGX: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_LTHUMBNEGX); - break; - - case IDC_SET_RIGHT_POSY: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_RTHUMBPOSY); - break; - - case IDC_SET_RIGHT_NEGY: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_RTHUMBNEGY); - break; - - case IDC_SET_RIGHT_POSX: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_RTHUMBPOSX); - break; - - case IDC_SET_RIGHT_NEGX: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_RTHUMBNEGX); - break; - - case IDC_SET_X: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_X); - break; - - case IDC_SET_Y: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_Y); - break; - - case IDC_SET_A: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_A); - break; - - case IDC_SET_B: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_B); - break; - - case IDC_SET_WHITE: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_WHITE); - break; - - case IDC_SET_BLACK: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_BLACK); - break; - - case IDC_SET_LTRIGGER: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_LTRIGGER); - break; - - case IDC_SET_RTRIGGER: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_RTRIGGER); - break; - - case IDC_SET_DPAD_UP: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_DPADUP); - break; - - case IDC_SET_DPAD_DOWN: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_DPADDOWN); - break; - - case IDC_SET_DPAD_LEFT: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_DPADLEFT); - break; - - case IDC_SET_DPAD_RIGHT: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_DPADRIGHT); - break; - - case IDC_SET_BACK: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_BACK); - break; - - case IDC_SET_START: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_START); - break; - - case IDC_SET_LTHUMB: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_LTHUMB); - break; - - case IDC_SET_RTHUMB: - ConfigureInput(hWndDlg, hWndButton, XBCTRL_OBJECT_RTHUMB); - break; - - case IDC_CONFIGURE_ALL: - { - int v=0; - - struct _ConfigObj - { - int idcVal; - XBCtrlObject ctrl; - } - configObj[] = - { - { IDC_SET_X, XBCTRL_OBJECT_X }, - { IDC_SET_Y, XBCTRL_OBJECT_Y }, - { IDC_SET_A, XBCTRL_OBJECT_A }, - { IDC_SET_B, XBCTRL_OBJECT_B }, - { IDC_SET_WHITE, XBCTRL_OBJECT_WHITE }, - { IDC_SET_BLACK, XBCTRL_OBJECT_BLACK }, - { IDC_SET_LTRIGGER, XBCTRL_OBJECT_LTRIGGER }, - { IDC_SET_RTRIGGER, XBCTRL_OBJECT_RTRIGGER }, - { IDC_SET_DPAD_UP, XBCTRL_OBJECT_DPADUP }, - { IDC_SET_DPAD_DOWN, XBCTRL_OBJECT_DPADDOWN }, - { IDC_SET_DPAD_LEFT, XBCTRL_OBJECT_DPADLEFT }, - { IDC_SET_DPAD_RIGHT, XBCTRL_OBJECT_DPADRIGHT }, - { IDC_SET_BACK, XBCTRL_OBJECT_BACK }, - { IDC_SET_START, XBCTRL_OBJECT_START }, - { IDC_SET_LTHUMB, XBCTRL_OBJECT_LTHUMB }, - { IDC_SET_RTHUMB, XBCTRL_OBJECT_RTHUMB }, - { IDC_SET_LEFT_POSY, XBCTRL_OBJECT_LTHUMBPOSY }, - { IDC_SET_LEFT_NEGY, XBCTRL_OBJECT_LTHUMBNEGY }, - { IDC_SET_LEFT_NEGX, XBCTRL_OBJECT_LTHUMBNEGX }, - { IDC_SET_LEFT_POSX, XBCTRL_OBJECT_LTHUMBPOSX }, - { IDC_SET_RIGHT_POSY, XBCTRL_OBJECT_RTHUMBPOSY }, - { IDC_SET_RIGHT_NEGY, XBCTRL_OBJECT_RTHUMBNEGY }, - { IDC_SET_RIGHT_NEGX, XBCTRL_OBJECT_RTHUMBNEGX }, - { IDC_SET_RIGHT_POSX, XBCTRL_OBJECT_RTHUMBPOSX }, - }; - - for(v=0;v0;v--) - { - // update the button text every second - if(v%20 == 0) - { - char szBuffer[255]; - - sprintf(szBuffer, "%d", (v+19)/20); - - SetWindowText(hWndButton, szBuffer); - - // NOTE: This fix false positive of non-responding message when inputting all keys at once. - // Source: https://msdn.microsoft.com/en-us/library/windows/desktop/ms633526%28v=vs.85%29.aspx - MSG Msg; - PeekMessage(&Msg, hWndDlg, 0, 0, PM_NOREMOVE); - } - - if(g_DInputController.HasError()) - { - goto cleanup; - } - - if(g_DInputController.ConfigPoll(szNewText)) - { - break; - } - - Sleep(50); - } - - if(g_DInputController.HasError()) - { - goto cleanup; - } - else - { - g_DInputController.ConfigEnd(); - } - -cleanup: - - /*! enable all buttons */ - EnableButtonWindows(hWndDlg, hWndButton, TRUE); - - /*! update window with status */ - { - if(g_DInputController.HasError()) - { - sprintf(szNewText, "%s", g_DInputController.GetError().c_str()); - } - - SetWindowText(hWndButton, szOrgText); - - SetWindowText(GetDlgItem(hWndDlg, IDC_CONFIG_STATUS), szNewText); - - MSG Msg; - - while(PeekMessage(&Msg, hWndDlg, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE)); - while(PeekMessage(&Msg, hWndDlg, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); - - } - - bConfigDone = true; -} - -VOID EnableButtonWindows(HWND hWndDlg, HWND hExclude, BOOL bEnable) -{ - int v=0; - - /*! list of applicable child windows */ - int itemList[] = - { - IDC_SET_X, IDC_SET_Y, IDC_SET_A, IDC_SET_B, - IDC_SET_WHITE, IDC_SET_BLACK, - IDC_SET_LTHUMB, IDC_SET_RTHUMB, - IDC_SET_DPAD_UP, IDC_SET_DPAD_DOWN, IDC_SET_DPAD_LEFT, IDC_SET_DPAD_RIGHT, - IDC_SET_BACK, IDC_SET_START, IDC_SET_LTRIGGER, IDC_SET_RTRIGGER, - IDC_SET_LEFT_POSY, IDC_SET_LEFT_NEGY, IDC_SET_LEFT_NEGX, IDC_SET_LEFT_POSX, - IDC_SET_RIGHT_POSY, IDC_SET_RIGHT_NEGY, IDC_SET_RIGHT_NEGX, IDC_SET_RIGHT_POSX, - IDC_INPUT_CONFIG_CANCEL, IDC_INPUT_CONFIG_ACCEPT, - IDC_CONFIGURE_ALL - }; - - /*! enable / disable all the listed windows */ - for(v=0;v> 8; + + // Ensure that port_num is a valid xbox port + assert(port_num >= PORT_1 && port_num <= PORT_4); + + // Ensure that the controller type is valid + assert(dev_type == to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE) || + dev_type == to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S)); + + g_InputWindow = new InputWindow; + g_InputWindow->Initialize(hWndDlg, port_num, dev_type); + } + break; + + case WM_CLOSE: + { + if (g_InputWindow->IsProfileSaved()) { + delete g_InputWindow; + g_InputWindow = nullptr; + EndDialog(hWndDlg, wParam); + } + } + break; + + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_DEVICE_LIST: { + if (HIWORD(wParam) == CBN_SELCHANGE) { + g_InputWindow->UpdateCurrentDevice(); + } + } + break; + + case IDC_XID_PROFILE_NAME: { + if (HIWORD(wParam) == CBN_SELCHANGE) { + char name[50]; + HWND hwnd = GetDlgItem(hWndDlg, IDC_XID_PROFILE_NAME); + LRESULT str_idx = SendMessage(hwnd, CB_GETCURSEL, 0, 0); + if (str_idx != CB_ERR) { + SendMessage(hwnd, CB_GETLBTEXT, str_idx, reinterpret_cast(name)); + g_InputWindow->UpdateProfile(std::string(name), PROFILE_LOAD); + } + } + } + break; + + case IDC_XID_PROFILE_SAVE: + case IDC_XID_PROFILE_DELETE: { + if (HIWORD(wParam) == BN_CLICKED) { + char name[50]; + SendMessage(GetDlgItem(hWndDlg, IDC_XID_PROFILE_NAME), WM_GETTEXT, + sizeof(name), reinterpret_cast(name)); + g_InputWindow->UpdateProfile(std::string(name), (LOWORD(wParam) == IDC_XID_PROFILE_SAVE) ? PROFILE_SAVE : PROFILE_DELETE); + } + } + break; + + case IDC_XINP_DEFAULT: { + if (HIWORD(wParam) == BN_CLICKED) { + g_InputWindow->BindXInput(); + } + } + break; + + case IDC_XID_CLEAR: { + if (HIWORD(wParam) == BN_CLICKED) { + if (MessageBox(hWndDlg, "Remove all button bindings. Ok?", "Cxbx-Reloaded", MB_OKCANCEL | MB_ICONINFORMATION | MB_APPLMODAL) == IDOK) { + g_InputWindow->ClearBindings(); + } + } + } + break; + + case IDC_REFRESH_DEVICES: { + if (HIWORD(wParam) == BN_CLICKED) { + g_InputWindow->UpdateDeviceList(); + } + } + break; + + case IDC_SET_X: + case IDC_SET_Y: + case IDC_SET_A: + case IDC_SET_B: + case IDC_SET_WHITE: + case IDC_SET_BLACK: + case IDC_SET_LTRIGGER: + case IDC_SET_RTRIGGER: + case IDC_SET_LTHUMB: + case IDC_SET_RTHUMB: + case IDC_SET_START: + case IDC_SET_BACK: + case IDC_SET_DPAD_LEFT: + case IDC_SET_DPAD_RIGHT: + case IDC_SET_DPAD_UP: + case IDC_SET_DPAD_DOWN: + case IDC_SET_LEFT_POSY: + case IDC_SET_LEFT_NEGX: + case IDC_SET_LEFT_NEGY: + case IDC_SET_LEFT_POSX: + case IDC_SET_RIGHT_POSY: + case IDC_SET_RIGHT_NEGY: + case IDC_SET_RIGHT_NEGX: + case IDC_SET_RIGHT_POSX: { + if (HIWORD(wParam) == BN_CLICKED) { + g_InputWindow->BindButton(LOWORD(wParam)); + } + } + break; + + case IDC_SET_MOTOR: { + if (HIWORD(wParam) == BN_CLICKED) { + // Show rumble dialog box + DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_RUMBLE_CFG), hWndDlg, DlgRumbleConfigProc); + g_InputWindow->UpdateRumble(RUMBLE_UPDATE); + } + } + break; + } + } + break; + } + return FALSE; +} + +INT_PTR CALLBACK DlgRumbleConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + g_InputWindow->InitRumble(hWndDlg); + } + break; + + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_RUMBLE_LIST: { + g_InputWindow->UpdateRumble(RUMBLE_SET); + } + break; + + case IDC_RUMBLE_TEST: { + g_InputWindow->UpdateRumble(RUMBLE_TEST); + } + break; + } + } + break; + + case WM_CLOSE: + { + EndDialog(hWndDlg, wParam); + } + break; + } + return FALSE; +} + +LRESULT CALLBACK ProfileNameSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +{ + switch (uMsg) + { + // Remove the window subclass when this window is destroyed + case WM_NCDESTROY: { + RemoveWindowSubclass(hWnd, ProfileNameSubclassProc, uIdSubclass); + } + break; + + // Override the default system behaviour and process WM_CHAR messages ourselves + case WM_GETDLGCODE: { + if (lParam) { + LPMSG lpmsg = reinterpret_cast(lParam); + if (lpmsg->message == WM_CHAR) { + return DLGC_WANTCHARS; + } + } + } + break; + + case WM_CHAR: + { + // Make sure that we only allow printable ascii characters and some special keys to delete characters + if (!((wParam >= ' ' && wParam <= '~') + || wParam == VK_CANCEL + || wParam == VK_CLEAR + || wParam == VK_DELETE + || wParam == VK_BACK)) + { + return FALSE; + } + } + break; + + // Don't allow pasting operations, they can be used to bypass the filtering done in WM_CHAR + case WM_PASTE: + return FALSE; + } + + return DefSubclassProc(hWnd, uMsg, wParam, lParam); +} diff --git a/src/gui/DlgXboxControllerPortMapping.h b/src/gui/DlgDukeControllerConfig.h similarity index 77% rename from src/gui/DlgXboxControllerPortMapping.h rename to src/gui/DlgDukeControllerConfig.h index cce7933a01..f1208f818d 100644 --- a/src/gui/DlgXboxControllerPortMapping.h +++ b/src/gui/DlgDukeControllerConfig.h @@ -1,3 +1,5 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // ****************************************************************** // * // * This file is part of the Cxbx project. @@ -17,17 +19,12 @@ // * If not, write to the Free Software Foundation, Inc., // * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. // * -// * (c) 2002-2003 Aaron Robinson +// * (c) 2019 ergo720 // * // * All rights reserved // * // ****************************************************************** -#ifndef DLGXBOXCONTROLLERPORTMAPPING_H -#define DLGXBOXCONTROLLERPORTMAPPING_H -#include +#pragma once -/*! show controller configuration dialog */ -extern VOID ShowXboxControllerPortMappingConfig(HWND hwnd); - -#endif +INT_PTR CALLBACK DlgXidControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); diff --git a/src/gui/DlgInputConfig.cpp b/src/gui/DlgInputConfig.cpp new file mode 100644 index 0000000000..647b9cd844 --- /dev/null +++ b/src/gui/DlgInputConfig.cpp @@ -0,0 +1,204 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +// ****************************************************************** +// * +// * This file is part of the Cxbx project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2019 ergo720 +// * +// * All rights reserved +// * +// ****************************************************************** + +#include "windows.h" +#include "DlgDukeControllerConfig.h" +#include "ResCxbx.h" +#include "input\InputManager.h" +#include "Logging.h" +#include "Settings.hpp" +#include "common\IPCHybrid.hpp" +#include "EmuShared.h" + + +// Windows dialog procedure for the input menu +static INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +HWND g_ChildWnd = NULL; + +int Gui2XboxPortArray[4] = { + 3, + 4, + 1, + 2 +}; + + +void SyncInputSettings(int port_num, int dev_type) +{ + if (g_ChildWnd) { + // Sync updated input to kernel process to use run-time settings. + g_EmuShared->SetInputDevTypeSettings(&g_Settings->m_input[port_num].Type, port_num); + + if (dev_type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { + std::string dev_name = g_Settings->m_input[port_num].DeviceName; + std::string profile_name = g_Settings->m_input[port_num].ProfileName; + + g_EmuShared->SetInputDevNameSettings(dev_name.c_str(), port_num); + auto it = std::find_if(g_Settings->m_input_profiles[dev_type].begin(), + g_Settings->m_input_profiles[dev_type].end(), [&profile_name](const auto& profile) { + if (profile.ProfileName == profile_name) { + return true; + } + return false; + }); + if (it != g_Settings->m_input_profiles[dev_type].end()) { + char controls_name[XBOX_CTRL_NUM_BUTTONS][30]; + for (int index = 0; index < dev_num_buttons[dev_type]; index++) { + strncpy(controls_name[index], it->ControlList[index].c_str(), 30); + } + g_EmuShared->SetInputBindingsSettings(controls_name, XBOX_CTRL_NUM_BUTTONS, port_num); + } + } +#if 0 // lle usb + ipc_send_kernel_update(IPC_UPDATE_KERNEL::CONFIG_INPUT_SYNC, PORT_DEC(Gui2XboxPortArray[port_num]), + reinterpret_cast(g_ChildWnd)); +#else + ipc_send_kernel_update(IPC_UPDATE_KERNEL::CONFIG_INPUT_SYNC, port_num, reinterpret_cast(g_ChildWnd)); +#endif + } +} + +void ShowInputConfig(HWND hwnd, HWND ChildWnd) +{ + g_InputDeviceManager.Initialize(true); + g_ChildWnd = ChildWnd; + + // Show dialog box + DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_INPUT_CFG), hwnd, DlgInputConfigProc); +} + +INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND hHandle; + + // Set window icon + SetClassLong(hWndDlg, GCL_HICON, (LONG)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_CXBX))); + + for (int i = 0, j = 0; i != 4; i++) { + hHandle = GetDlgItem(hWndDlg, IDC_DEVICE_PORT1 + i); + for (auto str : { "None", "MS Controller Duke" }) { + LRESULT index = SendMessage(hHandle, CB_ADDSTRING, 0, reinterpret_cast(str)); + SendMessage(hHandle, CB_SETITEMDATA, index, + to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) + j); + if (g_Settings->m_input[i].Type == to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) + j) { + SendMessage(hHandle, CB_SETCURSEL, index, 0); + if (g_Settings->m_input[i].Type == to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { + EnableWindow(GetDlgItem(hWndDlg, IDC_CONFIGURE_PORT1 + i), FALSE); + } + } + j++; + } + j = 0; + } + } + break; + + case WM_CLOSE: + { + g_InputDeviceManager.Shutdown(); + g_ChildWnd = NULL; + EndDialog(hWndDlg, wParam); + } + break; + + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_CONFIGURE_PORT1: + case IDC_CONFIGURE_PORT2: + case IDC_CONFIGURE_PORT3: + case IDC_CONFIGURE_PORT4: { + if (HIWORD(wParam) == BN_CLICKED) { + int port = + LOWORD(wParam) == IDC_CONFIGURE_PORT1 ? 0 : + LOWORD(wParam) == IDC_CONFIGURE_PORT2 ? 1 : + LOWORD(wParam) == IDC_CONFIGURE_PORT3 ? 2 : + LOWORD(wParam) == IDC_CONFIGURE_PORT4 ? 3 : + -1; + assert(port != -1); + HWND hHandle = GetDlgItem(hWndDlg, IDC_DEVICE_PORT1 + port); + int DeviceType = SendMessage(hHandle, CB_GETITEMDATA, SendMessage(hHandle, CB_GETCURSEL, 0, 0), 0); + switch (DeviceType) + { + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): { + DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_XID_DUKE_CFG), hWndDlg, DlgXidControllerConfigProc, + (DeviceType << 8) | port); + } + break; + + default: + break; + } + assert(DeviceType > to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) && + DeviceType < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)); + + // Also inform the kernel process if it exists + SyncInputSettings(port, DeviceType); + } + } + break; + + case IDC_DEVICE_PORT1: + case IDC_DEVICE_PORT2: + case IDC_DEVICE_PORT3: + case IDC_DEVICE_PORT4: + { + if (HIWORD(wParam) == CBN_SELCHANGE) { + LRESULT dev_type = SendMessage(GetDlgItem(hWndDlg, LOWORD(wParam)), CB_GETITEMDATA, + SendMessage(GetDlgItem(hWndDlg, LOWORD(wParam)), CB_GETCURSEL, 0, 0), 0); + int port = + LOWORD(wParam) == IDC_DEVICE_PORT1 ? 0 : + LOWORD(wParam) == IDC_DEVICE_PORT2 ? 1 : + LOWORD(wParam) == IDC_DEVICE_PORT3 ? 2 : + LOWORD(wParam) == IDC_DEVICE_PORT4 ? 3 : + -1; + assert(port != -1); + if (dev_type == to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { + EnableWindow(GetDlgItem(hWndDlg, IDC_CONFIGURE_PORT1 + port), FALSE); + } + else { + EnableWindow(GetDlgItem(hWndDlg, IDC_CONFIGURE_PORT1 + port), TRUE); + } + + g_Settings->m_input[port].Type = dev_type; + + // Also inform the kernel process if it exists + SyncInputSettings(port, dev_type); + } + } + break; + } + } + break; + } + return FALSE; +} diff --git a/src/gui/DlgControllerConfig.h b/src/gui/DlgInputConfig.h similarity index 77% rename from src/gui/DlgControllerConfig.h rename to src/gui/DlgInputConfig.h index 5ee6b7567a..a21b2f57d6 100644 --- a/src/gui/DlgControllerConfig.h +++ b/src/gui/DlgInputConfig.h @@ -1,3 +1,5 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // ****************************************************************** // * // * This file is part of the Cxbx project. @@ -17,17 +19,16 @@ // * If not, write to the Free Software Foundation, Inc., // * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. // * -// * (c) 2002-2003 Aaron Robinson +// * (c) 2019 ergo720 // * // * All rights reserved // * // ****************************************************************** -#ifndef DLGCONTROLLERCONFIG_H -#define DLGCONTROLLERCONFIG_H -#include +#ifndef DLGINPUTCONFIG_H +#define DLGINPUTCONFIG_H -/*! show controller configuration dialog */ -extern VOID ShowControllerConfig(HWND hwnd); +VOID ShowInputConfig(HWND hwnd, HWND ChildWnd); +extern HWND g_ChildWnd; #endif diff --git a/src/gui/DlgLoggingConfig.cpp b/src/gui/DlgLoggingConfig.cpp index 02f34b4420..913cbe2a64 100644 --- a/src/gui/DlgLoggingConfig.cpp +++ b/src/gui/DlgLoggingConfig.cpp @@ -60,7 +60,7 @@ static int g_DlgIndexes[] = { IDC_LOG_VTXB, IDC_LOG_DINP, IDC_LOG_XINP, - IDC_LOG_SDL2, + IDC_LOG_SDL, IDC_LOG_FILE, IDC_LOG_X86, IDC_LOG_HLE, @@ -73,6 +73,7 @@ static int g_DlgIndexes[] = { IDC_LOG_HUB, IDC_LOG_XIDCTRL, IDC_LOG_ADM, + IDC_LOG_INPSYS, // Kernel IDC_LOG_KRNL, IDC_LOG_LOG, @@ -347,7 +348,7 @@ INT_PTR CALLBACK DlgLogConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM case IDC_LOG_VTXB: case IDC_LOG_DINP: case IDC_LOG_XINP: - case IDC_LOG_SDL2: + case IDC_LOG_SDL: case IDC_LOG_FILE: case IDC_LOG_X86: case IDC_LOG_HLE: @@ -359,7 +360,8 @@ INT_PTR CALLBACK DlgLogConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM case IDC_LOG_USB: case IDC_LOG_HUB: case IDC_LOG_XIDCTRL: - case IDC_LOG_ADM: + case IDC_LOG_ADM: + case IDC_LOG_INPSYS: case IDC_LOG_KRNL: case IDC_LOG_LOG: case IDC_LOG_XBOX: diff --git a/src/gui/DlgXboxControllerPortMapping.cpp b/src/gui/DlgXboxControllerPortMapping.cpp deleted file mode 100644 index 08e931a18d..0000000000 --- a/src/gui/DlgXboxControllerPortMapping.cpp +++ /dev/null @@ -1,263 +0,0 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -// ****************************************************************** -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2002-2003 Aaron Robinson -// * -// * All rights reserved -// * -// ****************************************************************** - -// Without this, you'll get a ton of errors from the std library for some unknown reason... -#include "Logging.h" - -#include "common\Settings.hpp" // for g_Settings - -#include "DlgXboxControllerPortMapping.h" -#include "../Common/Win32/XBPortMapping.h" -#include "Windowsx.h" -#include "ResCxbx.h" -#include "core\kernel\support\EmuXTL.h" - - -/*! windows dialog procedure */ -static INT_PTR CALLBACK DlgXboxControllerPortMappingProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); -/*! changes flag */ -static BOOL g_bHasChanges = FALSE; -static WPARAM wXboxToHostTypePORT[4][7] = { - { IDC_HOST_NOTCONNECT_0_0 ,IDC_HOST_XINPUT_0_0,IDC_HOST_XINPUT_0_1,IDC_HOST_XINPUT_0_2,IDC_HOST_XINPUT_0_3,IDC_HOST_DINPUT_0_0,IDC_HOST_VIRTUAL_SBC_0_0 }, - { IDC_HOST_NOTCONNECT_1_0 ,IDC_HOST_XINPUT_1_0,IDC_HOST_XINPUT_1_1,IDC_HOST_XINPUT_1_2,IDC_HOST_XINPUT_1_3,IDC_HOST_DINPUT_1_0,IDC_HOST_VIRTUAL_SBC_1_0 }, - { IDC_HOST_NOTCONNECT_2_0 ,IDC_HOST_XINPUT_2_0,IDC_HOST_XINPUT_2_1,IDC_HOST_XINPUT_2_2,IDC_HOST_XINPUT_2_3,IDC_HOST_DINPUT_2_0,IDC_HOST_VIRTUAL_SBC_2_0 }, - { IDC_HOST_NOTCONNECT_3_0 ,IDC_HOST_XINPUT_3_0,IDC_HOST_XINPUT_3_1,IDC_HOST_XINPUT_3_2,IDC_HOST_XINPUT_3_3,IDC_HOST_DINPUT_3_0,IDC_HOST_VIRTUAL_SBC_3_0 } -}; - -void ShowXboxControllerPortMappingConfig(HWND hwnd) -{ - /*! reset changes flag */ - g_bHasChanges = FALSE; - - /*! show dialog box */ - DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_CONTROLLER_HOST_MAPPING), hwnd, DlgXboxControllerPortMappingProc); -} - -INT_PTR CALLBACK DlgXboxControllerPortMappingProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch(uMsg) - { - case WM_INITDIALOG: - { - /*! set window icon */ - SetClassLong(hWndDlg, GCL_HICON, (LONG)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_CXBX))); - // Load configuration from settings. - XBPortMappingSet(g_Settings->m_controller_port); - //Init dialog selections per global array contenst. - XTL::DWORD port = 0; - int index = 0; - XTL::DWORD dwHostType = 1; - XTL::DWORD dwHostPort = 0; - for (port = 0; port < 4; port++) { - GetXboxPortToHostPort(port, dwHostType, dwHostPort); - switch (dwHostType) { - case X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_NOTCONNECT: - index = 0; - break; - case X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT: - index = 1 + dwHostPort; - break; - case X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_DINPUT: - index = 5; - break; - case X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_VIRTUAL_SBC: - index = 6; - break; - - default: - index = 0; - break; - } - Button_SetCheck(GetDlgItem(hWndDlg, wXboxToHostTypePORT[port][index]), BST_CHECKED); - PostMessage(hWndDlg, WM_COMMAND, wXboxToHostTypePORT[port][index], 0); - } - - - /*! set default focus to X button */ - SetFocus(GetDlgItem(hWndDlg, IDC_HOST_APPLY)); - } - break; - - case WM_CLOSE: - { - /*! if changes have been made, check if the user wants to save them */ - if(g_bHasChanges) - { - int ret = MessageBox(hWndDlg, "Do you wish to apply your changes?", "Cxbx-Reloaded", MB_ICONQUESTION | MB_YESNOCANCEL); - - switch(ret) - { - case IDYES: - PostMessage(hWndDlg, WM_COMMAND, IDC_HOST_APPLY, 0); - break; - case IDNO: - PostMessage(hWndDlg, WM_COMMAND, IDC_HOST_CANCEL, 0); - break; - } - break; - } - - PostMessage(hWndDlg, WM_COMMAND, IDC_INPUT_CONFIG_CANCEL, 0); - } - break; - - case WM_COMMAND: - { - HWND hWndButton = GetDlgItem(hWndDlg, LOWORD(wParam)); - - switch(LOWORD(wParam)) - { - case IDC_HOST_CANCEL: - EndDialog(hWndDlg, wParam); - break; - case IDC_HOST_APPLY: - // Save configuration to settings. - XBPortMappingGet(g_Settings->m_controller_port); - EndDialog(hWndDlg, wParam); - break; - //set host type and host port in global array xbox to host bridge for xbox port 0 - case IDC_HOST_NOTCONNECT_0_0: - SetXboxPortToHostPort(0, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_NOTCONNECT, 0); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_0_0: - SetXboxPortToHostPort(0, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 0); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_0_1: - SetXboxPortToHostPort(0, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 1); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_0_2: - SetXboxPortToHostPort(0, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 2); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_0_3: - SetXboxPortToHostPort(0, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 3); - g_bHasChanges = TRUE; - break; - case IDC_HOST_DINPUT_0_0: - SetXboxPortToHostPort(0, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_DINPUT, 0); - g_bHasChanges = TRUE; - break; - case IDC_HOST_VIRTUAL_SBC_0_0: - SetXboxPortToHostPort(0, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_VIRTUAL_SBC, 0); - g_bHasChanges = TRUE; - break; - //set host type and host port in global array xbox to host bridge for xbox port 1 - case IDC_HOST_NOTCONNECT_1_0: - SetXboxPortToHostPort(1, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_NOTCONNECT, 0); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_1_0: - SetXboxPortToHostPort(1, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 0); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_1_1: - SetXboxPortToHostPort(1, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 1); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_1_2: - SetXboxPortToHostPort(1, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 2); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_1_3: - SetXboxPortToHostPort(1, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 3); - g_bHasChanges = TRUE; - break; - case IDC_HOST_DINPUT_1_0: - SetXboxPortToHostPort(1, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_DINPUT, 0); - g_bHasChanges = TRUE; - break; - case IDC_HOST_VIRTUAL_SBC_1_0: - SetXboxPortToHostPort(1, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_VIRTUAL_SBC, 0); - g_bHasChanges = TRUE; - break; - //set host type and host port in global array xbox to host bridge for xbox port 2 - case IDC_HOST_NOTCONNECT_2_0: - SetXboxPortToHostPort(2, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_NOTCONNECT, 0); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_2_0: - SetXboxPortToHostPort(2, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 0); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_2_1: - SetXboxPortToHostPort(2, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 1); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_2_2: - SetXboxPortToHostPort(2, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 2); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_2_3: - SetXboxPortToHostPort(2, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 3); - g_bHasChanges = TRUE; - break; - case IDC_HOST_DINPUT_2_0: - SetXboxPortToHostPort(2, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_DINPUT, 0); - g_bHasChanges = TRUE; - break; - case IDC_HOST_VIRTUAL_SBC_2_0: - SetXboxPortToHostPort(2, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_VIRTUAL_SBC, 0); - g_bHasChanges = TRUE; - break; - //set host type and host port in global array xbox to host bridge for xbox port 3 - case IDC_HOST_NOTCONNECT_3_0: - SetXboxPortToHostPort(3, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_NOTCONNECT, 0); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_3_0: - SetXboxPortToHostPort(3, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 0); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_3_1: - SetXboxPortToHostPort(3, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 1); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_3_2: - SetXboxPortToHostPort(3, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 2); - g_bHasChanges = TRUE; - break; - case IDC_HOST_XINPUT_3_3: - SetXboxPortToHostPort(3, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_XINPUT, 3); - g_bHasChanges = TRUE; - break; - case IDC_HOST_DINPUT_3_0: - SetXboxPortToHostPort(3, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_DINPUT, 0); - g_bHasChanges = TRUE; - break; - case IDC_HOST_VIRTUAL_SBC_3_0: - SetXboxPortToHostPort(3, X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_VIRTUAL_SBC, 0); - g_bHasChanges = TRUE; - break; - } - } - break; - } - return FALSE; -} diff --git a/src/gui/ResCxbx.h b/src/gui/ResCxbx.h index 682fda4542..108781b678 100644 --- a/src/gui/ResCxbx.h +++ b/src/gui/ResCxbx.h @@ -7,7 +7,7 @@ #define IDR_MAINMENU 103 #define IDB_LOGO 106 #define IDB_ABOUT 108 -#define IDD_CONTROLLER_CFG 111 +#define IDD_INPUT_CFG 111 #define IDD_LOGGING_CFG 112 #define IDD_VIDEO_CFG 113 #define IDD_AUDIO_CFG 114 @@ -17,9 +17,10 @@ #define IDD_ABOUT 119 #define IDR_CONTRIBUTORS 121 #define IDR_COPYING 122 -#define IDD_CONTROLLER_HOST_MAPPING 131 #define IDD_VIRTUAL_SBC_FEEDBACK 133 -#define IDD_NETWORK_CFG 134 +#define IDD_XID_DUKE_CFG 134 +#define IDD_RUMBLE_CFG 135 +#define IDD_NETWORK_CFG 136 #define IDC_LOG_CANCEL 892 #define IDC_LOG_ACCEPT 893 #define IDC_LOG_ENABLE_GENERAL 894 @@ -52,7 +53,7 @@ #define IDC_LOG_VTXB 921 #define IDC_LOG_DINP 922 #define IDC_LOG_XINP 923 -#define IDC_LOG_SDL2 924 +#define IDC_LOG_SDL 924 #define IDC_LOG_FILE 925 #define IDC_LOG_X86 926 #define IDC_LOG_HLE 927 @@ -85,6 +86,8 @@ #define IDC_LOG_RTL 954 #define IDC_LOG_XC 955 #define IDC_LOG_XE 956 +#define IDC_LOG_INPSYS 957 +#define IDC_SET_MOTOR 999 #define IDC_SET_X 1000 #define IDC_SET_Y 1001 #define IDC_SET_A 1002 @@ -188,39 +191,9 @@ #define ID_GUI_STATUS_LOG_ENABLED 1099 #define IDC_AC_MUTE_ON_UNFOCUS_DISABLE 1100 #define IDC_XBOX_PORT_0 1158 -#define IDC_HOST_NOTCONNECT_0_0 1159 -#define IDC_HOST_XINPUT_0_0 1160 -#define IDC_HOST_XINPUT_0_1 1161 -#define IDC_HOST_XINPUT_0_2 1162 -#define IDC_HOST_XINPUT_0_3 1163 -#define IDC_HOST_DINPUT_0_0 1164 -#define IDC_HOST_VIRTUAL_SBC_0_0 1165 #define IDC_XBOX_PORT_1 1166 -#define IDC_HOST_NOTCONNECT_1_0 1167 -#define IDC_HOST_XINPUT_1_0 1168 -#define IDC_HOST_XINPUT_1_1 1169 -#define IDC_HOST_XINPUT_1_2 1170 -#define IDC_HOST_XINPUT_1_3 1171 -#define IDC_HOST_DINPUT_1_0 1172 -#define IDC_HOST_VIRTUAL_SBC_1_0 1173 #define IDC_XBOX_PORT_2 1174 -#define IDC_HOST_NOTCONNECT_2_0 1175 -#define IDC_HOST_XINPUT_2_0 1176 -#define IDC_HOST_XINPUT_2_1 1177 -#define IDC_HOST_XINPUT_2_2 1178 -#define IDC_HOST_XINPUT_2_3 1179 -#define IDC_HOST_DINPUT_2_0 1180 -#define IDC_HOST_VIRTUAL_SBC_2_0 1181 #define IDC_XBOX_PORT_3 1182 -#define IDC_HOST_NOTCONNECT_3_0 1183 -#define IDC_HOST_XINPUT_3_0 1184 -#define IDC_HOST_XINPUT_3_1 1185 -#define IDC_HOST_XINPUT_3_2 1186 -#define IDC_HOST_XINPUT_3_3 1187 -#define IDC_HOST_DINPUT_3_0 1188 -#define IDC_HOST_VIRTUAL_SBC_3_0 1189 -#define IDC_HOST_APPLY 1190 -#define IDC_HOST_CANCEL 1191 #define IDC_LEFTBLOCK 1200 #define IDC_LEFTBLOCK2 1201 #define IDC_RIGHTBLOCK 1202 @@ -298,7 +271,33 @@ #define IDC_EVENT_LV 1273 #define IDC_CXBXR_EVENTS 1274 #define IDC_KERNEL_EVENTS 1275 -#define IDC_NETWORK_ADAPTER 1276 +#define IDC_XID_CONFIG 1276 +#define IDC_DEVICE_PORT1 1277 +#define IDC_DEVICE_PORT2 1278 +#define IDC_DEVICE_PORT3 1279 +#define IDC_DEVICE_PORT4 1280 +#define IDC_CONFIGURE_PORT1 1281 +#define IDC_CONFIGURE_PORT2 1282 +#define IDC_CONFIGURE_PORT3 1283 +#define IDC_CONFIGURE_PORT4 1284 +#define IDC_DEVICE_LIST 1285 +#define IDC_REFRESH_DEVICES 1286 +#define IDC_XINP_DEFAULT 1287 +#define IDC_XID_PROFILE 1288 +#define IDC_XID_PROFILE_NAME 1289 +#define IDC_XID_PROFILE_SAVE 1291 +#define IDC_XID_PROFILE_DELETE 1292 +#define IDC_XID_BUTTONS 1293 +#define IDC_XID_LSTICK 1294 +#define IDC_XID_RSTICK 1295 +#define IDC_XID_DPAD 1296 +#define IDC_XID_TRIGGERS 1297 +#define IDC_XID_RUMBLE 1298 +#define IDC_XID_OPTIONS 1299 +#define IDC_XID_CLEAR 1300 +#define IDC_RUMBLE_LIST 1301 +#define IDC_RUMBLE_TEST 1302 +#define IDC_NETWORK_ADAPTER 1303 #define ID_FILE_EXIT 40005 #define ID_HELP_ABOUT 40008 #define ID_EMULATION_START 40009 @@ -319,7 +318,7 @@ #define ID_EMULATION_LLE_APU 40039 #define ID_EMULATION_LLE_GPU 40040 #define ID_EMULATION_LLE_JIT 40041 -#define ID_SETTINGS_CONFIG_CONTROLLER 40046 +#define ID_SETTINGS_CONFIG_INPUT 40046 #define ID_SETTINGS_CONFIG_VIDEO 40047 #define ID_SETTINGS_CONFIG_AUDIO 40048 #define ID_SETTINGS_CONFIG_EEPROM 40049 @@ -347,7 +346,6 @@ #define ID_FPS 40096 #define ID_HACKS_RUNXBOXTHREADSONALLCORES 40098 #define ID_HACKS_SKIPRDTSCPATCHING 40099 -#define ID_SETTINGS_CONFIG_XBOX_CONTROLLER_MAPPING 40101 #define ID_HACKS_SPEEDHACKS 40103 #define ID_SETTINGS_CONFIG_DLOCCUSTOM 40104 #define ID_SETTINGS_CONFIG_DLOCAPPDATA 40105 @@ -357,6 +355,7 @@ #define ID_SYNC_CONFIG_LOGGING 40109 #define ID_LOG 40110 #define ID_SETTINGS_CONFIG_NETWORK 40111 +#define ID_SYNC_CONFIG_INPUT 40112 #define IDC_STATIC -1 // Next default values for new objects diff --git a/src/gui/WndMain.cpp b/src/gui/WndMain.cpp index 33906409ba..6c79e79559 100644 --- a/src/gui/WndMain.cpp +++ b/src/gui/WndMain.cpp @@ -32,13 +32,12 @@ #include "Logging.h" #include "WndMain.h" #include "DlgAbout.h" -#include "DlgControllerConfig.h" +#include "DlgInputConfig.h" #include "DlgVideoConfig.h" #include "DlgAudioConfig.h" #include "DlgNetworkConfig.h" #include "DlgEepromConfig.h" #include "DlgLoggingConfig.h" -#include "DlgXboxControllerPortMapping.h" #include "common\xbe\XbePrinter.h" // For DumpInformation #include "EmuShared.h" #include "core\kernel\support\EmuXTL.h" @@ -960,12 +959,8 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP } break; - case ID_SETTINGS_CONFIG_XBOX_CONTROLLER_MAPPING: - ShowXboxControllerPortMappingConfig(hwnd); - break; - - case ID_SETTINGS_CONFIG_CONTROLLER: - ShowControllerConfig(hwnd); + case ID_SETTINGS_CONFIG_INPUT: + ShowInputConfig(hwnd, m_hwndChild); break; case ID_SETTINGS_CONFIG_VIDEO: diff --git a/src/gui/WndMain.h b/src/gui/WndMain.h index 1e56558616..fe176a8cb3 100644 --- a/src/gui/WndMain.h +++ b/src/gui/WndMain.h @@ -26,7 +26,7 @@ #define WNDMAIN_H #include "Wnd.h" -#include "common\xbe\/Xbe.h" +#include "common\xbe\Xbe.h" #include