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
26 #include "StringUtil.h"
28 #include "pluginspecs_wiimote.h"
30 #include "wiimote_hid.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"
43 #include <BluetoothAPIs.h>
45 #pragma comment(lib, "Bthprops.lib")
47 extern SWiimoteInitialize g_WiimoteInitialize
;
52 bool g_RealWiiMoteInitialized
= false;
53 bool g_RealWiiMoteAllocated
= false;
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)
73 Common::Thread
* g_AutoPairUpInvisibleWindow
= NULL
;
74 Common::Thread
* g_AutoPairUpMonitoring
= NULL
;
75 Common::Event g_StartAutopairThread
;
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
);
87 THREAD_RETURN
ReadWiimote_ThreadFunc(void* arg
);
89 // Probably this class should be in its own file
95 CWiiMote(u8 _WiimoteNumber
, wiimote_t
* _pWiimote
)
96 : m_WiimoteNumber(_WiimoteNumber
)
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);
107 // F|RES: i dunno if we really need this
108 //CancelIo(m_pWiiMote->dev_handle);
109 CancelIoEx(m_pWiiMote
->dev_handle
,NULL
);
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();
127 memcpy(WriteEvent
.m_PayLoad
, _pData
, _Size
);
128 WriteEvent
._Size
= _Size
;
129 m_EventWriteQueue
.push(WriteEvent
);
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 */
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
);
154 if (m_pWiiMote
->event
== WIIUSE_UNEXPECTED_DISCONNECT
)
156 NOTICE_LOG(WIIMOTE
, "wiiuse_io_write: unexpected disconnect. handle: %08x", m_pWiiMote
->dev_handle
);
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...
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;
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();
196 else if (m_pWiiMote
->event
== WIIUSE_UNEXPECTED_DISCONNECT
)
198 NOTICE_LOG(WIIMOTE
, "wiiuse_io_read: unexpected disconnect. handle: %08x", m_pWiiMote
->dev_handle
);
204 // Send queued data to the core
208 m_pCriticalSection
->Enter();
210 if (m_EventReadQueue
.empty())
212 // Send the data report
213 if (m_LastReportValid
)
214 SendEvent(m_LastReport
);
218 // Send a 0x20, 0x21 or 0x22 report
219 SendEvent(m_EventReadQueue
.front());
220 m_EventReadQueue
.pop();
223 m_pCriticalSection
->Leave();
230 while (!m_EventReadQueue
.empty())
231 m_EventReadQueue
.pop();
232 while (!m_EventWriteQueue
.empty())
233 m_EventWriteQueue
.pop();
242 memset(m_PayLoad
, 0, MAX_PAYLOAD
);
244 byte m_PayLoad
[MAX_PAYLOAD
];
247 typedef std::queue
<SEvent
> CEventQueue
;
249 u8 m_WiimoteNumber
; // Just for debugging
251 CEventQueue m_EventReadQueue
; // Read from Wiimote
252 CEventQueue m_EventWriteQueue
; // Write to Wiimote
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)
265 // Check event buffer
268 hid_packet
* pHidHeader
= (hid_packet
*)(Buffer
+ Offset
);
269 pHidHeader
->type
= HID_TYPE_DATA
;
270 pHidHeader
->param
= HID_PARAM_INPUT
;
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
);
279 g_WiimoteInitialize
.pWiimoteInterruptChannel(m_WiimoteNumber
, m_channelID
, Buffer
, Offset
);
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
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
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
++)
323 wiiuse_rumble(WiiMoteReal::g_WiiMotesFromWiiUse
[i
], 1);
326 for (int i
= 0; i
< g_NumberOfWiiMotes
; i
++)
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
);
333 wiiuse_set_leds(WiiMoteReal::g_WiiMotesFromWiiUse
[i
], WIIMOTE_LED_NONE
);
339 int i
, wiimote_slots
= 0;
341 // Return if already initialized
342 if (g_RealWiiMoteInitialized
)
343 return g_NumberOfWiiMotes
;
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) {
366 // Don't bother initializing wiiuse if we don't want any real wiimotes
367 if (wiimote_slots
< 1)
371 if(!g_WiiMotesFromWiiUse
)
372 g_WiiMotesFromWiiUse
= wiiuse_init(MAX_WIIMOTES
);
375 g_NumberOfWiiMotes
= wiiuse_find(g_WiiMotesFromWiiUse
, wiimote_slots
, LastNumberOfWiimotes
);
377 g_NumberOfWiiMotes
= wiiuse_find(g_WiiMotesFromWiiUse
, wiimote_slots
, 5); //move the timeout var into wiimote_t structure to avoid confusion
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
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
)
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"
422 if (g_RealWiiMoteAllocated
)// && (g_NumberOfWiiMotes == LastNumberOfWiimotes))
424 if (!g_RealWiiMoteInitialized
)
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)
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
++;
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
)
461 wiiuse_set_leds(g_WiiMotesFromWiiUse
[i
], WIIMOTE_LED_1
);
464 wiiuse_set_leds(g_WiiMotesFromWiiUse
[i
], WIIMOTE_LED_2
);
467 wiiuse_set_leds(g_WiiMotesFromWiiUse
[i
], WIIMOTE_LED_3
);
470 wiiuse_set_leds(g_WiiMotesFromWiiUse
[i
], WIIMOTE_LED_4
);
473 PanicAlert("Trying to create real wiimote %i WTF", current_number
);
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
)
502 if (!g_RealWiiMoteInitialized
)
504 // Stop the loop in the thread
505 g_Shutdown
= true; // not safe .. might crash when still @ReadWiimote
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
;
522 if (g_EmulatorState
!= PLUGIN_EMUSTATE_PLAY
&& g_RealWiiMotePresent
)
527 wiiuse_cleanup(g_WiiMotesFromWiiUse
, g_NumberOfWiiMotes
);
528 g_WiiMotesFromWiiUse
= NULL
;
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
)
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
);
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();
591 // WiiMote Pair-Up, function will return amount of either new paired or unpaired devices
592 int WiimotePairUp(bool unpair
)
598 // Enumerate BT radios
599 HBLUETOOTH_RADIO_FIND hFindRadio
;
600 BLUETOOTH_FIND_RADIO_PARAMS radioParam
;
602 radioParam
.dwSize
= sizeof(BLUETOOTH_FIND_RADIO_PARAMS
);
605 hFindRadio
= BluetoothFindFirstRadio(&radioParam
, &hRadios
[nRadios
++]);
608 while (BluetoothFindNextRadio(&radioParam
, &hRadios
[nRadios
++]));
609 BluetoothFindRadioClose(hFindRadio
);
613 ERROR_LOG(WIIMOTE
, "Pair-Up: Error enumerating radios", GetLastError());
617 DEBUG_LOG(WIIMOTE
, "Pair-Up: Found %d radios\n", nRadios
);
619 // Pair with Wii device(s)
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
);
650 ERROR_LOG(WIIMOTE
, "Pair-Up: Error enumerating devices: %08x", GetLastError());
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
);
673 DWORD hr
= BluetoothSetServiceState(hRadios
[radio
], &btdi
, &HumanInterfaceDeviceServiceClass_UUID
, BLUETOOTH_SERVICE_ENABLE
);
674 if (!hr
== ERROR_SUCCESS
)
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());
691 } while (BluetoothFindNextDevice(hFind
, &btdi
));
692 BluetoothFindRadioClose(hFind
);
699 for (radio
= 0; radio
< nRadios
; radio
++)
701 CloseHandle(hRadios
[radio
]);
708 // Listening for new installed wiimotes, and calling PaiUpRefreshWiimote() when found
709 LRESULT CALLBACK
CallBackDeviceChange(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
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
723 if (stoprefresh
) // arrival will pop up twice //need to rewrite the stoprefresh thing, to support multiple pair ups in one go
727 PairUpRefreshWiimote(true);
730 else stoprefresh
= 1; //fake arrival wait for second go
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);
743 return DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);
746 return DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);
751 // Generating a new invisible message window and listening for new messages
752 THREAD_RETURN
RunInvisibleMessageWindow_ThreadFunc(void* arg
)
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
);
771 UnregisterClass(WCEx
.lpszClassName
, g_hInstance
);
776 wiiuse_register_system_notification(hwnd
); //function moved into wiiuse to avoid ddk/wdk dependicies
778 while((ret
= GetMessage(&Msg
, 0, 0, 0)) != 0)
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);
799 while (g_EmulatorState
!= PLUGIN_EMUSTATE_PLAY
) Sleep(50);
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
)
817 connectslot
= PairUpFindNewSlot();
820 if (m_BasicConfigFrame
!= NULL
)
821 m_BasicConfigFrame
->UpdateGUI();
825 ToggleEmulatorState(true);
829 connectslot
= PairUpFindNewSlot();
833 ToggleEmulatorState(false);
835 PostMessage(GetParent((HWND
)g_WiimoteInitialize
.hWnd
), WM_USER
, WM_USER_KEYDOWN
, (3 + connectslot
));
840 // returns first inactive wiimote slot to place new wiimote and set type to real wiimote
841 int PairUpFindNewSlot() {
843 for(int x
=0; x
<MAX_WIIMOTES
; x
++)
845 if (WiiMoteEmu::WiiMapping
[x
].Source
== 0)
847 WiiMoteEmu::WiiMapping
[x
].Source
= 2;
849 } else if (WiiMoteEmu::WiiMapping
[x
].Source
== 2) {
851 if (realWM
>g_NumberOfWiiMotes
)
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();
866 if (g_Config
.bPairRealWiimote
) {
868 result
= g_StartAutopairThread
.Wait(PairUpTimer
);
871 result
= g_StartAutopairThread
.Wait();
875 WiimotePairUp(false);
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.");
893 }; // end of namespace