| File: | Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp |
| Location: | line 555, column 32 |
| Description: | The left operand of '<' is a garbage value |
| 1 | // Copyright 2013 Dolphin Emulator Project | |||
| 2 | // Licensed under GPLv2 | |||
| 3 | // Refer to the license.txt file included. | |||
| 4 | ||||
| 5 | #include <cmath> | |||
| 6 | ||||
| 7 | #include "Attachment/Classic.h" | |||
| 8 | #include "Attachment/Nunchuk.h" | |||
| 9 | #include "Attachment/Guitar.h" | |||
| 10 | #include "Attachment/Drums.h" | |||
| 11 | #include "Attachment/Turntable.h" | |||
| 12 | ||||
| 13 | #include "WiimoteEmu.h" | |||
| 14 | #include "WiimoteHid.h" | |||
| 15 | ||||
| 16 | #include "../WiimoteReal/WiimoteReal.h" | |||
| 17 | ||||
| 18 | #include "Timer.h" | |||
| 19 | #include "Common.h" | |||
| 20 | #include "../../Host.h" | |||
| 21 | #include "../../ConfigManager.h" | |||
| 22 | ||||
| 23 | #include "UDPTLayer.h" | |||
| 24 | ||||
| 25 | inline double round(double x) { return (x-floor(x))>0.5 ? ceil(x) : floor(x); } //because damn MSVSC doesen't comply to C99 | |||
| 26 | ||||
| 27 | #include "MatrixMath.h" | |||
| 28 | ||||
| 29 | #include "../../Movie.h" | |||
| 30 | ||||
| 31 | namespace | |||
| 32 | { | |||
| 33 | // :) | |||
| 34 | auto const TAU = 6.28318530717958647692; | |||
| 35 | auto const PI = TAU / 2.0; | |||
| 36 | } | |||
| 37 | ||||
| 38 | namespace WiimoteEmu | |||
| 39 | { | |||
| 40 | ||||
| 41 | /* An example of a factory default first bytes of the Eeprom memory. There are differences between | |||
| 42 | different Wiimotes, my Wiimote had different neutral values for the accelerometer. */ | |||
| 43 | static const u8 eeprom_data_0[] = { | |||
| 44 | // IR, maybe more | |||
| 45 | // assuming last 2 bytes are checksum | |||
| 46 | 0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30, 0xA7, /*0x74, 0xD3,*/ 0x00, 0x00, // messing up the checksum on purpose | |||
| 47 | 0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30, 0xA7, /*0x74, 0xD3,*/ 0x00, 0x00, | |||
| 48 | // Accelerometer | |||
| 49 | // 0g x,y,z, 1g x,y,z, idk, last byte is a checksum | |||
| 50 | 0x80, 0x80, 0x80, 0x00, 0x9A, 0x9A, 0x9A, 0x00, 0x40, 0xE3, | |||
| 51 | 0x80, 0x80, 0x80, 0x00, 0x9A, 0x9A, 0x9A, 0x00, 0x40, 0xE3, | |||
| 52 | }; | |||
| 53 | ||||
| 54 | static const u8 motion_plus_id[] = { 0x00, 0x00, 0xA6, 0x20, 0x00, 0x05 }; | |||
| 55 | ||||
| 56 | static const u8 eeprom_data_16D0[] = { | |||
| 57 | 0x00, 0x00, 0x00, 0xFF, 0x11, 0xEE, 0x00, 0x00, | |||
| 58 | 0x33, 0xCC, 0x44, 0xBB, 0x00, 0x00, 0x66, 0x99, | |||
| 59 | 0x77, 0x88, 0x00, 0x00, 0x2B, 0x01, 0xE8, 0x13 | |||
| 60 | }; | |||
| 61 | ||||
| 62 | const ReportFeatures reporting_mode_features[] = | |||
| 63 | { | |||
| 64 | //0x30: Core Buttons | |||
| 65 | { 2, 0, 0, 0, 4 }, | |||
| 66 | //0x31: Core Buttons and Accelerometer | |||
| 67 | { 2, 4, 0, 0, 7 }, | |||
| 68 | //0x32: Core Buttons with 8 Extension bytes | |||
| 69 | { 2, 0, 0, 4, 12 }, | |||
| 70 | //0x33: Core Buttons and Accelerometer with 12 IR bytes | |||
| 71 | { 2, 4, 7, 0, 19 }, | |||
| 72 | //0x34: Core Buttons with 19 Extension bytes | |||
| 73 | { 2, 0, 0, 4, 23 }, | |||
| 74 | //0x35: Core Buttons and Accelerometer with 16 Extension Bytes | |||
| 75 | { 2, 4, 0, 7, 23 }, | |||
| 76 | //0x36: Core Buttons with 10 IR bytes and 9 Extension Bytes | |||
| 77 | { 2, 0, 4, 14, 23 }, | |||
| 78 | //0x37: Core Buttons and Accelerometer with 10 IR bytes and 6 Extension Bytes | |||
| 79 | { 2, 4, 7, 17, 23 }, | |||
| 80 | ||||
| 81 | // UNSUPPORTED: | |||
| 82 | //0x3d: 21 Extension Bytes | |||
| 83 | { 0, 0, 0, 2, 23 }, | |||
| 84 | //0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes | |||
| 85 | { 0, 0, 0, 0, 23 }, | |||
| 86 | }; | |||
| 87 | ||||
| 88 | void EmulateShake(AccelData* const accel | |||
| 89 | , accel_cal* const calib | |||
| 90 | , ControllerEmu::Buttons* const buttons_group | |||
| 91 | , u8* const shake_step ) | |||
| 92 | { | |||
| 93 | // frame count of one up/down shake | |||
| 94 | // < 9 no shake detection in "Wario Land: Shake It" | |||
| 95 | auto const shake_step_max = 15; | |||
| 96 | ||||
| 97 | // peak G-force | |||
| 98 | double shake_intensity; | |||
| 99 | ||||
| 100 | // shake is a bitfield of X,Y,Z shake button states | |||
| 101 | static const unsigned int btns[] = { 0x01, 0x02, 0x04 }; | |||
| 102 | unsigned int shake = 0; | |||
| 103 | buttons_group->GetState( &shake, btns ); | |||
| 104 | ||||
| 105 | for (int i = 0; i != 3; ++i) | |||
| 106 | { | |||
| 107 | if (shake & (1 << i)) | |||
| 108 | { | |||
| 109 | double zero = double((&(calib->zero_g.x))[i]); | |||
| 110 | double one = double((&(calib->one_g.x))[i]); | |||
| 111 | shake_intensity = max(zero / (one - zero), (255.f - zero) / (one - zero)); | |||
| 112 | (&(accel->x))[i] = std::sin(TAU * shake_step[i] / shake_step_max) * shake_intensity; | |||
| 113 | shake_step[i] = (shake_step[i] + 1) % shake_step_max; | |||
| 114 | } | |||
| 115 | else | |||
| 116 | shake_step[i] = 0; | |||
| 117 | } | |||
| 118 | } | |||
| 119 | ||||
| 120 | void EmulateTilt(AccelData* const accel | |||
| 121 | , ControllerEmu::Tilt* const tilt_group | |||
| 122 | , const bool focus, const bool sideways, const bool upright) | |||
| 123 | { | |||
| 124 | float roll, pitch; | |||
| 125 | // 180 degrees | |||
| 126 | tilt_group->GetState(&roll, &pitch, 0, focus ? PI : 0); | |||
| 127 | ||||
| 128 | unsigned int ud = 0, lr = 0, fb = 0; | |||
| 129 | ||||
| 130 | // some notes that no one will understand but me :p | |||
| 131 | // left, forward, up | |||
| 132 | // lr/ left == negative for all orientations | |||
| 133 | // ud/ up == negative for upright longways | |||
| 134 | // fb/ forward == positive for (sideways flat) | |||
| 135 | ||||
| 136 | // determine which axis is which direction | |||
| 137 | ud = upright ? (sideways ? 0 : 1) : 2; | |||
| 138 | lr = sideways; | |||
| 139 | fb = upright ? 2 : (sideways ? 0 : 1); | |||
| 140 | ||||
| 141 | int sgn[3]={-1,1,1}; //sign fix | |||
| 142 | ||||
| 143 | if (sideways && !upright) | |||
| 144 | sgn[fb] *= -1; | |||
| 145 | if (!sideways && upright) | |||
| 146 | sgn[ud] *= -1; | |||
| 147 | ||||
| 148 | (&accel->x)[ud] = (sin((PI / 2) - std::max(fabsf(roll), fabsf(pitch))))*sgn[ud]; | |||
| 149 | (&accel->x)[lr] = -sin(roll)*sgn[lr]; | |||
| 150 | (&accel->x)[fb] = sin(pitch)*sgn[fb]; | |||
| 151 | } | |||
| 152 | ||||
| 153 | #define SWING_INTENSITY2.5f 2.5f//-uncalibrated(aprox) 0x40-calibrated | |||
| 154 | ||||
| 155 | void EmulateSwing(AccelData* const accel | |||
| 156 | , ControllerEmu::Force* const swing_group | |||
| 157 | , const bool sideways, const bool upright) | |||
| 158 | { | |||
| 159 | float swing[3]; | |||
| 160 | swing_group->GetState(swing, 0, SWING_INTENSITY2.5f); | |||
| 161 | ||||
| 162 | s8 g_dir[3] = {-1, -1, -1}; | |||
| 163 | u8 axis_map[3]; | |||
| 164 | ||||
| 165 | // determine which axis is which direction | |||
| 166 | axis_map[0] = upright ? (sideways ? 0 : 1) : 2; // up/down | |||
| 167 | axis_map[1] = sideways; // left|right | |||
| 168 | axis_map[2] = upright ? 2 : (sideways ? 0 : 1); // forward/backward | |||
| 169 | ||||
| 170 | // some orientations have up as positive, some as negative | |||
| 171 | // same with forward | |||
| 172 | if (sideways && !upright) | |||
| 173 | g_dir[axis_map[2]] *= -1; | |||
| 174 | if (!sideways && upright) | |||
| 175 | g_dir[axis_map[0]] *= -1; | |||
| 176 | ||||
| 177 | for (unsigned int i=0; i<3; ++i) | |||
| 178 | (&accel->x)[axis_map[i]] += swing[i] * g_dir[i]; | |||
| 179 | } | |||
| 180 | ||||
| 181 | const u16 button_bitmasks[] = | |||
| 182 | { | |||
| 183 | Wiimote::BUTTON_A, | |||
| 184 | Wiimote::BUTTON_B, | |||
| 185 | Wiimote::BUTTON_ONE, | |||
| 186 | Wiimote::BUTTON_TWO, | |||
| 187 | Wiimote::BUTTON_MINUS, | |||
| 188 | Wiimote::BUTTON_PLUS, | |||
| 189 | Wiimote::BUTTON_HOME | |||
| 190 | }; | |||
| 191 | ||||
| 192 | const u16 dpad_bitmasks[] = | |||
| 193 | { | |||
| 194 | Wiimote::PAD_UP, Wiimote::PAD_DOWN, Wiimote::PAD_LEFT, Wiimote::PAD_RIGHT | |||
| 195 | }; | |||
| 196 | const u16 dpad_sideways_bitmasks[] = | |||
| 197 | { | |||
| 198 | Wiimote::PAD_RIGHT, Wiimote::PAD_LEFT, Wiimote::PAD_UP, Wiimote::PAD_DOWN | |||
| 199 | }; | |||
| 200 | ||||
| 201 | const char* const named_buttons[] = | |||
| 202 | { | |||
| 203 | "A", "B", "1", "2", "-", "+", "Home", | |||
| 204 | }; | |||
| 205 | ||||
| 206 | void Wiimote::Reset() | |||
| 207 | { | |||
| 208 | m_reporting_mode = WM_REPORT_CORE0x30; | |||
| 209 | // i think these two are good | |||
| 210 | m_reporting_channel = 0; | |||
| 211 | m_reporting_auto = false; | |||
| 212 | ||||
| 213 | m_rumble_on = false; | |||
| 214 | m_speaker_mute = false; | |||
| 215 | m_motion_plus_present = false; | |||
| 216 | m_motion_plus_active = false; | |||
| 217 | ||||
| 218 | // will make the first Update() call send a status request | |||
| 219 | // the first call to RequestStatus() will then set up the status struct extension bit | |||
| 220 | m_extension->active_extension = -1; | |||
| 221 | ||||
| 222 | // eeprom | |||
| 223 | memset(m_eeprom, 0, sizeof(m_eeprom)); | |||
| 224 | // calibration data | |||
| 225 | memcpy(m_eeprom, eeprom_data_0, sizeof(eeprom_data_0)); | |||
| 226 | // dunno what this is for, copied from old plugin | |||
| 227 | memcpy(m_eeprom + 0x16D0, eeprom_data_16D0, sizeof(eeprom_data_16D0)); | |||
| 228 | ||||
| 229 | // set up the register | |||
| 230 | memset(&m_reg_speaker, 0, sizeof(m_reg_speaker)); | |||
| 231 | memset(&m_reg_ir, 0, sizeof(m_reg_ir)); | |||
| 232 | memset(&m_reg_ext, 0, sizeof(m_reg_ext)); | |||
| 233 | memset(&m_reg_motion_plus, 0, sizeof(m_reg_motion_plus)); | |||
| 234 | ||||
| 235 | memcpy(&m_reg_motion_plus.ext_identifier, motion_plus_id, sizeof(motion_plus_id)); | |||
| 236 | ||||
| 237 | // status | |||
| 238 | memset(&m_status, 0, sizeof(m_status)); | |||
| 239 | // Battery levels in voltage | |||
| 240 | // 0x00 - 0x32: level 1 | |||
| 241 | // 0x33 - 0x43: level 2 | |||
| 242 | // 0x33 - 0x54: level 3 | |||
| 243 | // 0x55 - 0xff: level 4 | |||
| 244 | m_status.battery = 0x5f; | |||
| 245 | ||||
| 246 | memset(m_shake_step, 0, sizeof(m_shake_step)); | |||
| 247 | ||||
| 248 | // clear read request queue | |||
| 249 | while (m_read_requests.size()) | |||
| 250 | { | |||
| 251 | delete[] m_read_requests.front().data; | |||
| 252 | m_read_requests.pop(); | |||
| 253 | } | |||
| 254 | } | |||
| 255 | ||||
| 256 | Wiimote::Wiimote( const unsigned int index ) | |||
| 257 | : m_index(index) | |||
| 258 | , ir_sin(0) | |||
| 259 | , ir_cos(1) | |||
| 260 | // , m_sound_stream( NULL ) | |||
| 261 | { | |||
| 262 | // ---- set up all the controls ---- | |||
| 263 | ||||
| 264 | // buttons | |||
| 265 | groups.push_back(m_buttons = new Buttons("Buttons")); | |||
| 266 | for (unsigned int i=0; i < sizeof(named_buttons)/sizeof(*named_buttons); ++i) | |||
| 267 | m_buttons->controls.push_back(new ControlGroup::Input( named_buttons[i])); | |||
| 268 | ||||
| 269 | // udp | |||
| 270 | groups.push_back(m_udp = new UDPWrapper(m_index, _trans("UDP Wiimote")"UDP Wiimote")); | |||
| 271 | ||||
| 272 | // ir | |||
| 273 | groups.push_back(m_ir = new Cursor(_trans("IR")"IR")); | |||
| 274 | ||||
| 275 | // swing | |||
| 276 | groups.push_back(m_swing = new Force(_trans("Swing")"Swing")); | |||
| 277 | ||||
| 278 | // tilt | |||
| 279 | groups.push_back(m_tilt = new Tilt(_trans("Tilt")"Tilt")); | |||
| 280 | ||||
| 281 | // shake | |||
| 282 | groups.push_back(m_shake = new Buttons(_trans("Shake")"Shake")); | |||
| 283 | m_shake->controls.push_back(new ControlGroup::Input("X")); | |||
| 284 | m_shake->controls.push_back(new ControlGroup::Input("Y")); | |||
| 285 | m_shake->controls.push_back(new ControlGroup::Input("Z")); | |||
| 286 | ||||
| 287 | // extension | |||
| 288 | groups.push_back(m_extension = new Extension(_trans("Extension")"Extension")); | |||
| 289 | m_extension->attachments.push_back(new WiimoteEmu::None(m_reg_ext)); | |||
| 290 | m_extension->attachments.push_back(new WiimoteEmu::Nunchuk(m_udp, m_reg_ext)); | |||
| 291 | m_extension->attachments.push_back(new WiimoteEmu::Classic(m_reg_ext)); | |||
| 292 | m_extension->attachments.push_back(new WiimoteEmu::Guitar(m_reg_ext)); | |||
| 293 | m_extension->attachments.push_back(new WiimoteEmu::Drums(m_reg_ext)); | |||
| 294 | m_extension->attachments.push_back(new WiimoteEmu::Turntable(m_reg_ext)); | |||
| 295 | ||||
| 296 | m_extension->settings.push_back(new ControlGroup::Setting(_trans("Motion Plus")"Motion Plus", 0, 0, 1)); | |||
| 297 | ||||
| 298 | // rumble | |||
| 299 | groups.push_back(m_rumble = new ControlGroup(_trans("Rumble")"Rumble")); | |||
| 300 | m_rumble->controls.push_back(new ControlGroup::Output(_trans("Motor")"Motor")); | |||
| 301 | ||||
| 302 | // dpad | |||
| 303 | groups.push_back(m_dpad = new Buttons("D-Pad")); | |||
| 304 | for (unsigned int i=0; i < 4; ++i) | |||
| 305 | m_dpad->controls.push_back(new ControlGroup::Input(named_directions[i])); | |||
| 306 | ||||
| 307 | // options | |||
| 308 | groups.push_back( m_options = new ControlGroup(_trans("Options")"Options")); | |||
| 309 | m_options->settings.push_back(new ControlGroup::Setting(_trans("Background Input")"Background Input", false)); | |||
| 310 | m_options->settings.push_back(new ControlGroup::Setting(_trans("Sideways Wiimote")"Sideways Wiimote", false)); | |||
| 311 | m_options->settings.push_back(new ControlGroup::Setting(_trans("Upright Wiimote")"Upright Wiimote", false)); | |||
| 312 | ||||
| 313 | // TODO: This value should probably be re-read if SYSCONF gets changed | |||
| 314 | m_sensor_bar_on_top = SConfig::GetInstance().m_SYSCONF->GetData<u8>("BT.BAR") != 0; | |||
| 315 | ||||
| 316 | // --- reset eeprom/register/values to default --- | |||
| 317 | Reset(); | |||
| 318 | } | |||
| 319 | ||||
| 320 | std::string Wiimote::GetName() const | |||
| 321 | { | |||
| 322 | return std::string("Wiimote") + char('1'+m_index); | |||
| 323 | } | |||
| 324 | ||||
| 325 | // if windows is focused or background input is enabled | |||
| 326 | #define HAS_FOCUS(Host_RendererHasFocus() || (m_options->settings[0]->value != 0)) (Host_RendererHasFocus() || (m_options->settings[0]->value != 0)) | |||
| 327 | ||||
| 328 | bool Wiimote::Step() | |||
| 329 | { | |||
| 330 | const bool has_focus = HAS_FOCUS(Host_RendererHasFocus() || (m_options->settings[0]->value != 0)); | |||
| 331 | ||||
| 332 | // TODO: change this a bit | |||
| 333 | m_motion_plus_present = m_extension->settings[0]->value != 0; | |||
| 334 | ||||
| 335 | // no rumble if no focus | |||
| 336 | if (false == has_focus) | |||
| 337 | m_rumble_on = false; | |||
| 338 | ||||
| 339 | m_rumble->controls[0]->control_ref->State(m_rumble_on); | |||
| 340 | ||||
| 341 | // when a movie is active, this button status update is disabled (moved), because movies only record data reports. | |||
| 342 | if(!(Movie::IsPlayingInput() || Movie::IsRecordingInput())) | |||
| 343 | { | |||
| 344 | UpdateButtonsStatus(has_focus); | |||
| 345 | } | |||
| 346 | ||||
| 347 | // check if there is a read data request | |||
| 348 | if (m_read_requests.size()) | |||
| 349 | { | |||
| 350 | ReadRequest& rr = m_read_requests.front(); | |||
| 351 | // send up to 16 bytes to the wii | |||
| 352 | SendReadDataReply(rr); | |||
| 353 | //SendReadDataReply(rr.channel, rr); | |||
| 354 | ||||
| 355 | // if there is no more data, remove from queue | |||
| 356 | if (0 == rr.size) | |||
| 357 | { | |||
| 358 | delete[] rr.data; | |||
| 359 | m_read_requests.pop(); | |||
| 360 | } | |||
| 361 | ||||
| 362 | // dont send any other reports | |||
| 363 | return true; | |||
| 364 | } | |||
| 365 | ||||
| 366 | // check if a status report needs to be sent | |||
| 367 | // this happens on wiimote sync and when extensions are switched | |||
| 368 | if (m_extension->active_extension != m_extension->switch_extension) | |||
| 369 | { | |||
| 370 | RequestStatus(); | |||
| 371 | ||||
| 372 | // Wiibrew: Following a connection or disconnection event on the Extension Port, | |||
| 373 | // data reporting is disabled and the Data Reporting Mode must be reset before new data can arrive. | |||
| 374 | // after a game receives an unrequested status report, | |||
| 375 | // it expects data reports to stop until it sets the reporting mode again | |||
| 376 | m_reporting_auto = false; | |||
| 377 | ||||
| 378 | return true; | |||
| 379 | } | |||
| 380 | ||||
| 381 | return false; | |||
| 382 | } | |||
| 383 | ||||
| 384 | void Wiimote::UpdateButtonsStatus(bool has_focus) | |||
| 385 | { | |||
| 386 | // update buttons in status struct | |||
| 387 | m_status.buttons = 0; | |||
| 388 | if (has_focus) | |||
| 389 | { | |||
| 390 | const bool is_sideways = m_options->settings[1]->value != 0; | |||
| 391 | m_buttons->GetState(&m_status.buttons, button_bitmasks); | |||
| 392 | m_dpad->GetState(&m_status.buttons, is_sideways ? dpad_sideways_bitmasks : dpad_bitmasks); | |||
| 393 | UDPTLayer::GetButtons(m_udp, &m_status.buttons); | |||
| 394 | } | |||
| 395 | } | |||
| 396 | ||||
| 397 | void Wiimote::GetCoreData(u8* const data) | |||
| 398 | { | |||
| 399 | // when a movie is active, the button update happens here instead of Wiimote::Step, to avoid potential desync issues. | |||
| 400 | if(Movie::IsPlayingInput() || Movie::IsRecordingInput()) | |||
| 401 | { | |||
| 402 | UpdateButtonsStatus(HAS_FOCUS(Host_RendererHasFocus() || (m_options->settings[0]->value != 0))); | |||
| 403 | } | |||
| 404 | ||||
| 405 | *(wm_core*)data |= m_status.buttons; | |||
| 406 | } | |||
| 407 | ||||
| 408 | void Wiimote::GetAccelData(u8* const data, u8* const buttons) | |||
| 409 | { | |||
| 410 | const bool has_focus = HAS_FOCUS(Host_RendererHasFocus() || (m_options->settings[0]->value != 0)); | |||
| 411 | const bool is_sideways = m_options->settings[1]->value != 0; | |||
| 412 | const bool is_upright = m_options->settings[2]->value != 0; | |||
| 413 | accel_cal* calib = (accel_cal*)&m_eeprom[0x16]; | |||
| 414 | ||||
| 415 | // ----TILT---- | |||
| 416 | EmulateTilt(&m_accel, m_tilt, has_focus, is_sideways, is_upright); | |||
| 417 | ||||
| 418 | // ----SWING---- | |||
| 419 | // ----SHAKE---- | |||
| 420 | if (has_focus) | |||
| 421 | { | |||
| 422 | EmulateSwing(&m_accel, m_swing, is_sideways, is_upright); | |||
| 423 | EmulateShake(&m_accel, calib, m_shake, m_shake_step); | |||
| 424 | UDPTLayer::GetAcceleration(m_udp, &m_accel); | |||
| 425 | } | |||
| 426 | wm_accel* dt = (wm_accel*)data; | |||
| 427 | double cx,cy,cz; | |||
| 428 | cx=trim(m_accel.x*(calib->one_g.x-calib->zero_g.x)+calib->zero_g.x); | |||
| 429 | cy=trim(m_accel.y*(calib->one_g.y-calib->zero_g.y)+calib->zero_g.y); | |||
| 430 | cz=trim(m_accel.z*(calib->one_g.z-calib->zero_g.z)+calib->zero_g.z); | |||
| 431 | dt->x=u8(cx); | |||
| 432 | dt->y=u8(cy); | |||
| 433 | dt->z=u8(cz); | |||
| 434 | if (buttons) | |||
| 435 | { | |||
| 436 | buttons[0]|=(u8(cx*4)&3)<<5; | |||
| 437 | buttons[1]|=((u8(cy*2)&1)<<5)|((u8(cz*2)&1)<<6); | |||
| 438 | } | |||
| 439 | } | |||
| 440 | #define kCutoffFreq5.0f 5.0f | |||
| 441 | inline void LowPassFilter(double & var, double newval, double period) | |||
| 442 | { | |||
| 443 | double RC=1.0/kCutoffFreq5.0f; | |||
| 444 | double alpha=period/(period+RC); | |||
| 445 | var = newval * alpha + var * (1.0 - alpha); | |||
| 446 | } | |||
| 447 | ||||
| 448 | void Wiimote::GetIRData(u8* const data, bool use_accel) | |||
| 449 | { | |||
| 450 | const bool has_focus = HAS_FOCUS(Host_RendererHasFocus() || (m_options->settings[0]->value != 0)); | |||
| 451 | ||||
| 452 | u16 x[4], y[4]; | |||
| 453 | memset(x, 0xFF, sizeof(x)); | |||
| 454 | ||||
| 455 | if (has_focus) | |||
| ||||
| 456 | { | |||
| 457 | float xx = 10000, yy = 0, zz = 0; | |||
| 458 | double nsin,ncos; | |||
| 459 | ||||
| 460 | if (use_accel) | |||
| 461 | { | |||
| 462 | double ax,az,len; | |||
| 463 | ax=m_accel.x; | |||
| 464 | az=m_accel.z; | |||
| 465 | len=sqrt(ax*ax+az*az); | |||
| 466 | if (len) | |||
| 467 | { | |||
| 468 | ax/=len; | |||
| 469 | az/=len; //normalizing the vector | |||
| 470 | nsin=ax; | |||
| 471 | ncos=az; | |||
| 472 | } | |||
| 473 | else | |||
| 474 | { | |||
| 475 | nsin=0; | |||
| 476 | ncos=1; | |||
| 477 | } | |||
| 478 | // PanicAlert("%d %d %d\nx:%f\nz:%f\nsin:%f\ncos:%f",accel->x,accel->y,accel->z,ax,az,sin,cos); | |||
| 479 | //PanicAlert("%d %d %d\n%d %d %d\n%d %d %d",accel->x,accel->y,accel->z,calib->zero_g.x,calib->zero_g.y,calib->zero_g.z, | |||
| 480 | // calib->one_g.x,calib->one_g.y,calib->one_g.z); | |||
| 481 | } | |||
| 482 | else | |||
| 483 | { | |||
| 484 | nsin=0; //m_tilt stuff here (can't figure it out yet....) | |||
| 485 | ncos=1; | |||
| 486 | } | |||
| 487 | ||||
| 488 | LowPassFilter(ir_sin,nsin,1.0f/60); | |||
| 489 | LowPassFilter(ir_cos,ncos,1.0f/60); | |||
| 490 | ||||
| 491 | m_ir->GetState(&xx, &yy, &zz, true); | |||
| 492 | UDPTLayer::GetIR(m_udp, &xx, &yy, &zz); | |||
| 493 | ||||
| 494 | Vertex v[4]; | |||
| 495 | ||||
| 496 | static const int camWidth=1024; | |||
| 497 | static const int camHeight=768; | |||
| 498 | static const double bndup=-0.315447; | |||
| 499 | static const double bnddown=0.85; | |||
| 500 | static const double bndleft=0.443364; | |||
| 501 | static const double bndright=-0.443364; | |||
| 502 | static const double dist1=100.f/camWidth; //this seems the optimal distance for zelda | |||
| 503 | static const double dist2=1.2f*dist1; | |||
| 504 | ||||
| 505 | for (int i=0; i<4; i++) | |||
| 506 | { | |||
| 507 | v[i].x=xx*(bndright-bndleft)/2+(bndleft+bndright)/2; | |||
| 508 | if (m_sensor_bar_on_top) v[i].y=yy*(bndup-bnddown)/2+(bndup+bnddown)/2; | |||
| 509 | else v[i].y=yy*(bndup-bnddown)/2-(bndup+bnddown)/2; | |||
| 510 | v[i].z=0; | |||
| 511 | } | |||
| 512 | ||||
| 513 | v[0].x-=(zz*0.5+1)*dist1; | |||
| 514 | v[1].x+=(zz*0.5+1)*dist1; | |||
| 515 | v[2].x-=(zz*0.5+1)*dist2; | |||
| 516 | v[3].x+=(zz*0.5+1)*dist2; | |||
| 517 | ||||
| 518 | #define printmatrix(m)MsgAlert(false, WARNING, "%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n" ,m[0][0],m[0][1],m[0][2],m[0][3],m[1][0],m[1][1],m[1][2],m[1] [3],m[2][0],m[2][1],m[2][2],m[2][3],m[3][0],m[3][1],m[3][2],m [3][3]) PanicAlert("%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n",m[0][0],m[0][1],m[0][2],m[0][3],m[1][0],m[1][1],m[1][2],m[1][3],m[2][0],m[2][1],m[2][2],m[2][3],m[3][0],m[3][1],m[3][2],m[3][3])MsgAlert(false, WARNING, "%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n" ,m[0][0],m[0][1],m[0][2],m[0][3],m[1][0],m[1][1],m[1][2],m[1] [3],m[2][0],m[2][1],m[2][2],m[2][3],m[3][0],m[3][1],m[3][2],m [3][3]) | |||
| 519 | Matrix rot,tot; | |||
| 520 | static Matrix scale; | |||
| 521 | static bool isscale=false; | |||
| 522 | if (!isscale) | |||
| 523 | { | |||
| 524 | MatrixScale(scale,1,camWidth/camHeight,1); | |||
| 525 | //MatrixIdentity(scale); | |||
| 526 | } | |||
| 527 | MatrixRotationByZ(rot,ir_sin,ir_cos); | |||
| 528 | //MatrixIdentity(rot); | |||
| 529 | MatrixMultiply(tot,scale,rot); | |||
| 530 | ||||
| 531 | for (int i=0; i<4; i++) | |||
| 532 | { | |||
| 533 | MatrixTransformVertex(tot,v[i]); | |||
| 534 | if ((v[i].x<-1)||(v[i].x>1)||(v[i].y<-1)||(v[i].y>1)) | |||
| 535 | continue; | |||
| 536 | x[i]=(u16)round((v[i].x+1)/2*(camWidth-1)); | |||
| 537 | y[i]=(u16)round((v[i].y+1)/2*(camHeight-1)); | |||
| 538 | } | |||
| 539 | // PanicAlert("%f %f\n%f %f\n%f %f\n%f %f\n%d %d\n%d %d\n%d %d\n%d %d", | |||
| 540 | // v[0].x,v[0].y,v[1].x,v[1].y,v[2].x,v[2].y,v[3].x,v[3].y, | |||
| 541 | // x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[38]); | |||
| 542 | } | |||
| 543 | // Fill report with valid data when full handshake was done | |||
| 544 | if (m_reg_ir.data[0x30]) | |||
| 545 | // ir mode | |||
| 546 | switch (m_reg_ir.mode) | |||
| 547 | { | |||
| 548 | // basic | |||
| 549 | case 1 : | |||
| 550 | { | |||
| 551 | memset(data, 0xFF, 10); | |||
| 552 | wm_ir_basic* const irdata = (wm_ir_basic*)data; | |||
| 553 | for (unsigned int i=0; i<2; ++i) | |||
| 554 | { | |||
| 555 | if (x[i*2] < 1024 && y[i*2] < 768) | |||
| ||||
| 556 | { | |||
| 557 | irdata[i].x1 = u8(x[i*2]); | |||
| 558 | irdata[i].x1hi = x[i*2] >> 8; | |||
| 559 | ||||
| 560 | irdata[i].y1 = u8(y[i*2]); | |||
| 561 | irdata[i].y1hi = y[i*2] >> 8; | |||
| 562 | } | |||
| 563 | if (x[i*2+1] < 1024 && y[i*2+1] < 768) | |||
| 564 | { | |||
| 565 | irdata[i].x2 = u8(x[i*2+1]); | |||
| 566 | irdata[i].x2hi = x[i*2+1] >> 8; | |||
| 567 | ||||
| 568 | irdata[i].y2 = u8(y[i*2+1]); | |||
| 569 | irdata[i].y2hi = y[i*2+1] >> 8; | |||
| 570 | } | |||
| 571 | } | |||
| 572 | } | |||
| 573 | break; | |||
| 574 | // extended | |||
| 575 | case 3 : | |||
| 576 | { | |||
| 577 | memset(data, 0xFF, 12); | |||
| 578 | wm_ir_extended* const irdata = (wm_ir_extended*)data; | |||
| 579 | for (unsigned int i=0; i<4; ++i) | |||
| 580 | if (x[i] < 1024 && y[i] < 768) | |||
| 581 | { | |||
| 582 | irdata[i].x = u8(x[i]); | |||
| 583 | irdata[i].xhi = x[i] >> 8; | |||
| 584 | ||||
| 585 | irdata[i].y = u8(y[i]); | |||
| 586 | irdata[i].yhi = y[i] >> 8; | |||
| 587 | ||||
| 588 | irdata[i].size = 10; | |||
| 589 | } | |||
| 590 | } | |||
| 591 | break; | |||
| 592 | // full | |||
| 593 | case 5 : | |||
| 594 | PanicAlert("Full IR report")MsgAlert(false, WARNING, "Full IR report"); | |||
| 595 | // UNSUPPORTED | |||
| 596 | break; | |||
| 597 | } | |||
| 598 | } | |||
| 599 | ||||
| 600 | void Wiimote::GetExtData(u8* const data) | |||
| 601 | { | |||
| 602 | m_extension->GetState(data, HAS_FOCUS(Host_RendererHasFocus() || (m_options->settings[0]->value != 0))); | |||
| 603 | ||||
| 604 | // i dont think anything accesses the extension data like this, but ill support it. Indeed, commercial games don't do this. | |||
| 605 | // i think it should be unencrpyted in the register, encrypted when read. | |||
| 606 | memcpy(m_reg_ext.controller_data, data, sizeof(wm_extension)); | |||
| 607 | ||||
| 608 | // motionplus pass-through modes | |||
| 609 | if (m_motion_plus_active) | |||
| 610 | { | |||
| 611 | switch (m_reg_motion_plus.ext_identifier[0x4]) | |||
| 612 | { | |||
| 613 | // nunchuck pass-through mode | |||
| 614 | // Bit 7 of byte 5 is moved to bit 6 of byte 5, overwriting it | |||
| 615 | // Bit 0 of byte 4 is moved to bit 7 of byte 5 | |||
| 616 | // Bit 3 of byte 5 is moved to bit 4 of byte 5, overwriting it | |||
| 617 | // Bit 1 of byte 5 is moved to bit 3 of byte 5 | |||
| 618 | // Bit 0 of byte 5 is moved to bit 2 of byte 5, overwriting it | |||
| 619 | case 0x5: | |||
| 620 | //data[5] & (1 << 7) | |||
| 621 | //data[4] & (1 << 0) | |||
| 622 | //data[5] & (1 << 3) | |||
| 623 | //data[5] & (1 << 1) | |||
| 624 | //data[5] & (1 << 0) | |||
| 625 | break; | |||
| 626 | ||||
| 627 | // classic controller/musical instrument pass-through mode | |||
| 628 | // Bit 0 of Byte 4 is overwritten | |||
| 629 | // Bits 0 and 1 of Byte 5 are moved to bit 0 of Bytes 0 and 1, overwriting | |||
| 630 | case 0x7: | |||
| 631 | //data[4] & (1 << 0) | |||
| 632 | //data[5] & (1 << 0) | |||
| 633 | //data[5] & (1 << 1) | |||
| 634 | break; | |||
| 635 | ||||
| 636 | // unknown pass-through mode | |||
| 637 | default: | |||
| 638 | break; | |||
| 639 | } | |||
| 640 | ||||
| 641 | ((wm_motionplus_data*)data)->is_mp_data = 0; | |||
| 642 | ((wm_motionplus_data*)data)->extension_connected = m_extension->active_extension; | |||
| 643 | } | |||
| 644 | ||||
| 645 | if (0xAA == m_reg_ext.encryption) | |||
| 646 | wiimote_encrypt(&m_ext_key, data, 0x00, sizeof(wm_extension)); | |||
| 647 | } | |||
| 648 | ||||
| 649 | void Wiimote::Update() | |||
| 650 | { | |||
| 651 | // no channel == not connected i guess | |||
| 652 | if (0 == m_reporting_channel) | |||
| 653 | return; | |||
| 654 | ||||
| 655 | // returns true if a report was sent | |||
| 656 | if (Step()) | |||
| 657 | return; | |||
| 658 | ||||
| 659 | u8 data[MAX_PAYLOAD23]; | |||
| 660 | memset(data, 0, sizeof(data)); | |||
| 661 | ||||
| 662 | // figure out what data we need | |||
| 663 | s8 rptf_size = MAX_PAYLOAD23; | |||
| 664 | ||||
| 665 | Movie::SetPolledDevice(); | |||
| 666 | ||||
| 667 | const ReportFeatures& rptf = reporting_mode_features[m_reporting_mode - WM_REPORT_CORE0x30]; | |||
| 668 | rptf_size = rptf.size; | |||
| 669 | if (Movie::IsPlayingInput() && Movie::PlayWiimote(m_index, data, rptf, m_reg_ir.mode)) | |||
| 670 | { | |||
| 671 | if (rptf.core) | |||
| 672 | m_status.buttons = *(wm_core*)(data + rptf.core); | |||
| 673 | } | |||
| 674 | else | |||
| 675 | { | |||
| 676 | data[0] = 0xA1; | |||
| 677 | data[1] = m_reporting_mode; | |||
| 678 | ||||
| 679 | // core buttons | |||
| 680 | if (rptf.core) | |||
| 681 | GetCoreData(data + rptf.core); | |||
| 682 | ||||
| 683 | // acceleration | |||
| 684 | if (rptf.accel) | |||
| 685 | GetAccelData(data + rptf.accel, rptf.core?(data+rptf.core):NULL__null); | |||
| 686 | ||||
| 687 | // IR | |||
| 688 | if (rptf.ir) | |||
| 689 | GetIRData(data + rptf.ir, (rptf.accel != 0)); | |||
| 690 | ||||
| 691 | // extension | |||
| 692 | if (rptf.ext) | |||
| 693 | GetExtData(data + rptf.ext); | |||
| 694 | ||||
| 695 | // hybrid wiimote stuff (for now, it's not supported while recording) | |||
| 696 | if (WIIMOTE_SRC_HYBRID == g_wiimote_sources[m_index] && !Movie::IsRecordingInput()) | |||
| 697 | { | |||
| 698 | using namespace WiimoteReal; | |||
| 699 | ||||
| 700 | std::lock_guard<std::recursive_mutex> lk(g_refresh_lock); | |||
| 701 | if (g_wiimotes[m_index]) | |||
| 702 | { | |||
| 703 | const Report& rpt = g_wiimotes[m_index]->ProcessReadQueue(); | |||
| 704 | if (!rpt.empty()) | |||
| 705 | { | |||
| 706 | const u8 *real_data = rpt.data(); | |||
| 707 | switch (real_data[1]) | |||
| 708 | { | |||
| 709 | // use data reports | |||
| 710 | default: | |||
| 711 | if (real_data[1] >= WM_REPORT_CORE0x30) | |||
| 712 | { | |||
| 713 | const ReportFeatures& real_rptf = reporting_mode_features[real_data[1] - WM_REPORT_CORE0x30]; | |||
| 714 | ||||
| 715 | // force same report type from real-wiimote | |||
| 716 | if (&real_rptf != &rptf) | |||
| 717 | rptf_size = 0; | |||
| 718 | ||||
| 719 | // core | |||
| 720 | // mix real-buttons with emu-buttons in the status struct, and in the report | |||
| 721 | if (real_rptf.core && rptf.core) | |||
| 722 | { | |||
| 723 | m_status.buttons |= *(wm_core*)(real_data + real_rptf.core); | |||
| 724 | *(wm_core*)(data + rptf.core) = m_status.buttons; | |||
| 725 | } | |||
| 726 | ||||
| 727 | // accel | |||
| 728 | // use real-accel data always i guess | |||
| 729 | if (real_rptf.accel && rptf.accel) | |||
| 730 | memcpy(data + rptf.accel, real_data + real_rptf.accel, sizeof(wm_accel)); | |||
| 731 | ||||
| 732 | // ir | |||
| 733 | // TODO | |||
| 734 | ||||
| 735 | // ext | |||
| 736 | // use real-ext data if an emu-extention isn't chosen | |||
| 737 | if (real_rptf.ext && rptf.ext && (0 == m_extension->switch_extension)) | |||
| 738 | memcpy(data + rptf.ext, real_data + real_rptf.ext, sizeof(wm_extension)); | |||
| 739 | } | |||
| 740 | else if (WM_ACK_DATA0x22 != real_data[1] || m_extension->active_extension > 0) | |||
| 741 | rptf_size = 0; | |||
| 742 | else | |||
| 743 | // use real-acks if an emu-extension isn't chosen | |||
| 744 | rptf_size = -1; | |||
| 745 | break; | |||
| 746 | ||||
| 747 | // use all status reports, after modification of the extension bit | |||
| 748 | case WM_STATUS_REPORT0x20 : | |||
| 749 | //if (m_extension->switch_extension) | |||
| 750 | //((wm_status_report*)(real_data + 2))->extension = (m_extension->active_extension > 0); | |||
| 751 | if (m_extension->active_extension) | |||
| 752 | ((wm_status_report*)(real_data + 2))->extension = 1; | |||
| 753 | rptf_size = -1; | |||
| 754 | break; | |||
| 755 | ||||
| 756 | // use all read-data replies | |||
| 757 | case WM_READ_DATA_REPLY0x21: | |||
| 758 | rptf_size = -1; | |||
| 759 | break; | |||
| 760 | ||||
| 761 | } | |||
| 762 | ||||
| 763 | // copy over report from real-wiimote | |||
| 764 | if (-1 == rptf_size) | |||
| 765 | { | |||
| 766 | std::copy(rpt.begin(), rpt.end(), data); | |||
| 767 | rptf_size = rpt.size(); | |||
| 768 | } | |||
| 769 | } | |||
| 770 | } | |||
| 771 | } | |||
| 772 | } | |||
| 773 | if (!Movie::IsPlayingInput()) | |||
| 774 | { | |||
| 775 | Movie::CheckWiimoteStatus(m_index, data, rptf, m_reg_ir.mode); | |||
| 776 | } | |||
| 777 | ||||
| 778 | // don't send a data report if auto reporting is off | |||
| 779 | if (false == m_reporting_auto && data[2] >= WM_REPORT_CORE0x30) | |||
| 780 | return; | |||
| 781 | ||||
| 782 | // send data report | |||
| 783 | if (rptf_size) | |||
| 784 | { | |||
| 785 | WiimoteEmu::Spy(this, data, rptf_size); | |||
| 786 | Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, data, rptf_size); | |||
| 787 | } | |||
| 788 | } | |||
| 789 | ||||
| 790 | void Wiimote::ControlChannel(const u16 _channelID, const void* _pData, u32 _Size) | |||
| 791 | { | |||
| 792 | // Check for custom communication | |||
| 793 | if (99 == _channelID) | |||
| 794 | { | |||
| 795 | // wiimote disconnected | |||
| 796 | //PanicAlert( "Wiimote Disconnected" ); | |||
| 797 | ||||
| 798 | // reset eeprom/register/reporting mode | |||
| 799 | Reset(); | |||
| 800 | return; | |||
| 801 | } | |||
| 802 | ||||
| 803 | // this all good? | |||
| 804 | m_reporting_channel = _channelID; | |||
| 805 | ||||
| 806 | const hid_packet* const hidp = (hid_packet*)_pData; | |||
| 807 | ||||
| 808 | INFO_LOG(WIIMOTE, "Emu ControlChannel (page: %i, type: 0x%02x, param: 0x%02x)", m_index, hidp->type, hidp->param)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO , LogTypes::WIIMOTE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp" , 808, "Emu ControlChannel (page: %i, type: 0x%02x, param: 0x%02x)" , m_index, hidp->type, hidp->param); } } while (0); | |||
| 809 | ||||
| 810 | switch (hidp->type) | |||
| 811 | { | |||
| 812 | case HID_TYPE_HANDSHAKE0 : | |||
| 813 | PanicAlert("HID_TYPE_HANDSHAKE - %s", (hidp->param == HID_PARAM_INPUT) ? "INPUT" : "OUPUT")MsgAlert(false, WARNING, "HID_TYPE_HANDSHAKE - %s", (hidp-> param == 1) ? "INPUT" : "OUPUT"); | |||
| 814 | break; | |||
| 815 | ||||
| 816 | case HID_TYPE_SET_REPORT5 : | |||
| 817 | if (HID_PARAM_INPUT1 == hidp->param) | |||
| 818 | { | |||
| 819 | PanicAlert("HID_TYPE_SET_REPORT - INPUT")MsgAlert(false, WARNING, "HID_TYPE_SET_REPORT - INPUT"); | |||
| 820 | } | |||
| 821 | else | |||
| 822 | { | |||
| 823 | // AyuanX: My experiment shows Control Channel is never used | |||
| 824 | // shuffle2: but lwbt uses this, so we'll do what we must :) | |||
| 825 | HidOutputReport((wm_report*)hidp->data); | |||
| 826 | ||||
| 827 | u8 handshake = HID_HANDSHAKE_SUCCESS0; | |||
| 828 | Core::Callback_WiimoteInterruptChannel(m_index, _channelID, &handshake, 1); | |||
| 829 | } | |||
| 830 | break; | |||
| 831 | ||||
| 832 | case HID_TYPE_DATA0xA : | |||
| 833 | PanicAlert("HID_TYPE_DATA - %s", (hidp->param == HID_PARAM_INPUT) ? "INPUT" : "OUTPUT")MsgAlert(false, WARNING, "HID_TYPE_DATA - %s", (hidp->param == 1) ? "INPUT" : "OUTPUT"); | |||
| 834 | break; | |||
| 835 | ||||
| 836 | default : | |||
| 837 | PanicAlert("HidControlChannel: Unknown type %x and param %x", hidp->type, hidp->param)MsgAlert(false, WARNING, "HidControlChannel: Unknown type %x and param %x" , hidp->type, hidp->param); | |||
| 838 | break; | |||
| 839 | } | |||
| 840 | ||||
| 841 | } | |||
| 842 | ||||
| 843 | void Wiimote::InterruptChannel(const u16 _channelID, const void* _pData, u32 _Size) | |||
| 844 | { | |||
| 845 | // this all good? | |||
| 846 | m_reporting_channel = _channelID; | |||
| 847 | ||||
| 848 | const hid_packet* const hidp = (hid_packet*)_pData; | |||
| 849 | ||||
| 850 | switch (hidp->type) | |||
| 851 | { | |||
| 852 | case HID_TYPE_DATA0xA: | |||
| 853 | switch (hidp->param) | |||
| 854 | { | |||
| 855 | case HID_PARAM_OUTPUT2 : | |||
| 856 | { | |||
| 857 | const wm_report* const sr = (wm_report*)hidp->data; | |||
| 858 | ||||
| 859 | if (WIIMOTE_SRC_REAL & g_wiimote_sources[m_index]) | |||
| 860 | { | |||
| 861 | switch (sr->wm) | |||
| 862 | { | |||
| 863 | // these two types are handled in RequestStatus() & ReadData() | |||
| 864 | case WM_REQUEST_STATUS0x15 : | |||
| 865 | case WM_READ_DATA0x17 : | |||
| 866 | if (WIIMOTE_SRC_REAL == g_wiimote_sources[m_index]) | |||
| 867 | WiimoteReal::InterruptChannel(m_index, _channelID, _pData, _Size); | |||
| 868 | break; | |||
| 869 | ||||
| 870 | default : | |||
| 871 | WiimoteReal::InterruptChannel(m_index, _channelID, _pData, _Size); | |||
| 872 | break; | |||
| 873 | } | |||
| 874 | ||||
| 875 | HidOutputReport(sr, m_extension->switch_extension > 0); | |||
| 876 | } | |||
| 877 | else | |||
| 878 | HidOutputReport(sr); | |||
| 879 | } | |||
| 880 | break; | |||
| 881 | ||||
| 882 | default : | |||
| 883 | PanicAlert("HidInput: HID_TYPE_DATA - param 0x%02x", hidp->param)MsgAlert(false, WARNING, "HidInput: HID_TYPE_DATA - param 0x%02x" , hidp->param); | |||
| 884 | break; | |||
| 885 | } | |||
| 886 | break; | |||
| 887 | ||||
| 888 | default: | |||
| 889 | PanicAlert("HidInput: Unknown type 0x%02x and param 0x%02x", hidp->type, hidp->param)MsgAlert(false, WARNING, "HidInput: Unknown type 0x%02x and param 0x%02x" , hidp->type, hidp->param); | |||
| 890 | break; | |||
| 891 | } | |||
| 892 | } | |||
| 893 | ||||
| 894 | void Wiimote::LoadDefaults(const ControllerInterface& ciface) | |||
| 895 | { | |||
| 896 | ControllerEmu::LoadDefaults(ciface); | |||
| 897 | ||||
| 898 | #define set_control(group, num, str)(group)->controls[num]->control_ref->expression = (str ) (group)->controls[num]->control_ref->expression = (str) | |||
| 899 | ||||
| 900 | // Buttons | |||
| 901 | #if defined HAVE_X111 && HAVE_X111 | |||
| 902 | set_control(m_buttons, 0, "Click 1")(m_buttons)->controls[0]->control_ref->expression = ( "Click 1"); // A | |||
| 903 | set_control(m_buttons, 1, "Click 3")(m_buttons)->controls[1]->control_ref->expression = ( "Click 3"); // B | |||
| 904 | #else | |||
| 905 | set_control(m_buttons, 0, "Click 0")(m_buttons)->controls[0]->control_ref->expression = ( "Click 0"); // A | |||
| 906 | set_control(m_buttons, 1, "Click 1")(m_buttons)->controls[1]->control_ref->expression = ( "Click 1"); // B | |||
| 907 | #endif | |||
| 908 | set_control(m_buttons, 2, "1")(m_buttons)->controls[2]->control_ref->expression = ( "1"); // 1 | |||
| 909 | set_control(m_buttons, 3, "2")(m_buttons)->controls[3]->control_ref->expression = ( "2"); // 2 | |||
| 910 | set_control(m_buttons, 4, "Q")(m_buttons)->controls[4]->control_ref->expression = ( "Q"); // - | |||
| 911 | set_control(m_buttons, 5, "E")(m_buttons)->controls[5]->control_ref->expression = ( "E"); // + | |||
| 912 | ||||
| 913 | #ifdef _WIN32 | |||
| 914 | set_control(m_buttons, 6, "RETURN")(m_buttons)->controls[6]->control_ref->expression = ( "RETURN"); // Home | |||
| 915 | #else | |||
| 916 | set_control(m_buttons, 6, "Return")(m_buttons)->controls[6]->control_ref->expression = ( "Return"); // Home | |||
| 917 | #endif | |||
| 918 | ||||
| 919 | // Shake | |||
| 920 | for (size_t i = 0; i != 3; ++i) | |||
| 921 | set_control(m_shake, i, "Click 2")(m_shake)->controls[i]->control_ref->expression = ("Click 2" ); | |||
| 922 | ||||
| 923 | // IR | |||
| 924 | set_control(m_ir, 0, "Cursor Y-")(m_ir)->controls[0]->control_ref->expression = ("Cursor Y-" ); | |||
| 925 | set_control(m_ir, 1, "Cursor Y+")(m_ir)->controls[1]->control_ref->expression = ("Cursor Y+" ); | |||
| 926 | set_control(m_ir, 2, "Cursor X-")(m_ir)->controls[2]->control_ref->expression = ("Cursor X-" ); | |||
| 927 | set_control(m_ir, 3, "Cursor X+")(m_ir)->controls[3]->control_ref->expression = ("Cursor X+" ); | |||
| 928 | ||||
| 929 | // DPad | |||
| 930 | #ifdef _WIN32 | |||
| 931 | set_control(m_dpad, 0, "UP")(m_dpad)->controls[0]->control_ref->expression = ("UP" ); // Up | |||
| 932 | set_control(m_dpad, 1, "DOWN")(m_dpad)->controls[1]->control_ref->expression = ("DOWN" ); // Down | |||
| 933 | set_control(m_dpad, 2, "LEFT")(m_dpad)->controls[2]->control_ref->expression = ("LEFT" ); // Left | |||
| 934 | set_control(m_dpad, 3, "RIGHT")(m_dpad)->controls[3]->control_ref->expression = ("RIGHT" ); // Right | |||
| 935 | #elif __APPLE__ | |||
| 936 | set_control(m_dpad, 0, "Up Arrow")(m_dpad)->controls[0]->control_ref->expression = ("Up Arrow" ); // Up | |||
| 937 | set_control(m_dpad, 1, "Down Arrow")(m_dpad)->controls[1]->control_ref->expression = ("Down Arrow" ); // Down | |||
| 938 | set_control(m_dpad, 2, "Left Arrow")(m_dpad)->controls[2]->control_ref->expression = ("Left Arrow" ); // Left | |||
| 939 | set_control(m_dpad, 3, "Right Arrow")(m_dpad)->controls[3]->control_ref->expression = ("Right Arrow" ); // Right | |||
| 940 | #else | |||
| 941 | set_control(m_dpad, 0, "Up")(m_dpad)->controls[0]->control_ref->expression = ("Up" ); // Up | |||
| 942 | set_control(m_dpad, 1, "Down")(m_dpad)->controls[1]->control_ref->expression = ("Down" ); // Down | |||
| 943 | set_control(m_dpad, 2, "Left")(m_dpad)->controls[2]->control_ref->expression = ("Left" ); // Left | |||
| 944 | set_control(m_dpad, 3, "Right")(m_dpad)->controls[3]->control_ref->expression = ("Right" ); // Right | |||
| 945 | #endif | |||
| 946 | ||||
| 947 | // ugly stuff | |||
| 948 | // enable nunchuk | |||
| 949 | m_extension->switch_extension = 1; | |||
| 950 | ||||
| 951 | // set nunchuk defaults | |||
| 952 | m_extension->attachments[1]->LoadDefaults(ciface); | |||
| 953 | } | |||
| 954 | ||||
| 955 | } |