Rumble using MacBook's Taptic Engine (take 2)
This commit is contained in:
parent
bc1c70bd1a
commit
baab70c509
|
@ -1394,13 +1394,15 @@ if(NOT LIBRETRO)
|
||||||
find_library(AUDIO_TOOLBOX_LIBRARY AudioToolbox)
|
find_library(AUDIO_TOOLBOX_LIBRARY AudioToolbox)
|
||||||
find_library(OPENGL_LIBRARY OpenGL)
|
find_library(OPENGL_LIBRARY OpenGL)
|
||||||
find_library(IOSURFACE_LIBRARY IOSurface)
|
find_library(IOSURFACE_LIBRARY IOSurface)
|
||||||
|
find_library(MULTITOUCH_SUPPORT_LIBRARY MultitouchSupport /System/Library/PrivateFrameworks)
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||||
${AUDIO_UNIT_LIBRARY}
|
${AUDIO_UNIT_LIBRARY}
|
||||||
${FOUNDATION_LIBRARY}
|
${FOUNDATION_LIBRARY}
|
||||||
${AUDIO_TOOLBOX_LIBRARY}
|
${AUDIO_TOOLBOX_LIBRARY}
|
||||||
${OPENGL_LIBRARY}
|
${OPENGL_LIBRARY}
|
||||||
${IOSURFACE_LIBRARY})
|
${IOSURFACE_LIBRARY}
|
||||||
|
${MULTITOUCH_SUPPORT_LIBRARY})
|
||||||
|
|
||||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy "$ENV{VULKAN_SDK}/lib/libMoltenVK.dylib"
|
COMMAND ${CMAKE_COMMAND} -E copy "$ENV{VULKAN_SDK}/lib/libMoltenVK.dylib"
|
||||||
|
|
|
@ -2,6 +2,25 @@
|
||||||
#include "input/keyboard_device.h"
|
#include "input/keyboard_device.h"
|
||||||
#include "sdl.h"
|
#include "sdl.h"
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
#include <IOKit/IOTypes.h>
|
||||||
|
#include <stack>
|
||||||
|
// Rumbling Taptic Engine by Private MultitouchSupport.framework
|
||||||
|
extern "C" {
|
||||||
|
typedef void *MTDeviceRef;
|
||||||
|
bool MTDeviceIsAvailable(void);
|
||||||
|
MTDeviceRef MTDeviceCreateDefault(void);
|
||||||
|
OSStatus MTDeviceGetDeviceID(MTDeviceRef, uint64_t*) __attribute__ ((weak_import));
|
||||||
|
CFTypeRef MTActuatorCreateFromDeviceID(UInt64 deviceID);
|
||||||
|
IOReturn MTActuatorOpen(CFTypeRef actuatorRef);
|
||||||
|
IOReturn MTActuatorClose(CFTypeRef actuatorRef);
|
||||||
|
IOReturn MTActuatorActuate(CFTypeRef actuatorRef, SInt32 actuationID, UInt32 unknown1, Float32 unknown2, Float32 unknown3);
|
||||||
|
bool MTActuatorIsOpen(CFTypeRef actuatorRef);
|
||||||
|
enum ActuatePattern { minimal = 3, weak = 5, medium = 4, strong = 6 };
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
class SDLKeyboardDevice : public KeyboardDeviceTemplate<SDL_Scancode>
|
class SDLKeyboardDevice : public KeyboardDeviceTemplate<SDL_Scancode>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -35,6 +54,12 @@ public:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
input_mapper = getDefaultMapping();
|
input_mapper = getDefaultMapping();
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
uint64_t deviceID;
|
||||||
|
if ( MTDeviceIsAvailable() && MTDeviceGetDeviceID(MTDeviceCreateDefault(), &deviceID) == 0 && (vib_device = MTActuatorCreateFromDeviceID(deviceID)) != NULL && MTActuatorOpen(vib_device) == kIOReturnSuccess)
|
||||||
|
rumbleEnabled = true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *get_button_name(u32 code) override
|
const char *get_button_name(u32 code) override
|
||||||
|
@ -45,6 +70,59 @@ public:
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
void rumble(float power, float inclination, u32 duration_ms) override
|
||||||
|
{
|
||||||
|
if (rumbleEnabled)
|
||||||
|
{
|
||||||
|
vib_stop_time = os_GetSeconds() + duration_ms / 1000.0;
|
||||||
|
|
||||||
|
__block int pattern;
|
||||||
|
if (power >= 0.75)
|
||||||
|
pattern = ActuatePattern::strong;
|
||||||
|
else if (power >= 0.5)
|
||||||
|
pattern = ActuatePattern::medium;
|
||||||
|
else if (power >= 0.25)
|
||||||
|
pattern = ActuatePattern::weak;
|
||||||
|
else if (power > 0)
|
||||||
|
pattern = ActuatePattern::minimal;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while(!vib_timer_stack.empty())
|
||||||
|
{
|
||||||
|
dispatch_source_cancel(vib_timer_stack.top());
|
||||||
|
vib_timer_stack.pop();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Since the Actuator API does not support duration
|
||||||
|
// using a interval timer with `10ms * rumblePower percentage` to fake it
|
||||||
|
__block dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
|
||||||
|
vib_timer_stack.push(_timer);
|
||||||
|
dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, 10 * NSEC_PER_MSEC * rumblePower / 100.f, 0);
|
||||||
|
|
||||||
|
dispatch_source_set_event_handler(_timer, ^{
|
||||||
|
if ( vib_stop_time - os_GetSeconds() < 0 )
|
||||||
|
{
|
||||||
|
dispatch_source_cancel(_timer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MTActuatorActuate(vib_device, pattern, 0, 0.0, 0.0);
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch_resume(_timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~SDLKeyboardDevice() {
|
||||||
|
if (rumbleEnabled)
|
||||||
|
{
|
||||||
|
MTActuatorClose(vib_device);
|
||||||
|
CFRelease(vib_device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
u8 convert_keycode(SDL_Scancode scancode) override
|
u8 convert_keycode(SDL_Scancode scancode) override
|
||||||
{
|
{
|
||||||
|
@ -53,4 +131,11 @@ protected:
|
||||||
else
|
else
|
||||||
return (u8)scancode;
|
return (u8)scancode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
private:
|
||||||
|
std::stack<dispatch_source_t> vib_timer_stack;
|
||||||
|
CFTypeRef vib_device = NULL;
|
||||||
|
double vib_stop_time = 0;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue