You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过C#蓝牙指令关闭Xbox Series手柄(WinForms .NET 4.7.2)

如何通过C#蓝牙指令关闭Xbox Series手柄(WinForms .NET 4.7.2)

我懂你现在的困扰——想在游戏退出时单独断开Xbox Series手柄,而不是关掉整个PC蓝牙,之前试了各种释放资源的方法都没效果对吧?你的思路其实非常对:当PC蓝牙关闭时,确实会给手柄发送一个明确的断开指令,我们完全可以模拟这个指令,而不是一刀切关掉蓝牙。我来帮你梳理下问题和可行的解决方案:

为什么你当前的代码没效果?

你现在的代码有两个核心问题:

  1. 设备类型选错了:你用的是BluetoothLEDevice(蓝牙低功耗设备),但Xbox Series手柄在蓝牙模式下,主要使用的是**经典蓝牙(BR/EDR)**而非BLE。用BLE的设备选择器可能根本找不到正确的设备实例,或者即使找到,也无法发送正确的断开指令。
  2. 单纯释放资源≠主动断开:你调用Dispose()和GC回收,只是释放了PC端的设备资源,但并没有给手柄发送主动断开的GATT指令。手柄会一直保持连接直到超时(通常15分钟左右),因为它没收到明确的断开信号。

修正方案1:用经典蓝牙API主动发送断开指令

我们先调整代码,使用经典蓝牙的API来获取设备,然后主动断开GATT会话,而不是单纯释放资源:

using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth;
using Windows.Devices.Enumeration;
using Windows.Devices.Bluetooth.GenericAttributeProfile;

private async Task TurnOffXboxController()
{
    // 用经典蓝牙的设备选择器,而非BLE
    string deviceSelector = BluetoothDevice.GetDeviceSelector();
    DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(deviceSelector);

    // 匹配Xbox手柄名称(部分手柄会带序列号后缀,建议用Contains而非严格Equals)
    var xboxControllerInfo = devices.FirstOrDefault(btDevice => 
        btDevice.Name != null && btDevice.Name.Contains("Xbox Wireless Controller"));

    if (xboxControllerInfo == null)
    {
        Console.WriteLine("未找到Xbox手柄");
        return;
    }

    // 获取经典蓝牙设备实例
    var xboxController = await BluetoothDevice.FromIdAsync(xboxControllerInfo.Id);
    if (xboxController == null)
    {
        Console.WriteLine("无法获取手柄设备权限,请检查蓝牙访问权限");
        return;
    }

    try
    {
        // 获取所有GATT服务
        var servicesResult = await xboxController.GetGattServicesAsync();
        if (servicesResult.Status != GattCommunicationStatus.Success)
        {
            Console.WriteLine("无法获取GATT服务");
            return;
        }

        // 遍历服务,主动断开GATT会话
        foreach (var service in servicesResult.Services)
        {
            if (service.Session != null)
            {
                // 发送主动断开指令
                service.Session.Disconnect();
                await Task.Delay(100); // 等待指令生效
            }
            service.Dispose();
        }

        // 监听连接状态变化,确认断开
        xboxController.ConnectionStatusChanged += (s, e) =>
        {
            if (xboxController.ConnectionStatus == BluetoothConnectionStatus.Disconnected)
            {
                Console.WriteLine("手柄已成功断开");
            }
        };
    }
    finally
    {
        xboxController.Dispose();
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}

注意事项:

  • 权限问题:如果打包成MSIX,需要在Package.appxmanifest中添加bluetooth和bluetooth.rfcomm权限;普通EXE则需确保用户有蓝牙设备的访问权限(可通过DeviceInformation.RequestAccessAsync主动请求)。
  • 设备名称匹配:部分手柄名称会带后缀(比如Xbox Wireless Controller (1234)),建议用Contains而非严格相等。

更可靠的方案2:通过HID指令直接控制手柄断开

Xbox手柄本质是HID设备,它支持特定的HID报告指令用来主动断开连接。这个方法比蓝牙API更直接,因为是手柄原生支持的指令:

using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.HumanInterfaceDevice;
using Windows.Storage.Streams;

private async Task TurnOffXboxControllerViaHID()
{
    // HID设备选择器:匹配Xbox的VID(固定为0x045E)和对应PID
    // 不同手柄PID不同:Series X/S是0x0B14,One S是0x0B13,旧款One是0x02E0
    string hidSelector = HidDevice.GetDeviceSelector(0x045E, 0x0B14);
    DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(hidSelector);

    var xboxControllerInfo = devices.FirstOrDefault();
    if (xboxControllerInfo == null)
    {
        // 尝试其他PID
        hidSelector = HidDevice.GetDeviceSelector(0x045E, 0x0B13);
        devices = await DeviceInformation.FindAllAsync(hidSelector);
        xboxControllerInfo = devices.FirstOrDefault();
    }

    if (xboxControllerInfo == null)
    {
        Console.WriteLine("未找到Xbox HID设备");
        return;
    }

    var hidDevice = await HidDevice.FromIdAsync(xboxControllerInfo.Id, FileAccessMode.ReadWrite);
    if (hidDevice == null)
    {
        Console.WriteLine("无法获取HID设备访问权限");
        return;
    }

    try
    {
        // Xbox手柄标准断开指令:报告ID 0x01,后跟7个0x00
        var report = new HidOutputReport(hidDevice, 0x01);
        using (var writer = new DataWriter(report.Data))
        {
            writer.WriteBytes(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
            await writer.StoreAsync();
        }

        // 发送断开指令
        var result = await hidDevice.SendOutputReportAsync(report);
        if (result.Status == HidSendReportStatus.Success)
        {
            Console.WriteLine("已发送断开指令,手柄将在1-2秒内关闭");
        }
    }
    finally
    {
        hidDevice.Dispose();
    }
}

说明:

  • VID/PID匹配:Xbox的厂商ID(VID)固定为0x045E,产品ID(PID)根据型号不同:Series X/S是0x0B14,One S是0x0B13,旧款One是0x02E0,可根据自己的手柄型号调整。
  • HID报告效果:发送该报告后,手柄会在1-2秒内断开连接,灯效完全关闭,和手动关闭手柄效果一致。

最后通用注意事项

  • 不管用哪种方法,都需要确保WinForms项目引用Windows Runtime API:可通过NuGet安装Microsoft.Windows.SDK.Contracts包(选择对应你的Windows 10版本的版本号,比如1903+选10.0.18362.0)。
  • 测试时需确保手柄处于蓝牙连接模式(而非Xbox无线适配器模式),适配器模式需使用Xbox专用API而非蓝牙/HID接口。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 10:34:30