【发布时间】:2018-06-28 21:29:46
【问题描述】:
我正在尝试编写一个程序,使与 Windows 配对的 Wiimotes 管理变得更加简单和自动化。程序使用WiimoteLib(使用hidsdi.h和setupapi.h)连接Wiimote设备,32feet(使用Windows Bluetooth API)自动配对/取消配对设备。配对器/取消配对器的代码基于Wiipair。目前,这个过程有点颠簸和缓慢,但它确实有效。 (但仅限于一个 Wiimote)
问题是我的蓝牙设备配对/取消配对模块没有关于如何识别 HID 设备(由 Wiimote 类使用)是否是同一设备的信息。如果蓝牙设备已被强制关闭或未配对,我希望能够提醒 Wiimote 类,以便它可以优雅地断开连接。反之亦然,我希望 Wiimote 在 HID 设备断开连接时提醒配对器/取消配对器,以便可以选择取消配对蓝牙设备(假设您计划关闭 Wiimote)。
如果我只想访问一个 Wiimote,那么这不是什么大问题,但我希望能够访问多个 Wiimote,并能够通过使用它们的 HID 信息和蓝牙信息来区分它们。我已经使用了大量我自己的 P/Invoke 来覆盖 32feet 缺乏的区域,因此再使用也不成问题。
这是我的配对器的主要代码。 (虽然我不确定是否真的有必要):
(注意: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;
}
【问题讨论】: