16#include <wiiuse/wpad.h>
19#include "OgcInputDriver.h"
20#include "../Platform.h"
21#include "../InputController.h"
24#include "wii/WiiPlatform.h"
25#include "wii/wiidrc.h"
28static inline float clampf(
float v,
float lo,
float hi) {
29 return (v < lo) ? lo : (v > hi) ? hi : v;
36static uint32_t MapPADToGeneric(uint32_t pad_btns) {
37 uint32_t mask = INPUT_BTN_NONE;
38 if (pad_btns & PAD_BUTTON_A) mask |= INPUT_BTN_A;
39 if (pad_btns & PAD_BUTTON_B) mask |= INPUT_BTN_B;
40 if (pad_btns & PAD_BUTTON_X) mask |= INPUT_BTN_X;
41 if (pad_btns & PAD_BUTTON_Y) mask |= INPUT_BTN_Y;
42 if (pad_btns & PAD_BUTTON_UP) mask |= INPUT_BTN_UP;
43 if (pad_btns & PAD_BUTTON_DOWN) mask |= INPUT_BTN_DOWN;
44 if (pad_btns & PAD_BUTTON_LEFT) mask |= INPUT_BTN_LEFT;
45 if (pad_btns & PAD_BUTTON_RIGHT) mask |= INPUT_BTN_RIGHT;
46 if (pad_btns & PAD_BUTTON_START) mask |= INPUT_BTN_PLUS;
47 if (pad_btns & PAD_TRIGGER_L) mask |= INPUT_TRIGGER_L;
48 if (pad_btns & PAD_TRIGGER_R) mask |= INPUT_TRIGGER_R;
49 if (pad_btns & PAD_TRIGGER_Z) mask |= INPUT_TRIGGER_ZR;
54static uint32_t MapWiimoteToGeneric(uint32_t wpad_btns)
56 uint32_t mask = INPUT_BTN_NONE;
58 if (wpad_btns & WPAD_BUTTON_A) mask |= INPUT_BTN_A;
59 if (wpad_btns & WPAD_BUTTON_B) mask |= INPUT_BTN_B;
60 if (wpad_btns & WPAD_BUTTON_1) mask |= INPUT_BTN_1;
61 if (wpad_btns & WPAD_BUTTON_2) mask |= INPUT_BTN_2;
62 if (wpad_btns & WPAD_BUTTON_UP) mask |= INPUT_BTN_UP;
63 if (wpad_btns & WPAD_BUTTON_DOWN) mask |= INPUT_BTN_DOWN;
64 if (wpad_btns & WPAD_BUTTON_LEFT) mask |= INPUT_BTN_LEFT;
65 if (wpad_btns & WPAD_BUTTON_RIGHT) mask |= INPUT_BTN_RIGHT;
66 if (wpad_btns & WPAD_BUTTON_PLUS) mask |= INPUT_BTN_PLUS;
67 if (wpad_btns & WPAD_BUTTON_MINUS) mask |= INPUT_BTN_MINUS;
68 if (wpad_btns & WPAD_BUTTON_HOME) mask |= INPUT_BTN_HOME;
73static uint32_t MapNunchukToGeneric(uint32_t wpad_btns)
75 uint32_t mask = INPUT_BTN_NONE;
77 if (wpad_btns & WPAD_NUNCHUK_BUTTON_Z) mask |= INPUT_TRIGGER_ZL;
78 if (wpad_btns & WPAD_NUNCHUK_BUTTON_C) mask |= INPUT_TRIGGER_L;
83static uint32_t MapClassicToGeneric(uint32_t wpad_btns)
85 uint32_t mask = INPUT_BTN_NONE;
88 if (wpad_btns & WPAD_CLASSIC_BUTTON_A) mask |= INPUT_BTN_A;
89 if (wpad_btns & WPAD_CLASSIC_BUTTON_B) mask |= INPUT_BTN_B;
90 if (wpad_btns & WPAD_CLASSIC_BUTTON_X) mask |= INPUT_BTN_X;
91 if (wpad_btns & WPAD_CLASSIC_BUTTON_Y) mask |= INPUT_BTN_Y;
92 if (wpad_btns & WPAD_CLASSIC_BUTTON_UP) mask |= INPUT_BTN_UP;
93 if (wpad_btns & WPAD_CLASSIC_BUTTON_DOWN) mask |= INPUT_BTN_DOWN;
94 if (wpad_btns & WPAD_CLASSIC_BUTTON_LEFT) mask |= INPUT_BTN_LEFT;
95 if (wpad_btns & WPAD_CLASSIC_BUTTON_RIGHT) mask |= INPUT_BTN_RIGHT;
96 if (wpad_btns & WPAD_CLASSIC_BUTTON_PLUS) mask |= INPUT_BTN_PLUS;
97 if (wpad_btns & WPAD_CLASSIC_BUTTON_MINUS) mask |= INPUT_BTN_MINUS;
98 if (wpad_btns & WPAD_CLASSIC_BUTTON_HOME) mask |= INPUT_BTN_HOME;
99 if (wpad_btns & WPAD_CLASSIC_BUTTON_FULL_L) mask |= INPUT_TRIGGER_L;
100 if (wpad_btns & WPAD_CLASSIC_BUTTON_FULL_R) mask |= INPUT_TRIGGER_R;
101 if (wpad_btns & WPAD_CLASSIC_BUTTON_ZL) mask |= INPUT_TRIGGER_ZL;
102 if (wpad_btns & WPAD_CLASSIC_BUTTON_ZR) mask |= INPUT_TRIGGER_ZR;
107static uint32_t MapWiiUGamepadToGeneric(uint32_t drc_btns) {
108 uint32_t mask = INPUT_BTN_NONE;
109 if (drc_btns & WIIDRC_BUTTON_A) mask |= INPUT_BTN_A;
110 if (drc_btns & WIIDRC_BUTTON_B) mask |= INPUT_BTN_B;
111 if (drc_btns & WIIDRC_BUTTON_X) mask |= INPUT_BTN_X;
112 if (drc_btns & WIIDRC_BUTTON_Y) mask |= INPUT_BTN_Y;
113 if (drc_btns & WIIDRC_BUTTON_UP) mask |= INPUT_BTN_UP;
114 if (drc_btns & WIIDRC_BUTTON_DOWN) mask |= INPUT_BTN_DOWN;
115 if (drc_btns & WIIDRC_BUTTON_LEFT) mask |= INPUT_BTN_LEFT;
116 if (drc_btns & WIIDRC_BUTTON_RIGHT) mask |= INPUT_BTN_RIGHT;
117 if (drc_btns & WIIDRC_BUTTON_PLUS) mask |= INPUT_BTN_PLUS;
118 if (drc_btns & WIIDRC_BUTTON_MINUS) mask |= INPUT_BTN_MINUS;
119 if (drc_btns & WIIDRC_BUTTON_HOME) mask |= INPUT_BTN_HOME;
120 if (drc_btns & WIIDRC_BUTTON_L) mask |= INPUT_TRIGGER_L;
121 if (drc_btns & WIIDRC_BUTTON_R) mask |= INPUT_TRIGGER_R;
122 if (drc_btns & WIIDRC_BUTTON_ZL) mask |= INPUT_TRIGGER_ZL;
123 if (drc_btns & WIIDRC_BUTTON_ZR) mask |= INPUT_TRIGGER_ZR;
130static float NormalizeWPADAnalog(
int pos,
int min,
int max,
int center) {
131 if (min == max)
return 0.0f;
134 if ((min >= center) || (max <= center)) {
135 min = 0; max = 64; center = 32;
137 int offset = pos - center;
139 return clampf((
float)offset / (
float)(max - center), 0.0f, 1.0f);
141 return clampf((
float)offset / (
float)(center - min), -1.0f, 0.0f);
146OgcInputDriver::OgcInputDriver() {
147 for (
int i = 0; i < 4; i++) {
148 rumbleRequest[i] = continuousRumble[i] =
false;
149 menuRumbleFrames[i] = continuousRumbleCount[i] = silenceFrames[i] = menuRumbleGapFrames[i] = 0;
153OgcInputDriver::~OgcInputDriver() {
158static void WiimotePowerButtonCallback(s32) { NotifyWiiShutdownRequested(); }
165 SYS_SetPowerCallback(NotifyWiiShutdownRequested);
169 WPAD_SetDataFormat(WPAD_CHAN_ALL, WPAD_FMT_BTNS_ACC_IR);
170 WPAD_SetVRes(WPAD_CHAN_ALL, platform->getVideo()->getScreenWidth(), platform->getVideo()->getScreenHeight());
171 WPAD_SetPowerButtonCallback(WiimotePowerButtonCallback);
174 InitUserInputControllers();
178 for (
int i = 0; i < 4; i++) {
182 PAD_ControlMotor(i, PAD_MOTOR_STOP);
183 rumbleRequest[i] = continuousRumble[i] =
false;
184 menuRumbleFrames[i] = continuousRumbleCount[i] = silenceFrames[i] = menuRumbleGapFrames[i] = 0;
189 if (channel >= 0 && channel < 4) {
190 rumbleRequest[channel] = rumble;
195 if (channel >= 0 && channel < 4) continuousRumble[channel] = continuous;
202 bool systemRumbleAllowed = (CONF_GetPadMotorMode() != 0);
204 bool systemRumbleAllowed =
true;
207 u32 activeGamecubePads = PAD_ScanPads();
210 for(
int i = 3; i >= 0; i--) {
213 bool gamecubeActive = (activeGamecubePads & (1 << i)) != 0;
217 padData.
hw_buttons_d[INPUT_HW_GAMECUBE] = MapPADToGeneric(PAD_ButtonsDown(i));
218 padData.
hw_buttons_h[INPUT_HW_GAMECUBE] = MapPADToGeneric(PAD_ButtonsHeld(i));
219 padData.
hw_buttons_r[INPUT_HW_GAMECUBE] = MapPADToGeneric(PAD_ButtonsUp(i));
220 padData.
hw_stickX[INPUT_HW_GAMECUBE] = clampf((
float)PAD_StickX(i) / 128.0f, -1.0f, 1.0f);
221 padData.
hw_stickY[INPUT_HW_GAMECUBE] = clampf((
float)PAD_StickY(i) / 128.0f, -1.0f, 1.0f);
222 padData.
hw_substickX[INPUT_HW_GAMECUBE] = clampf((
float)PAD_SubStickX(i) / 128.0f, -1.0f, 1.0f);
223 padData.
hw_substickY[INPUT_HW_GAMECUBE] = clampf((
float)PAD_SubStickY(i) / 128.0f, -1.0f, 1.0f);
224 padData.
hw_triggerL[INPUT_HW_GAMECUBE] = clampf((
float)PAD_TriggerL(i) / 255.0f, 0.0f, 1.0f);
225 padData.
hw_triggerR[INPUT_HW_GAMECUBE] = clampf((
float)PAD_TriggerR(i) / 255.0f, 0.0f, 1.0f);
230 uint32_t exp_type = WPAD_EXP_NONE;
232 if (WPAD_Probe(i, &exp_type) == WPAD_ERR_NONE) {
233 WPADData* wpad = WPAD_Data(i);
239 padData.
hw_gforceX[INPUT_HW_WIIMOTE] = wpad->gforce.x;
240 padData.
hw_gforceY[INPUT_HW_WIIMOTE] = wpad->gforce.y;
241 padData.
hw_gforceZ[INPUT_HW_WIIMOTE] = wpad->gforce.z;
242 padData.
hw_pitch[INPUT_HW_WIIMOTE] = wpad->orient.pitch;
243 padData.
hw_roll[INPUT_HW_WIIMOTE] = wpad->orient.roll;
244 padData.
hw_yaw[INPUT_HW_WIIMOTE] = wpad->orient.yaw;
246 if (exp_type == WPAD_EXP_NONE) {
247 padData.
hw_buttons_d[INPUT_HW_WIIMOTE] = MapWiimoteToGeneric(wpad->btns_d);
248 padData.
hw_buttons_h[INPUT_HW_WIIMOTE] = MapWiimoteToGeneric(wpad->btns_h);
249 padData.
hw_buttons_r[INPUT_HW_WIIMOTE] = MapWiimoteToGeneric(wpad->btns_u);
251 if (wpad->ir.valid) {
261 else if (exp_type == WPAD_EXP_NUNCHUK) {
262 padData.
hw_buttons_d[INPUT_HW_WIIMOTE] = MapWiimoteToGeneric(wpad->btns_d);
263 padData.
hw_buttons_h[INPUT_HW_WIIMOTE] = MapWiimoteToGeneric(wpad->btns_h);
264 padData.
hw_buttons_r[INPUT_HW_WIIMOTE] = MapWiimoteToGeneric(wpad->btns_u);
267 padData.
hw_buttons_d[INPUT_HW_NUNCHUK] = MapNunchukToGeneric(wpad->btns_d);
268 padData.
hw_buttons_h[INPUT_HW_NUNCHUK] = MapNunchukToGeneric(wpad->btns_h);
269 padData.
hw_buttons_r[INPUT_HW_NUNCHUK] = MapNunchukToGeneric(wpad->btns_u);
270 joystick_t* js = &wpad->exp.nunchuk.js;
271 padData.
hw_stickX[INPUT_HW_NUNCHUK] = NormalizeWPADAnalog(js->pos.x, js->min.x, js->max.x, js->center.x);
272 padData.
hw_stickY[INPUT_HW_NUNCHUK] = NormalizeWPADAnalog(js->pos.y, js->min.y, js->max.y, js->center.y);
274 padData.
hw_gforceX[INPUT_HW_NUNCHUK] = wpad->exp.nunchuk.gforce.x;
275 padData.
hw_gforceY[INPUT_HW_NUNCHUK] = wpad->exp.nunchuk.gforce.y;
276 padData.
hw_gforceZ[INPUT_HW_NUNCHUK] = wpad->exp.nunchuk.gforce.z;
277 padData.
hw_pitch[INPUT_HW_NUNCHUK] = wpad->exp.nunchuk.orient.pitch;
278 padData.
hw_roll[INPUT_HW_NUNCHUK] = wpad->exp.nunchuk.orient.roll;
279 padData.
hw_yaw[INPUT_HW_NUNCHUK] = wpad->exp.nunchuk.orient.yaw;
282 if (wpad->ir.valid) {
290 controller[i]->setSideways(
false);
292 else if (exp_type == WPAD_EXP_CLASSIC) {
293 bool isWUPC = (wpad->exp.classic.type == 2);
294 int hw = isWUPC ? INPUT_HW_WUPC : INPUT_HW_CLASSIC;
297 padData.
hw_buttons_d[hw] = MapClassicToGeneric(wpad->btns_d);
298 padData.
hw_buttons_h[hw] = MapClassicToGeneric(wpad->btns_h);
299 padData.
hw_buttons_r[hw] = MapClassicToGeneric(wpad->btns_u);
301 joystick_t* ljs = &wpad->exp.classic.ljs;
302 joystick_t* rjs = &wpad->exp.classic.rjs;
303 padData.
hw_stickX[hw] = NormalizeWPADAnalog(ljs->pos.x, ljs->min.x, ljs->max.x, ljs->center.x);
304 padData.
hw_stickY[hw] = NormalizeWPADAnalog(ljs->pos.y, ljs->min.y, ljs->max.y, ljs->center.y);
305 padData.
hw_substickX[hw] = NormalizeWPADAnalog(rjs->pos.x, rjs->min.x, rjs->max.x, rjs->center.x);
306 padData.
hw_substickY[hw] = NormalizeWPADAnalog(rjs->pos.y, rjs->min.y, rjs->max.y, rjs->center.y);
307 padData.
hw_triggerL[hw] = clampf(wpad->exp.classic.l_shoulder, 0.0f, 1.0f);
308 padData.
hw_triggerR[hw] = clampf(wpad->exp.classic.r_shoulder, 0.0f, 1.0f);
309 controller[i]->setSideways(
false);
312 controller[i]->setSideways(
false);
317 if(i == 0 && WiiDRC_Inited() && WiiDRC_Connected()) {
319 padData.
hw_buttons_d[INPUT_HW_DRC] = MapWiiUGamepadToGeneric(WiiDRC_ButtonsDown());
320 padData.
hw_buttons_h[INPUT_HW_DRC] = MapWiiUGamepadToGeneric(WiiDRC_ButtonsHeld());
321 padData.
hw_buttons_r[INPUT_HW_DRC] = MapWiiUGamepadToGeneric(WiiDRC_ButtonsUp());
322 padData.
hw_stickX[INPUT_HW_DRC] = clampf((
float)WiiDRC_lStickX() / 128.0f, -1.0f, 1.0f);
323 padData.
hw_stickY[INPUT_HW_DRC] = clampf((
float)WiiDRC_lStickY() / 128.0f, -1.0f, 1.0f);
324 padData.
hw_substickX[INPUT_HW_DRC] = clampf((
float)WiiDRC_rStickX() / 128.0f, -1.0f, 1.0f);
325 padData.
hw_substickY[INPUT_HW_DRC] = clampf((
float)WiiDRC_rStickY() / 128.0f, -1.0f, 1.0f);
330 for (uint32_t hw = 0; hw < INPUT_HW_MAX; hw++) {
347 if (std::abs(padData.
hw_yaw[hw]) > std::abs(padData.
yaw)) padData.
yaw = padData.
hw_yaw[hw];
351 controller[i]->update(padData, platform->getVideo()->getDeltaTime());
354 static constexpr int kMenuRumbleOnFrames = 2;
355 static constexpr int kMenuRumbleGapFrames = 6;
357 if (rumbleRequest[i]) {
358 rumbleRequest[i] =
false;
359 if (menuRumbleFrames[i] == 0 && menuRumbleGapFrames[i] == 0) {
360 menuRumbleFrames[i] = kMenuRumbleOnFrames;
364 bool menuWantRumble = menuRumbleFrames[i] > 0;
366 if (menuRumbleFrames[i] > 0) {
367 menuRumbleFrames[i]--;
368 if (menuRumbleFrames[i] == 0) menuRumbleGapFrames[i] = kMenuRumbleGapFrames;
369 }
else if (menuRumbleGapFrames[i] > 0) {
370 menuRumbleGapFrames[i]--;
373 bool wantRumble = menuWantRumble || continuousRumble[i];
374 bool motorOn =
false;
378 if (silenceFrames[i] > 0) {
380 continuousRumbleCount[i] = 0;
382 if (wantRumble && allowRumble) {
383 continuousRumbleCount[i]++;
384 if (continuousRumbleCount[i] > 70) {
385 silenceFrames[i] = 5;
386 continuousRumbleCount[i] = 0;
391 continuousRumbleCount[i] = 0;
396 WPAD_Rumble(i, motorOn ? 1 : 0);
399 if (gamecubeActive) {
400 PAD_ControlMotor(i, motorOn ? PAD_MOTOR_RUMBLE : PAD_MOTOR_STOP);