mirror of
https://github.com/isledecomp/isle-portable.git
synced 2025-08-03 07:36:20 -04:00
Add device and gamepad haptics to web port (#613)
* Add device and gamepad haptics to web port * Update skip.yml
This commit is contained in:
parent
d0dc595fc5
commit
deca5e5a2e
@ -555,6 +555,7 @@ if (ISLE_BUILD_APP)
|
||||
ISLE/emscripten/config.cpp
|
||||
ISLE/emscripten/events.cpp
|
||||
ISLE/emscripten/filesystem.cpp
|
||||
ISLE/emscripten/haptic.cpp
|
||||
ISLE/emscripten/messagebox.cpp
|
||||
ISLE/emscripten/window.cpp
|
||||
)
|
||||
|
52
ISLE/emscripten/haptic.cpp
Normal file
52
ISLE/emscripten/haptic.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include "haptic.h"
|
||||
|
||||
#include "compat.h"
|
||||
#include "lego/sources/misc/legoutil.h"
|
||||
#include "legoinputmanager.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include <emscripten/html5.h>
|
||||
|
||||
void Emscripten_HandleRumbleEvent(float p_lowFrequencyRumble, float p_highFrequencyRumble, MxU32 p_milliseconds)
|
||||
{
|
||||
std::visit(
|
||||
overloaded{
|
||||
[](LegoInputManager::SDL_KeyboardID_v p_id) {},
|
||||
[](LegoInputManager::SDL_MouseID_v p_id) {},
|
||||
[p_lowFrequencyRumble, p_highFrequencyRumble, p_milliseconds](LegoInputManager::SDL_JoystickID_v p_id) {
|
||||
const char* name = SDL_GetJoystickNameForID((SDL_JoystickID) p_id);
|
||||
if (name) {
|
||||
MAIN_THREAD_EM_ASM(
|
||||
{
|
||||
const name = UTF8ToString($0);
|
||||
const gamepads = navigator.getGamepads();
|
||||
for (const gamepad of gamepads) {
|
||||
if (gamepad && gamepad.connected && gamepad.id == name && gamepad.vibrationActuator) {
|
||||
gamepad.vibrationActuator.playEffect("dual-rumble", {
|
||||
startDelay : 0,
|
||||
weakMagnitude : $1,
|
||||
strongMagnitude : $2,
|
||||
duration : $3,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
name,
|
||||
SDL_clamp(p_lowFrequencyRumble, 0, 1),
|
||||
SDL_clamp(p_highFrequencyRumble, 0, 1),
|
||||
p_milliseconds
|
||||
);
|
||||
}
|
||||
},
|
||||
[](LegoInputManager::SDL_TouchID_v p_id) {
|
||||
MAIN_THREAD_EM_ASM({
|
||||
if (navigator.vibrate) {
|
||||
navigator.vibrate(700);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
InputManager()->GetLastInputMethod()
|
||||
);
|
||||
}
|
8
ISLE/emscripten/haptic.h
Normal file
8
ISLE/emscripten/haptic.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef EMSCRIPTEN_HAPTIC_H
|
||||
#define EMSCRIPTEN_HAPTIC_H
|
||||
|
||||
#include "mxtypes.h"
|
||||
|
||||
void Emscripten_HandleRumbleEvent(float p_lowFrequencyRumble, float p_highFrequencyRumble, MxU32 p_milliseconds);
|
||||
|
||||
#endif // EMSCRIPTEN_HAPTIC_H
|
@ -54,6 +54,7 @@
|
||||
#include "emscripten/config.h"
|
||||
#include "emscripten/events.h"
|
||||
#include "emscripten/filesystem.h"
|
||||
#include "emscripten/haptic.h"
|
||||
#include "emscripten/messagebox.h"
|
||||
#include "emscripten/window.h"
|
||||
#endif
|
||||
@ -501,6 +502,16 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDL_EVENT_KEYBOARD_ADDED:
|
||||
if (InputManager()) {
|
||||
InputManager()->AddKeyboard(event->kdevice.which);
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_KEYBOARD_REMOVED:
|
||||
if (InputManager()) {
|
||||
InputManager()->RemoveKeyboard(event->kdevice.which);
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_MOUSE_ADDED:
|
||||
if (InputManager()) {
|
||||
InputManager()->AddMouse(event->mdevice.which);
|
||||
@ -789,8 +800,11 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
|
||||
}
|
||||
}
|
||||
else if (event->user.type == g_legoSdlEvents.m_hitActor && g_isle->GetHaptic()) {
|
||||
if (InputManager()) {
|
||||
InputManager()->HandleRumbleEvent();
|
||||
if (!InputManager()->HandleRumbleEvent(0.5f, 0.5f, 0.5f, 700)) {
|
||||
// Platform-specific handling
|
||||
#ifdef __EMSCRIPTEN__
|
||||
Emscripten_HandleRumbleEvent(0.5f, 0.5f, 700);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,24 +154,29 @@ public:
|
||||
void GetKeyboardState();
|
||||
MxResult GetNavigationKeyStates(MxU32& p_keyFlags);
|
||||
MxResult GetNavigationTouchStates(MxU32& p_keyFlags);
|
||||
LEGO1_EXPORT void AddKeyboard(SDL_KeyboardID p_keyboardID);
|
||||
LEGO1_EXPORT void RemoveKeyboard(SDL_KeyboardID p_keyboardID);
|
||||
LEGO1_EXPORT void AddMouse(SDL_MouseID p_mouseID);
|
||||
LEGO1_EXPORT void RemoveMouse(SDL_MouseID p_mouseID);
|
||||
LEGO1_EXPORT void AddJoystick(SDL_JoystickID p_joystickID);
|
||||
LEGO1_EXPORT void RemoveJoystick(SDL_JoystickID p_joystickID);
|
||||
LEGO1_EXPORT MxBool HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touchScheme);
|
||||
LEGO1_EXPORT MxBool HandleRumbleEvent();
|
||||
LEGO1_EXPORT MxBool
|
||||
HandleRumbleEvent(float p_strength, float p_lowFrequencyRumble, float p_highFrequencyRumble, MxU32 p_milliseconds);
|
||||
LEGO1_EXPORT void UpdateLastInputMethod(SDL_Event* p_event);
|
||||
const auto& GetLastInputMethod() { return m_lastInputMethod; }
|
||||
|
||||
// SYNTHETIC: LEGO1 0x1005b8d0
|
||||
// LegoInputManager::`scalar deleting destructor'
|
||||
|
||||
private:
|
||||
// clang-format off
|
||||
enum class SDL_KeyboardID_v : SDL_KeyboardID {};
|
||||
enum class SDL_MouseID_v : SDL_MouseID {};
|
||||
enum class SDL_JoystickID_v : SDL_JoystickID {};
|
||||
enum class SDL_TouchID_v : SDL_TouchID {};
|
||||
// clang-format on
|
||||
|
||||
// SYNTHETIC: LEGO1 0x1005b8d0
|
||||
// LegoInputManager::`scalar deleting destructor'
|
||||
|
||||
private:
|
||||
void InitializeHaptics();
|
||||
|
||||
MxCriticalSection m_criticalSection; // 0x58
|
||||
@ -197,10 +202,11 @@ private:
|
||||
SDL_Point m_touchVirtualThumb = {0, 0};
|
||||
SDL_FPoint m_touchVirtualThumbOrigin;
|
||||
std::map<SDL_FingerID, MxU32> m_touchFlags;
|
||||
std::map<SDL_KeyboardID, std::pair<void*, void*>> m_keyboards;
|
||||
std::map<SDL_MouseID, std::pair<void*, SDL_Haptic*>> m_mice;
|
||||
std::map<SDL_JoystickID, std::pair<SDL_Gamepad*, SDL_Haptic*>> m_joysticks;
|
||||
std::map<SDL_HapticID, SDL_Haptic*> m_otherHaptics;
|
||||
std::variant<SDL_MouseID_v, SDL_JoystickID_v, SDL_TouchID_v> m_lastInputMethod;
|
||||
std::variant<SDL_KeyboardID_v, SDL_MouseID_v, SDL_JoystickID_v, SDL_TouchID_v> m_lastInputMethod;
|
||||
};
|
||||
|
||||
// TEMPLATE: LEGO1 0x10028850
|
||||
|
@ -160,7 +160,8 @@ MxResult LegoInputManager::GetNavigationKeyStates(MxU32& p_keyFlags)
|
||||
// FUNCTION: LEGO1 0x1005c320
|
||||
MxResult LegoInputManager::GetJoystickState(MxU32* p_joystickX, MxU32* p_joystickY, MxU32* p_povPosition)
|
||||
{
|
||||
if (m_joysticks.empty() && m_touchScheme != e_gamepad) {
|
||||
if (!std::holds_alternative<SDL_JoystickID_v>(m_lastInputMethod) &&
|
||||
!(std::holds_alternative<SDL_TouchID_v>(m_lastInputMethod) && m_touchScheme == e_gamepad)) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
@ -513,6 +514,24 @@ MxResult LegoInputManager::GetNavigationTouchStates(MxU32& p_keyStates)
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void LegoInputManager::AddKeyboard(SDL_KeyboardID p_keyboardID)
|
||||
{
|
||||
if (m_keyboards.count(p_keyboardID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_keyboards[p_keyboardID] = {nullptr, nullptr};
|
||||
}
|
||||
|
||||
void LegoInputManager::RemoveKeyboard(SDL_KeyboardID p_keyboardID)
|
||||
{
|
||||
if (!m_keyboards.count(p_keyboardID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_keyboards.erase(p_keyboardID);
|
||||
}
|
||||
|
||||
void LegoInputManager::AddMouse(SDL_MouseID p_mouseID)
|
||||
{
|
||||
if (m_mice.count(p_mouseID)) {
|
||||
@ -656,7 +675,12 @@ MxBool LegoInputManager::HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touc
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
MxBool LegoInputManager::HandleRumbleEvent()
|
||||
MxBool LegoInputManager::HandleRumbleEvent(
|
||||
float p_strength,
|
||||
float p_lowFrequencyRumble,
|
||||
float p_highFrequencyRumble,
|
||||
MxU32 p_milliseconds
|
||||
)
|
||||
{
|
||||
static bool g_hapticsInitialized = false;
|
||||
|
||||
@ -668,6 +692,7 @@ MxBool LegoInputManager::HandleRumbleEvent()
|
||||
SDL_Haptic* haptic = nullptr;
|
||||
std::visit(
|
||||
overloaded{
|
||||
[](SDL_KeyboardID_v p_id) {},
|
||||
[&haptic, this](SDL_MouseID_v p_id) {
|
||||
if (m_mice.count((SDL_MouseID) p_id)) {
|
||||
haptic = m_mice[(SDL_MouseID) p_id].second;
|
||||
@ -688,11 +713,8 @@ MxBool LegoInputManager::HandleRumbleEvent()
|
||||
m_lastInputMethod
|
||||
);
|
||||
|
||||
const float strength = 0.5f;
|
||||
const Uint32 durationMs = 700;
|
||||
|
||||
if (haptic) {
|
||||
return SDL_PlayHapticRumble(haptic, strength, durationMs);
|
||||
return SDL_PlayHapticRumble(haptic, p_strength, p_milliseconds);
|
||||
}
|
||||
|
||||
// A joystick isn't necessarily a haptic device; try basic rumble instead
|
||||
@ -700,9 +722,9 @@ MxBool LegoInputManager::HandleRumbleEvent()
|
||||
if (m_joysticks.count((SDL_JoystickID) *joystick)) {
|
||||
return SDL_RumbleGamepad(
|
||||
m_joysticks[(SDL_JoystickID) *joystick].first,
|
||||
strength * 65535,
|
||||
strength * 65535,
|
||||
durationMs
|
||||
SDL_clamp(p_lowFrequencyRumble, 0, 1) * USHRT_MAX,
|
||||
SDL_clamp(p_highFrequencyRumble, 0, 1) * USHRT_MAX,
|
||||
p_milliseconds
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -752,6 +774,10 @@ void LegoInputManager::InitializeHaptics()
|
||||
void LegoInputManager::UpdateLastInputMethod(SDL_Event* p_event)
|
||||
{
|
||||
switch (p_event->type) {
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
m_lastInputMethod = SDL_KeyboardID_v{p_event->key.which};
|
||||
break;
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||
m_lastInputMethod = SDL_MouseID_v{p_event->button.which};
|
||||
|
@ -74,6 +74,7 @@ cksize: "Re-defined Windows name"
|
||||
fccType: "Re-defined Windows name"
|
||||
dwDataOffset: "Re-defined Windows name"
|
||||
fccType: "Re-defined Windows name"
|
||||
SDL_KeyboardID_v: "SDL-based name"
|
||||
SDL_MouseID_v: "SDL-based name"
|
||||
SDL_JoystickID_v: "SDL-based name"
|
||||
SDL_TouchID_v: "SDL-based name"
|
Loading…
x
Reference in New Issue
Block a user