Removed the hackery that was being done with the plugin configuration dialogs on...
[dolphin.git] / Source / Plugins / Plugin_Wiimote / Src / wiimote_real.cpp
blob703bd61c2c40e927ae58c5bbe964ae4e2610de3e
1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
19 #include <iostream> // System
20 #include <queue>
22 #include "wiiuse.h"
24 #include "Common.h"
25 #include "Thread.h"
26 #include "StringUtil.h"
27 #include "Timer.h"
28 #include "pluginspecs_wiimote.h"
30 #include "wiimote_hid.h"
31 #include "main.h"
32 #include "Config.h"
33 #include "EmuMain.h"
34 #include "EmuDefinitions.h"
35 #define EXCLUDE_H // Avoid certain declarations in wiimote_real.h
36 #include "wiimote_real.h"
37 #if defined(HAVE_WX) && HAVE_WX
38 #include "ConfigBasicDlg.h"
39 #endif
41 #ifdef WIN32
42 #include <bthdef.h>
43 #include <BluetoothAPIs.h>
45 #pragma comment(lib, "Bthprops.lib")
46 #endif
47 extern SWiimoteInitialize g_WiimoteInitialize;
49 namespace WiiMoteReal
52 bool g_RealWiiMoteInitialized = false;
53 bool g_RealWiiMoteAllocated = false;
55 // Forwarding
57 class CWiiMote;
59 // Variable declarations
61 wiimote_t** g_WiiMotesFromWiiUse = NULL;
62 Common::Thread* g_pReadThread = NULL;
63 int g_NumberOfWiiMotes;
64 volatile int LastNumberOfWiimotes = 0;
65 CWiiMote* g_WiiMotes[MAX_WIIMOTES];
66 volatile bool g_Shutdown = false;
67 bool g_WiimoteInUse[MAX_WIIMOTES];
68 Common::Event NeedsConnect;
69 Common::Event Connected;
71 #if defined(_WIN32) && defined(HAVE_WIIUSE)
72 //Autopairup
73 Common::Thread* g_AutoPairUpInvisibleWindow = NULL;
74 Common::Thread* g_AutoPairUpMonitoring = NULL;
75 Common::Event g_StartAutopairThread;
77 int stoprefresh = 0;
78 unsigned int PairUpTimer = 2000;
80 int PairUpRefreshWiimote(bool addwiimote);
81 int PairUpFindNewSlot(void);
82 void ToggleEmulatorState(bool stop);
83 THREAD_RETURN PairUp_ThreadFunc(void* arg);
84 THREAD_RETURN RunInvisibleMessageWindow_ThreadFunc(void* arg);
85 #endif
87 THREAD_RETURN ReadWiimote_ThreadFunc(void* arg);
89 // Probably this class should be in its own file
91 class CWiiMote
93 public:
95 CWiiMote(u8 _WiimoteNumber, wiimote_t* _pWiimote)
96 : m_WiimoteNumber(_WiimoteNumber)
97 , m_channelID(0)
98 , m_pWiiMote(_pWiimote)
99 , m_pCriticalSection(NULL)
100 , m_LastReportValid(false)
102 m_pCriticalSection = new Common::CriticalSection();
104 //wiiuse_set_leds(m_pWiiMote, WIIMOTE_LED_4);
106 #ifdef _WIN32
107 // F|RES: i dunno if we really need this
108 //CancelIo(m_pWiiMote->dev_handle);
109 CancelIoEx(m_pWiiMote->dev_handle,NULL);
110 #endif
113 virtual ~CWiiMote()
115 delete m_pCriticalSection;
119 // Queue raw HID data from the core to the wiimote
120 void SendData(u16 _channelID, const u8* _pData, u32 _Size)
122 m_channelID = _channelID;
124 m_pCriticalSection->Enter();
126 SEvent WriteEvent;
127 memcpy(WriteEvent.m_PayLoad, _pData, _Size);
128 WriteEvent._Size = _Size;
129 m_EventWriteQueue.push(WriteEvent);
131 // Debugging
132 //std::string Temp = ArrayToString(WriteEvent.m_PayLoad, 28, 0, 30);
133 //DEBUG_LOG(WIIMOTE, "Wiimote Write:\n%s", Temp.c_str());
135 m_pCriticalSection->Leave();
139 /* Read and write data to the Wiimote */
140 void ReadData()
142 if (!m_channelID)
143 return;
145 m_pCriticalSection->Enter();
147 // Send data to the Wiimote
148 if (!m_EventWriteQueue.empty())
150 //DEBUG_LOG(WIIMOTE, "Writing data to the Wiimote");
151 SEvent& rEvent = m_EventWriteQueue.front();
152 wiiuse_io_write(m_pWiiMote, (byte*)rEvent.m_PayLoad, rEvent._Size);
153 #ifdef _WIN32
154 if (m_pWiiMote->event == WIIUSE_UNEXPECTED_DISCONNECT)
156 NOTICE_LOG(WIIMOTE, "wiiuse_io_write: unexpected disconnect. handle: %08x", m_pWiiMote->dev_handle);
158 #endif
159 m_EventWriteQueue.pop();
161 // InterruptDebugging(false, rEvent.m_PayLoad);
164 m_pCriticalSection->Leave();
167 // Read data from wiimote (but don't send it to the core, just filter and queue)
168 if (wiiuse_io_read(m_pWiiMote))
170 const byte* pBuffer = m_pWiiMote->event_buf;
171 // Check if we have a channel (connection) if so save the data...
172 if (m_channelID > 0)
174 m_pCriticalSection->Enter();
176 // Filter out data reports
177 if (pBuffer[1] >= 0x30)
179 // Copy Buffer to LastReport
180 memcpy(m_LastReport.m_PayLoad, pBuffer + 1, MAX_PAYLOAD - 1);
181 m_LastReportValid = true;
183 else
185 // Copy Buffer to ImportantEvent
186 SEvent ImportantEvent;
187 memcpy(ImportantEvent.m_PayLoad, pBuffer + 1, MAX_PAYLOAD - 1);
189 // Put it in the read queue right away
190 m_EventReadQueue.push(ImportantEvent);
192 m_pCriticalSection->Leave();
195 #ifdef _WIN32
196 else if (m_pWiiMote->event == WIIUSE_UNEXPECTED_DISCONNECT)
198 NOTICE_LOG(WIIMOTE, "wiiuse_io_read: unexpected disconnect. handle: %08x", m_pWiiMote->dev_handle);
200 #endif
204 // Send queued data to the core
205 void Update()
207 // Thread function
208 m_pCriticalSection->Enter();
210 if (m_EventReadQueue.empty())
212 // Send the data report
213 if (m_LastReportValid)
214 SendEvent(m_LastReport);
216 else
218 // Send a 0x20, 0x21 or 0x22 report
219 SendEvent(m_EventReadQueue.front());
220 m_EventReadQueue.pop();
223 m_pCriticalSection->Leave();
227 // Clear events
228 void ClearEvents()
230 while (!m_EventReadQueue.empty())
231 m_EventReadQueue.pop();
232 while (!m_EventWriteQueue.empty())
233 m_EventWriteQueue.pop();
236 private:
238 struct SEvent
240 SEvent()
242 memset(m_PayLoad, 0, MAX_PAYLOAD);
244 byte m_PayLoad[MAX_PAYLOAD];
245 u32 _Size;
247 typedef std::queue<SEvent> CEventQueue;
249 u8 m_WiimoteNumber; // Just for debugging
250 u16 m_channelID;
251 CEventQueue m_EventReadQueue; // Read from Wiimote
252 CEventQueue m_EventWriteQueue; // Write to Wiimote
253 SEvent m_LastReport;
254 wiimote_t* m_pWiiMote; // This is g_WiiMotesFromWiiUse[]
255 Common::CriticalSection* m_pCriticalSection;
256 bool m_LastReportValid;
258 // Send queued data to the core
259 void SendEvent(SEvent& _rEvent)
261 // We don't have an answer channel
262 if (m_channelID == 0)
263 return;
265 // Check event buffer
266 u8 Buffer[1024];
267 u32 Offset = 0;
268 hid_packet* pHidHeader = (hid_packet*)(Buffer + Offset);
269 pHidHeader->type = HID_TYPE_DATA;
270 pHidHeader->param = HID_PARAM_INPUT;
272 // Create the buffer
273 memcpy(&Buffer[Offset], pHidHeader, sizeof(hid_packet));
274 Offset += sizeof(hid_packet);
275 memcpy(&Buffer[Offset], _rEvent.m_PayLoad, sizeof(_rEvent.m_PayLoad));
276 Offset += sizeof(_rEvent.m_PayLoad);
278 // Send it
279 g_WiimoteInitialize.pWiimoteInterruptChannel(m_WiimoteNumber, m_channelID, Buffer, Offset);
281 // Debugging
282 // ReadDebugging(false, Buffer, Offset);
288 // Function Definitions
290 void SendAcc(u8 _ReportID)
292 byte DataAcc[MAX_PAYLOAD];
294 DataAcc[0] = 0x22; // Report 0x12
295 DataAcc[1] = 0x00; // Core buttons
296 DataAcc[2] = 0x00;
297 DataAcc[3] = _ReportID; // Reporting mode
299 for (int i = 0; i < g_NumberOfWiiMotes; i++)
300 wiiuse_io_write(WiiMoteReal::g_WiiMotesFromWiiUse[i], (byte*)DataAcc, MAX_PAYLOAD);
302 std::string Temp = ArrayToString(DataAcc, 28, 0, 30);
303 DEBUG_LOG(WIIMOTE, "SendAcc: %s", Temp.c_str());
305 //22 00 00 _reportID 00
308 // Clear any potential queued events
309 void ClearEvents()
311 for (int i = 0; i < g_NumberOfWiiMotes; i++)
312 if (g_WiimoteInUse[i])
313 g_WiiMotes[i]->ClearEvents();
316 // Flash lights, and if connecting, also rumble
317 void FlashLights(bool Connect)
320 for (int i = 0; i < g_NumberOfWiiMotes; i++)
322 if (Connect)
323 wiiuse_rumble(WiiMoteReal::g_WiiMotesFromWiiUse[i], 1);
325 SLEEP(200);
326 for (int i = 0; i < g_NumberOfWiiMotes; i++)
328 if (Connect) {
329 wiiuse_rumble(WiiMoteReal::g_WiiMotesFromWiiUse[i], 0);
330 wiiuse_set_leds(WiiMoteReal::g_WiiMotesFromWiiUse[i], WIIMOTE_LED_1 | WIIMOTE_LED_2 | WIIMOTE_LED_3 | WIIMOTE_LED_4);
332 else
333 wiiuse_set_leds(WiiMoteReal::g_WiiMotesFromWiiUse[i], WIIMOTE_LED_NONE);
337 int Initialize()
339 int i, wiimote_slots = 0;
341 // Return if already initialized
342 if (g_RealWiiMoteInitialized)
343 return g_NumberOfWiiMotes;
346 NeedsConnect.Init();
347 Connected.Init();
349 // Clear the wiimote classes
350 memset(g_WiiMotes, 0, sizeof(CWiiMote*) * MAX_WIIMOTES);
351 for (i = 0; i < MAX_WIIMOTES; i++)
352 g_WiimoteInUse[i] = false;
354 g_RealWiiMotePresent = false;
355 g_RealWiiMoteAllocated = false;
357 // Only call wiiuse_find with the number of slots configured for real wiimotes
358 for (i = 0; i < MAX_WIIMOTES; i++)
360 // Found a WiiMote (slot) that wants to be real :P
361 if (WiiMoteEmu::WiiMapping[i].Source == 2) {
362 wiimote_slots++;
366 // Don't bother initializing wiiuse if we don't want any real wiimotes
367 if (wiimote_slots < 1)
368 return 0;
370 // Call Wiiuse.dll
371 if(!g_WiiMotesFromWiiUse)
372 g_WiiMotesFromWiiUse = wiiuse_init(MAX_WIIMOTES);
374 #ifdef _WIN32
375 g_NumberOfWiiMotes = wiiuse_find(g_WiiMotesFromWiiUse, wiimote_slots, LastNumberOfWiimotes);
376 #else
377 g_NumberOfWiiMotes = wiiuse_find(g_WiiMotesFromWiiUse, wiimote_slots, 5); //move the timeout var into wiimote_t structure to avoid confusion
378 #endif
379 LastNumberOfWiimotes = g_NumberOfWiiMotes;
380 DEBUG_LOG(WIIMOTE, "Found No of Wiimotes: %i", g_NumberOfWiiMotes);
381 if (g_NumberOfWiiMotes > 0)
384 g_RealWiiMotePresent = true;
385 // Create a new thread for listening for Wiimote data
386 // and also connecting in Linux/OSX.
387 // Windows connects to Wiimote in the wiiuse_find function
388 g_pReadThread = new Common::Thread(ReadWiimote_ThreadFunc, NULL);
389 // Don't run the Wiimote thread if no wiimotes were found
390 g_Shutdown = false;
392 //Hack for OSX
393 NeedsConnect.Set();
394 Connected.Wait();
396 else
397 return 0;
399 for (i = 0; i < g_NumberOfWiiMotes; i++)
401 // Set the ir sensor sensitivity.
402 if (g_Config.iIRLevel) {
403 wiiuse_set_ir_sensitivity(g_WiiMotesFromWiiUse[i], g_Config.iIRLevel);
406 if (g_Config.bWiiReadTimeout != 30)
407 wiiuse_set_timeout(g_WiiMotesFromWiiUse, g_NumberOfWiiMotes, g_Config.bWiiReadTimeout);
409 // If we are connecting from the config window without a game running we set the LEDs
410 if (g_EmulatorState == PLUGIN_EMUSTATE_STOP && g_RealWiiMotePresent)
411 FlashLights(true);
413 // Initialized, even if we didn't find a Wiimote
414 g_RealWiiMoteInitialized = true;
416 return g_NumberOfWiiMotes;
419 // Allocate each Real WiiMote found to a WiiMote slot with Source set to "WiiMote Real"
420 void Allocate()
422 if (g_RealWiiMoteAllocated)// && (g_NumberOfWiiMotes == LastNumberOfWiimotes))
423 return;
424 if (!g_RealWiiMoteInitialized)
425 Initialize();
427 // Clear the wiimote classes
428 memset(g_WiiMotes, 0, sizeof(CWiiMote*) * MAX_WIIMOTES);
429 for (int i = 0; i < MAX_WIIMOTES; i++)
430 g_WiimoteInUse[i] = false;
432 g_Config.bNumberEmuWiimotes = g_Config.bNumberRealWiimotes = 0;
434 // Create Wiimote classes, one for each Real WiiMote found
435 int current_number = 0;
436 for (int i = 0; i < g_NumberOfWiiMotes; i++)
439 // Let's find out the slot this Real WiiMote will be using... We need this because the user can set any of the 4 WiiMotes as Real, Emulated or Inactive...
440 for (; current_number < MAX_WIIMOTES; current_number++)
442 // Just to be sure we won't be overlapping any WiiMote...
443 if (g_WiimoteInUse[current_number] == true)
444 continue;
445 if (WiiMoteEmu::WiiMapping[current_number].Source == 1)
446 g_Config.bNumberEmuWiimotes++;
447 // Found a WiiMote (slot) that wants to be real :P
448 else if (WiiMoteEmu::WiiMapping[current_number].Source == 2) {
449 g_Config.bNumberRealWiimotes++;
450 break;
453 // If we found a valid slot for this WiiMote...
454 if (current_number < MAX_WIIMOTES)
456 g_WiiMotes[current_number] = new CWiiMote(current_number, g_WiiMotesFromWiiUse[i]);
457 g_WiimoteInUse[current_number] = true;
458 switch (current_number)
460 case 0:
461 wiiuse_set_leds(g_WiiMotesFromWiiUse[i], WIIMOTE_LED_1);
462 break;
463 case 1:
464 wiiuse_set_leds(g_WiiMotesFromWiiUse[i], WIIMOTE_LED_2);
465 break;
466 case 2:
467 wiiuse_set_leds(g_WiiMotesFromWiiUse[i], WIIMOTE_LED_3);
468 break;
469 case 3:
470 wiiuse_set_leds(g_WiiMotesFromWiiUse[i], WIIMOTE_LED_4);
471 break;
472 default:
473 PanicAlert("Trying to create real wiimote %i WTF", current_number);
474 break;
476 DEBUG_LOG(WIIMOTE, "Real WiiMote allocated as WiiMote #%i", current_number);
480 // If there are more slots marked as "Real WiiMote" than the number of Real WiiMotes connected, disable them!
481 for(current_number++; current_number < MAX_WIIMOTES; current_number++)
483 if (WiiMoteEmu::WiiMapping[current_number].Source == 1)
484 g_Config.bNumberEmuWiimotes++;
485 else if (WiiMoteEmu::WiiMapping[current_number].Source == 2)
486 WiiMoteEmu::WiiMapping[current_number].Source = 0;
489 DEBUG_LOG(WIIMOTE, "Using %i Real Wiimote(s) and %i Emu Wiimote(s)", g_Config.bNumberRealWiimotes, g_Config.bNumberEmuWiimotes);
491 g_RealWiiMoteAllocated = true;
495 void DoState(PointerWrap &p)
497 //TODO: Implement
500 void Shutdown(void)
502 if (!g_RealWiiMoteInitialized)
503 return;
504 // Stop the loop in the thread
505 g_Shutdown = true; // not safe .. might crash when still @ReadWiimote
507 // Stop the thread
508 if (g_pReadThread != NULL)
510 delete g_pReadThread;
511 g_pReadThread = NULL;
514 // Delete the wiimotes
515 for (int i = 0; i < MAX_WIIMOTES; i++)
517 delete g_WiiMotes[i];
518 g_WiiMotes[i] = NULL;
521 // Flash flights
522 if (g_EmulatorState != PLUGIN_EMUSTATE_PLAY && g_RealWiiMotePresent)
523 FlashLights(false);
525 // Clean up wiiuse
526 #ifndef WIN32
527 wiiuse_cleanup(g_WiiMotesFromWiiUse, g_NumberOfWiiMotes);
528 g_WiiMotesFromWiiUse = NULL;
529 #endif
530 // Uninitialized
531 g_RealWiiMoteInitialized = false;
532 g_RealWiiMotePresent = false;
533 g_RealWiiMoteAllocated = false;
536 void InterruptChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size)
538 //DEBUG_LOG(WIIMOTE, "Real InterruptChannel on WiiMote #%i", _WiimoteNumber);
539 g_WiiMotes[_WiimoteNumber]->SendData(_channelID, (const u8*)_pData, _Size);
542 void ControlChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size)
544 //DEBUG_LOG(WIIMOTE, "Real ControlChannel on WiiMote #%i", _WiimoteNumber);
545 g_WiiMotes[_WiimoteNumber]->SendData(_channelID, (const u8*)_pData, _Size);
549 // Read the Wiimote once
550 void Update(int _WiimoteNumber)
552 //DEBUG_LOG(WIIMOTE, "Real Update on WiiMote #%i", _WiimoteNumber);
553 g_WiiMotes[_WiimoteNumber]->Update();
556 /* Continuously read the Wiimote status. However, the actual sending of data
557 occurs in Update(). If we are not currently using the real Wiimote we allow
558 the separate ReadWiimote() function to run. Wo don't use them at the same
559 time to avoid a potential collision. */
560 THREAD_RETURN ReadWiimote_ThreadFunc(void* arg)
562 NeedsConnect.Wait();
563 #ifndef _WIN32
564 int Connect;
565 // WiiUse initializes the Wiimotes in Windows right from the wiiuse_find function
566 // The Functionality should REALLY be changed
567 Connect = wiiuse_connect(g_WiiMotesFromWiiUse, MAX_WIIMOTES);
568 DEBUG_LOG(WIIMOTE, "Connected: %i", Connect);
569 #endif
570 Connected.Set();
572 while (!g_Shutdown)
574 // Usually, there is at least one Real Wiimote in use,
575 // except a wiimote gets disconnected unexpectly ingame or wiimote input type gets changed from real to none
577 if (g_Config.bNumberRealWiimotes > 0)
579 for (int i = 0; i < MAX_WIIMOTES; i++)
580 if (g_WiimoteInUse[i])
581 g_WiiMotes[i]->ReadData();
583 //else { idle }
587 return 0;
590 #ifdef WIN32
591 // WiiMote Pair-Up, function will return amount of either new paired or unpaired devices
592 int WiimotePairUp(bool unpair)
594 HANDLE hRadios[256];
595 int nRadios;
596 int nPaired = 0;
598 // Enumerate BT radios
599 HBLUETOOTH_RADIO_FIND hFindRadio;
600 BLUETOOTH_FIND_RADIO_PARAMS radioParam;
602 radioParam.dwSize = sizeof(BLUETOOTH_FIND_RADIO_PARAMS);
603 nRadios = 0;
605 hFindRadio = BluetoothFindFirstRadio(&radioParam, &hRadios[nRadios++]);
606 if (hFindRadio)
608 while (BluetoothFindNextRadio(&radioParam, &hRadios[nRadios++]));
609 BluetoothFindRadioClose(hFindRadio);
611 else
613 ERROR_LOG(WIIMOTE, "Pair-Up: Error enumerating radios", GetLastError());
614 return -1;
616 nRadios--;
617 DEBUG_LOG(WIIMOTE, "Pair-Up: Found %d radios\n", nRadios);
619 // Pair with Wii device(s)
620 int radio = 0;
622 for (radio = 0; radio < nRadios; radio++)
624 BLUETOOTH_RADIO_INFO radioInfo;
625 HBLUETOOTH_DEVICE_FIND hFind;
627 BLUETOOTH_DEVICE_INFO btdi;
628 BLUETOOTH_DEVICE_SEARCH_PARAMS srch;
630 radioInfo.dwSize = sizeof(radioInfo);
631 btdi.dwSize = sizeof(btdi);
632 srch.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
634 BluetoothGetRadioInfo(hRadios[radio], &radioInfo);
636 srch.fReturnAuthenticated = TRUE;
637 srch.fReturnRemembered = TRUE;
638 srch.fReturnConnected = TRUE; // does not filter properly somehow, so we 've to do an additional check on fConnected BT Devices
639 srch.fReturnUnknown = TRUE;
640 srch.fIssueInquiry = TRUE;
641 srch.cTimeoutMultiplier = 2;
642 srch.hRadio = hRadios[radio];
644 //DEBUG_LOG(WIIMOTE, "Pair-Up: Scanning for BT Device(s)");
646 hFind = BluetoothFindFirstDevice(&srch, &btdi);
648 if (hFind == NULL)
650 ERROR_LOG(WIIMOTE, "Pair-Up: Error enumerating devices: %08x", GetLastError());
651 return -1;
656 //btdi.szName is sometimes missings it's content - it's a bt feature..
658 DEBUG_LOG(WIIMOTE, "authed %i connected %i remembered %i ", btdi.fAuthenticated, btdi.fConnected, btdi.fRemembered);
660 if ((!wcscmp(btdi.szName, L"Nintendo RVL-WBC-01") || !wcscmp(btdi.szName, L"Nintendo RVL-CNT-01")) && !btdi.fConnected && !unpair)
662 //TODO: improve the read of the BT driver, esp. when batteries of the wiimote are removed while being fConnected
663 if (btdi.fRemembered)
665 // Make Windows forget old expired pairing
666 // we can pretty much ignore the return value here.
667 // it either worked (ERROR_SUCCESS), or the device did not exist (ERROR_NOT_FOUND)
668 // in both cases, there is nothing left.
669 BluetoothRemoveDevice(&btdi.Address);
672 // Activate service
673 DWORD hr = BluetoothSetServiceState(hRadios[radio], &btdi, &HumanInterfaceDeviceServiceClass_UUID, BLUETOOTH_SERVICE_ENABLE);
674 if (!hr == ERROR_SUCCESS)
676 nPaired++;
678 else
680 ERROR_LOG(WIIMOTE, "Pair-Up: BluetoothSetServiceState() returned %08x", hr);
683 else if ((!wcscmp(btdi.szName, L"Nintendo RVL-WBC-01") || !wcscmp(btdi.szName, L"Nintendo RVL-CNT-01")) && unpair)
686 BluetoothRemoveDevice(&btdi.Address);
687 NOTICE_LOG(WIIMOTE, "Pair-Up: Automatically removed BT Device on shutdown: %08x", GetLastError());
688 nPaired++;
691 } while (BluetoothFindNextDevice(hFind, &btdi));
692 BluetoothFindRadioClose(hFind);
695 SLEEP(10);
698 // Clean up
699 for (radio = 0; radio < nRadios; radio++)
701 CloseHandle(hRadios[radio]);
704 return nPaired;
707 #ifdef HAVE_WIIUSE
708 // Listening for new installed wiimotes, and calling PaiUpRefreshWiimote() when found
709 LRESULT CALLBACK CallBackDeviceChange(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
711 switch(uMsg)
714 case WM_DEVICECHANGE:
715 // DBT_DEVNODES_CHANGED 0x007 (devnodes are atm not received); DBT_DEVICEARRIVAL 0x8000 DBT_DEVICEREMOVECOMPLETE 0x8004 // avoiding header file^^
716 if ( ( wParam == 0x8000 || wParam == 0x8004 || wParam == 0x0007 ) )
718 if (wiiuse_check_system_notification(uMsg, wParam, lParam)) //extern wiiuse function: returns 1 if the event came from a wiimote
720 switch (wParam)
722 case 0x8000:
723 if (stoprefresh) // arrival will pop up twice //need to rewrite the stoprefresh thing, to support multiple pair ups in one go
725 stoprefresh = 0;
727 PairUpRefreshWiimote(true);
728 break;
730 else stoprefresh = 1; //fake arrival wait for second go
731 break;
733 case 0x8004:
734 if (!stoprefresh) // removal event will pop up only once (it will also pop up if we add a device: fake arrival, fake removal, real arrival.
736 PairUpRefreshWiimote(false);
738 break;
743 return DefWindowProc(hWnd, uMsg, wParam, lParam);
745 default:
746 return DefWindowProc(hWnd, uMsg, wParam, lParam);
749 return 0;
751 // Generating a new invisible message window and listening for new messages
752 THREAD_RETURN RunInvisibleMessageWindow_ThreadFunc(void* arg)
754 MSG Msg;
755 HWND hwnd;
756 BOOL ret;
758 WNDCLASSEX WCEx;
759 ZeroMemory(&WCEx, sizeof(WCEx));
760 WCEx.cbSize = sizeof(WCEx);
761 WCEx.lpfnWndProc = CallBackDeviceChange;
762 WCEx.hInstance = g_hInstance;
763 WCEx.lpszClassName = L"MSGWND";
765 if (RegisterClassEx(&WCEx) != 0)
767 hwnd = CreateWindowEx(0, WCEx.lpszClassName, NULL,0,
768 0, 0, 0, 0, HWND_MESSAGE, NULL, g_hInstance, NULL);
770 if (!hwnd) {
771 UnregisterClass(WCEx.lpszClassName, g_hInstance);
772 return 1;
776 wiiuse_register_system_notification(hwnd); //function moved into wiiuse to avoid ddk/wdk dependicies
778 while((ret = GetMessage(&Msg, 0, 0, 0)) != 0)
780 if ( ret == -1) {
781 return 1;
783 else {
784 TranslateMessage(&Msg);
785 DispatchMessage(&Msg);
789 UnregisterClass(WCEx.lpszClassName, g_hInstance);
791 return (int)Msg.wParam;
796 void ToggleEmulatorState(bool stop) {
797 PostMessage(GetParent((HWND)g_WiimoteInitialize.hWnd), WM_USER, WM_USER_PAUSE, 0);
798 if (stop) {
799 while (g_EmulatorState != PLUGIN_EMUSTATE_PLAY) Sleep(50);
801 else {
802 while (g_EmulatorState == PLUGIN_EMUSTATE_PLAY) Sleep(50);
807 // function gets called by windows callbacks if a wiimote was either installed or removed
808 int PairUpRefreshWiimote(bool addwiimote)
810 int connectslot = -1;
812 if (g_EmulatorState != PLUGIN_EMUSTATE_PLAY)
814 Shutdown();
815 if (addwiimote)
817 connectslot = PairUpFindNewSlot();
819 Initialize();
820 if (m_BasicConfigFrame != NULL)
821 m_BasicConfigFrame->UpdateGUI();
823 else {
825 ToggleEmulatorState(true);
826 Shutdown();
827 if (addwiimote)
829 connectslot = PairUpFindNewSlot();
831 Initialize();
832 Allocate();
833 ToggleEmulatorState(false);
834 if (addwiimote)
835 PostMessage(GetParent((HWND)g_WiimoteInitialize.hWnd), WM_USER, WM_USER_KEYDOWN, (3 + connectslot));
838 return 0;
840 // returns first inactive wiimote slot to place new wiimote and set type to real wiimote
841 int PairUpFindNewSlot() {
842 int realWM = 0;
843 for(int x=0; x<MAX_WIIMOTES; x++)
845 if (WiiMoteEmu::WiiMapping[x].Source == 0)
847 WiiMoteEmu::WiiMapping[x].Source = 2;
848 return x;
849 } else if (WiiMoteEmu::WiiMapping[x].Source == 2) {
850 realWM++;
851 if (realWM>g_NumberOfWiiMotes)
852 return x;
855 return -1;
857 // loop to poll and install new bluetooth devices; windows callback will take care of the rest on successful installation
858 THREAD_RETURN PairUp_ThreadFunc(void* arg)
860 Sleep(100); //small pause till the callback is registered on first start
861 DEBUG_LOG(WIIMOTE, "PairUp_ThreadFunc started.");
862 g_StartAutopairThread.Init();
863 int result;
865 while(1) {
866 if (g_Config.bPairRealWiimote) {
867 PairUpTimer = 2000;
868 result = g_StartAutopairThread.Wait(PairUpTimer);
870 else {
871 result = g_StartAutopairThread.Wait();
874 if (result)
875 WiimotePairUp(false);
876 else {
877 if (m_BasicConfigFrame != NULL)
878 m_BasicConfigFrame->UpdateBasicConfigDialog(false);
879 WiimotePairUp(false);
880 if (m_BasicConfigFrame != NULL)
881 m_BasicConfigFrame->UpdateBasicConfigDialog(true);
886 DEBUG_LOG(WIIMOTE, "PairUp_ThreadFunc terminated.");
887 return 0;
890 #endif
891 #endif
893 }; // end of namespace