@ -273,8 +273,8 @@ Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} {
{ 204 , & Hid : : PermitVibration , " PermitVibration " } ,
{ 205 , & Hid : : IsVibrationPermitted , " IsVibrationPermitted " } ,
{ 206 , & Hid : : SendVibrationValues , " SendVibrationValues " } ,
{ 207 , nullptr , " SendVibrationGcErmCommand " } ,
{ 208 , nullptr , " GetActualVibrationGcErmCommand " } ,
{ 207 , & Hid : : SendVibrationGcErmCommand , " SendVibrationGcErmCommand " } ,
{ 208 , & Hid : : GetActualVibrationGcErmCommand , " GetActualVibrationGcErmCommand " } ,
{ 209 , & Hid : : BeginPermitVibrationSession , " BeginPermitVibrationSession " } ,
{ 210 , & Hid : : EndPermitVibrationSession , " EndPermitVibrationSession " } ,
{ 211 , & Hid : : IsVibrationDeviceMounted , " IsVibrationDeviceMounted " } ,
@ -1093,7 +1093,22 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
VibrationDeviceInfo vibration_device_info ;
vibration_device_info . type = VibrationDeviceType : : LinearResonantActuator ;
switch ( vibration_device_handle . npad_type ) {
case Controller_NPad : : NpadType : : ProController :
case Controller_NPad : : NpadType : : Handheld :
case Controller_NPad : : NpadType : : JoyconDual :
case Controller_NPad : : NpadType : : JoyconLeft :
case Controller_NPad : : NpadType : : JoyconRight :
default :
vibration_device_info . type = VibrationDeviceType : : LinearResonantActuator ;
break ;
case Controller_NPad : : NpadType : : GameCube :
vibration_device_info . type = VibrationDeviceType : : GcErm ;
break ;
case Controller_NPad : : NpadType : : Pokeball :
vibration_device_info . type = VibrationDeviceType : : Unknown ;
break ;
}
switch ( vibration_device_handle . device_index ) {
case Controller_NPad : : DeviceIndex : : Left :
@ -1215,6 +1230,108 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
rb . Push ( RESULT_SUCCESS ) ;
}
void Hid : : SendVibrationGcErmCommand ( Kernel : : HLERequestContext & ctx ) {
IPC : : RequestParser rp { ctx } ;
struct Parameters {
Controller_NPad : : DeviceHandle vibration_device_handle ;
u64 applet_resource_user_id ;
VibrationGcErmCommand gc_erm_command ;
} ;
static_assert ( sizeof ( Parameters ) = = 0x18 , " Parameters has incorrect size. " ) ;
const auto parameters { rp . PopRaw < Parameters > ( ) } ;
/**
* Note : This uses yuzu - specific behavior such that the StopHard command produces
* vibrations where freq_low = = 0.0f and freq_high = = 0.0f , as defined below ,
* in order to differentiate between Stop and StopHard commands .
* This is done to reuse the controller vibration functions made for regular controllers .
*/
const auto vibration_value = [ parameters ] {
switch ( parameters . gc_erm_command ) {
case VibrationGcErmCommand : : Stop :
return Controller_NPad : : VibrationValue {
. amp_low = 0.0f ,
. freq_low = 160.0f ,
. amp_high = 0.0f ,
. freq_high = 320.0f ,
} ;
case VibrationGcErmCommand : : Start :
return Controller_NPad : : VibrationValue {
. amp_low = 1.0f ,
. freq_low = 160.0f ,
. amp_high = 1.0f ,
. freq_high = 320.0f ,
} ;
case VibrationGcErmCommand : : StopHard :
return Controller_NPad : : VibrationValue {
. amp_low = 0.0f ,
. freq_low = 0.0f ,
. amp_high = 0.0f ,
. freq_high = 0.0f ,
} ;
default :
return Controller_NPad : : DEFAULT_VIBRATION_VALUE ;
}
} ( ) ;
applet_resource - > GetController < Controller_NPad > ( HidController : : NPad )
. VibrateController ( parameters . vibration_device_handle , vibration_value ) ;
LOG_DEBUG ( Service_HID ,
" called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, "
" gc_erm_command={} " ,
parameters . vibration_device_handle . npad_type ,
parameters . vibration_device_handle . npad_id ,
parameters . vibration_device_handle . device_index , parameters . applet_resource_user_id ,
parameters . gc_erm_command ) ;
IPC : : ResponseBuilder rb { ctx , 2 } ;
rb . Push ( RESULT_SUCCESS ) ;
}
void Hid : : GetActualVibrationGcErmCommand ( Kernel : : HLERequestContext & ctx ) {
IPC : : RequestParser rp { ctx } ;
struct Parameters {
Controller_NPad : : DeviceHandle vibration_device_handle ;
INSERT_PADDING_WORDS_NOINIT ( 1 ) ;
u64 applet_resource_user_id ;
} ;
const auto parameters { rp . PopRaw < Parameters > ( ) } ;
const auto last_vibration = applet_resource - > GetController < Controller_NPad > ( HidController : : NPad )
. GetLastVibration ( parameters . vibration_device_handle ) ;
const auto gc_erm_command = [ last_vibration ] {
if ( last_vibration . amp_low ! = 0.0f | | last_vibration . amp_high ! = 0.0f ) {
return VibrationGcErmCommand : : Start ;
}
/**
* Note : This uses yuzu - specific behavior such that the StopHard command produces
* vibrations where freq_low = = 0.0f and freq_high = = 0.0f , as defined in the HID function
* SendVibrationGcErmCommand , in order to differentiate between Stop and StopHard commands .
* This is done to reuse the controller vibration functions made for regular controllers .
*/
if ( last_vibration . freq_low = = 0.0f & & last_vibration . freq_high = = 0.0f ) {
return VibrationGcErmCommand : : StopHard ;
}
return VibrationGcErmCommand : : Stop ;
} ( ) ;
LOG_DEBUG ( Service_HID ,
" called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={} " ,
parameters . vibration_device_handle . npad_type ,
parameters . vibration_device_handle . npad_id ,
parameters . vibration_device_handle . device_index , parameters . applet_resource_user_id ) ;
IPC : : ResponseBuilder rb { ctx , 4 } ;
rb . Push ( RESULT_SUCCESS ) ;
rb . PushEnum ( gc_erm_command ) ;
}
void Hid : : BeginPermitVibrationSession ( Kernel : : HLERequestContext & ctx ) {
IPC : : RequestParser rp { ctx } ;
const auto applet_resource_user_id { rp . Pop < u64 > ( ) } ;