Я пытаюсь написать программу, которая делает управление Wiimotes в паре с Windows намного проще и автоматизированнее. Программа использует WiimoteLib (который использует hidsdi.h и setupapi.h ) для подключения к устройствам Wiimote и 32 футов (использует Windows Bluetooth API ) для автоматического сопряжения / отключения устройств. Код для pairer / unpairer основан на Wiipair . На данный момент процесс немного неровный и медленный, но он работает. (Но только для одного Wiimote)
Проблема заключается в том, что мой модуль для сопряжения / отключения устройств Bluetooth не имеет информации о том, как определить, является ли устройство HID (используемое классом Wiimote) тем же устройством. Я хочу иметь возможность предупреждать класс Wiimote, если устройство Bluetooth было принудительно отключено или не подключено, чтобы оно могло изящно отключиться. И наоборот, я бы хотел, чтобы Wiimote предупредил pairer / unpairer, когда устройство HID отключено, так что устройство Bluetooth может быть опционально отключено (если вы планируете отключить Wiimote).
Если бы я хотел получить доступ только к одному Wiimote, то это не было бы большой проблемой, но я бы хотел иметь доступ к нескольким Wiimote и различать их, используя информацию HID и информацию Bluetooth. Я уже использую множество своих собственных P / Invoke для покрытия областей, в которых не хватает 32 футов, так что их использование больше не проблема.
Вот основной код моего pairer. (Хотя я не уверен, действительно ли это необходимо):
(Примечание: IsDiscoverable()
, ToPin()
и ToMacAddress()
- все методы расширения.)
// Once this is true, the Wiimote will
// attempt to connect to an HID device.
public bool IsAnyDeviceAvailable { get; private set; }
private void PairTask(CancellationToken token) {
// Setup automatic authentication
BluetoothWin32Authentication auth = new BluetoothWin32Authentication(OnHandleRequests);
while (!token.IsCancellationRequested)
PairLoop(token);
}
private void PairLoop(CancellationToken token) {
// Get a copy of known addresses since
// these are added to in another task.
BluetoothAddress[] addresses;
lock (knownAddresses)
addresses = KnownAddresses.ToArray();
bool available = false;
foreach (BluetoothAddress address in addresses) {
if (token.IsCancellationRequested)
return;
BluetoothDeviceInfo device = new BluetoothDeviceInfo(address);
if (device.Connected) {
if (!available && !IsAnyDeviceAvailable) {
lock (knownAddresses)
IsAnyDeviceAvailable = true;
}
available = true;
continue;
}
if (device.Remembered) {
RemoveDevice(device, token);
}
else if (device.IsDiscoverable() && !device.Authenticated) {
if (PairDevice(device, token, available))
available = true;
}
token.WaitHandle.WaitOne(500);
}
if (!available && IsAnyDeviceAvailable) {
Trace.WriteLine("No more devices connected");
lock (knownAddresses)
IsAnyDeviceAvailable = false;
}
}
private void RemoveDevice(BluetoothDeviceInfo device, CancellationToken token) {
token.WaitHandle.WaitOne(1000);
if (BluetoothSecurity.RemoveDevice(device.DeviceAddress)) {
Trace.WriteLine($"Wiimote removed: {device.DeviceAddress.ToMacAddress()}");
token.WaitHandle.WaitOne(2000);
}
}
private bool PairDevice(BluetoothDeviceInfo device, CancellationToken token,
bool available)
{
string pin = device.DeviceAddress.ToPin();
try {
if (BluetoothSecurity.PairRequest(device.DeviceAddress, pin)) {
Trace.WriteLine($"Wiimote authenticated: {device.DeviceAddress.ToMacAddress()}");
token.WaitHandle.WaitOne(1000);
// Calling this before and after seems to help unsure
// the device works when paired programmatically.
Guid[] services = device.InstalledServices;
device.SetServiceState(Uuids.HumanInterfaceDeviceServiceClass_UUID, true, true);
services = device.InstalledServices;
Trace.WriteLine($"Wiimote paired: {device.DeviceAddress.ToMacAddress()}");
token.WaitHandle.WaitOne(8000);
if (!available && !IsAnyDeviceAvailable) {
Trace.WriteLine("First device has been connected");
lock (knownAddresses)
IsAnyDeviceAvailable = true;
}
return true;
}
else {
Trace.WriteLine($"Wiimote authentication failed: {device.DeviceAddress.ToMacAddress()}");
}
}
catch {
Trace.WriteLine($"Wiimote pairing failed: {device.DeviceAddress.ToMacAddress()}");
}
return false;
}
private void OnHandleRequests(object sender, BluetoothWin32AuthenticationEventArgs e) {
e.Confirm = true;
}