1. 简介

WebHID API允许网页应用直接与HID(人机接口设备)进行通信。本教程将演示如何创建一个基础的WebHID应用,实现以下功能:

  • 显示和获取HID设备列表
  • 连接/断开HID设备
  • 读取设备数据
  • 向设备发送数据

在这里插入图片描述

2. 兼容性和前提条件

2.1 浏览器支持

  • 主要支持Chrome浏览器
  • 需要在安全上下文中运行(HTTPS或localhost)

2.2 权限要求

  • 需要用户明确授权才能访问HID设备
  • 某些操作系统可能需要额外的权限设置

3. 项目结构

项目包含两个主要文件:

├── index.html    // 页面结构和样式
└── hid-demo.js   // WebHID功能实现

在这里插入图片描述

4. 实现步骤

4.1 创建基础HTML结构

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>HID Device Communication</title>
  <style>
    #output {
      width: 100%;
      height: 200px;
      margin: 10px 0;
      padding: 5px;
      border: 1px solid #ccc;
      overflow-y: auto;
    }
    /* ... 其他样式 ... */
  </style>
</head>
<body>
  <h1>WebHID API 演示</h1>
  
  <button id="connectButton">连接新HID设备</button>
  
  <h2>已连接设备列表:</h2>
  <ul id="deviceList"></ul>
  
  <div class="input-group">
    <input type="text" id="sendData" placeholder="输入要发送的数据(用逗号分隔的数字)">
    <button id="sendButton">发送数据</button>
  </div>
  
  <h2>输出日志:</h2>
  <pre id="output"></pre>

  <script src="hid-demo.js"></script>
</body>
</html>

4.2 实现WebHID核心功能

4.2.1 初始化和获取设备列表
let currentDevice = null;

document.addEventListener('DOMContentLoaded', () => {
  // 获取已授权的设备
  navigator.hid.getDevices()
    .then(devices => {
      updateDeviceList(devices);
    })
    .catch(error => {
      console.error('Error getting devices:', error);
    });
});
4.2.2 连接新设备
document.getElementById('connectButton').addEventListener('click', async () => {
  try {
    const devices = await navigator.hid.requestDevice({
      filters: [] // 空过滤器显示所有设备
    });
    
    if (devices.length > 0) {
      updateDeviceList(devices);
    }
  } catch (error) {
    console.error('Error connecting to device:', error);
  }
});
4.2.3 设备连接/断开处理
async function toggleConnect(device) {
  try {
    if (device.opened) {
      await device.close();
      currentDevice = null;
      appendToOutput(`设备已断开: ${device.productName}`);
    } else {
      await device.open();
      currentDevice = device;
      appendToOutput(`设备已连接: ${device.productName}`);
      
      // 监听设备输入报告
      device.addEventListener('inputreport', event => {
        const {data, reportId} = event;
        const value = new Uint8Array(data.buffer);
        appendToOutput(`收到数据 (报告ID ${reportId}): ${Array.from(value)}`);
      });
    }
    
    // 刷新设备列表显示
    const devices = await navigator.hid.getDevices();
    updateDeviceList(devices);
  } catch (error) {
    console.error('Error toggling device connection:', error);
    appendToOutput(`操作失败: ${error.message}`);
  }
}
4.2.4 数据发送功能
document.getElementById('sendButton').addEventListener('click', async () => {
  if (!currentDevice || !currentDevice.opened) {
    alert('请先连接设备!');
    return;
  }

  const data = document.getElementById('sendData').value;
  try {
    const dataArray = new Uint8Array(data.split(',').map(x => parseInt(x.trim())));
    await currentDevice.sendReport(0, dataArray);
    appendToOutput('已发送数据: ' + data);
  } catch (error) {
    console.error('Error sending data:', error);
    appendToOutput('发送数据失败: ' + error.message);
  }
});

5. 使用说明

5.1 连接设备

  1. 点击"连接新HID设备"按钮
  2. 在弹出的系统对话框中选择要连接的设备
  3. 设备将显示在已连接设备列表中

5.2 数据收发

  1. 连接设备后,设备发送的数据会自动显示在输出日志中
  2. 在输入框中输入要发送的数据(格式:逗号分隔的数字,如 1,2,3,4
  3. 点击"发送数据"按钮发送数据

6. 注意事项

  1. 数据格式

    • 发送数据需要使用逗号分隔的数字格式
    • 不同设备可能需要特定的数据格式,请参考设备文档
  2. 报告ID

    • 当前示例使用默认报告ID (0)
    • 某些设备可能需要特定的报告ID,需要相应修改代码
  3. 错误处理

    • 所有操作都包含错误处理
    • 错误信息会显示在输出日志中
  4. 安全性

    • 必须在HTTPS或localhost环境下运行
    • 需要用户明确授权才能访问设备

7. 调试建议

  1. 使用Chrome开发者工具监控控制台输出
  2. 检查设备连接状态和错误信息
  3. 验证数据格式是否符合设备要求
  4. 确保设备驱动正确安装

8. 扩展建议

  1. 添加设备过滤器,只显示特定类型的设备
  2. 实现自定义数据格式转换
  3. 添加数据可视化功能
  4. 实现设备自动重连机制

9. 参考资源

完整Demo

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>HID Device Communication</title>
  <style>
    #output {
      width: 100%;
      height: 200px;
      margin: 10px 0;
      padding: 5px;
      border: 1px solid #ccc;
      overflow-y: auto;
    }
    #deviceList {
      margin: 10px 0;
    }
    #deviceList li {
      margin: 5px 0;
      padding: 5px;
      border: 1px solid #eee;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    .input-group {
      margin: 10px 0;
    }
  </style>
</head>
<body>
  <h1>WebHID API 演示</h1>
  
  <button id="connectButton">连接新HID设备</button>
  
  <h2>已连接设备列表:</h2>
  <ul id="deviceList"></ul>
  
  <div class="input-group">
    <input type="text" id="sendData" placeholder="输入要发送的数据(用逗号分隔的数字)">
    <button id="sendButton">发送数据</button>
  </div>
  
  <h2>输出日志:</h2>
  <pre id="output"></pre>

  <script src="hid-demo.js"></script>
</body>
</html>

let currentDevice = null;

document.addEventListener('DOMContentLoaded', () => {
  // 获取已授权的设备
  navigator.hid.getDevices()
    .then(devices => {
      updateDeviceList(devices);
    })
    .catch(error => {
      console.error('Error getting devices:', error);
    });

  // 连接新设备按钮事件
  document.getElementById('connectButton').addEventListener('click', async () => {
    try {
      // 请求连接HID设备
      const devices = await navigator.hid.requestDevice({
        filters: [] // 空过滤器显示所有设备
      });
      
      if (devices.length > 0) {
        updateDeviceList(devices);
      }
    } catch (error) {
      console.error('Error connecting to device:', error);
    }
  });

  // 发送数据按钮事件
  document.getElementById('sendButton').addEventListener('click', async () => {
    if (!currentDevice || !currentDevice.opened) {
      alert('请先连接设备!');
      return;
    }

    const data = document.getElementById('sendData').value;
    console.log('发送数据: ' + data);
    try {
      // 将输入数据转换为Uint8Array
      const dataArray = new Uint8Array(data.split(',').map(x => parseInt(x.trim())));
      await currentDevice.sendReport(5, dataArray);
      appendToOutput('已发送数据: ' + data);
      console.log('已发送数据: ' + data);
    } catch (error) {
      console.error('Error sending data:', error);
      appendToOutput('发送数据失败: ' + error.message);
    }
  });
});

// 更新设备列表显示
function updateDeviceList(devices) {
  const deviceList = document.getElementById('deviceList');
  deviceList.innerHTML = '';
  
  devices.forEach(device => {
    const li = document.createElement('li');
    li.textContent = `${device.productName} (VID: ${device.vendorId}, PID: ${device.productId})`;
    
    const connectBtn = document.createElement('button');
    connectBtn.textContent = device.opened ? '断开' : '连接';
    connectBtn.addEventListener('click', () => toggleConnect(device));
    
    li.appendChild(connectBtn);
    deviceList.appendChild(li);
  });
}

// 连接/断开设备
async function toggleConnect(device) {
  try {
    if (device.opened) {
      await device.close();
      currentDevice = null;
      appendToOutput(`设备已断开: ${device.productName}`);
    } else {
      await device.open();
      currentDevice = device;
      appendToOutput(`设备已连接: ${device.productName}`);
      
      // 监听设备输入报告
      device.addEventListener('inputreport', event => {
        const {data, reportId} = event;
        const value = new Uint8Array(data.buffer);
        appendToOutput(`收到数据 (报告ID ${reportId}): ${Array.from(value)}`);
      });
    }
    
    // 刷新设备列表显示
    const devices = await navigator.hid.getDevices();
    updateDeviceList(devices);
  } catch (error) {
    console.error('Error toggling device connection:', error);
    appendToOutput(`操作失败: ${error.message}`);
  }
}

// 添加输出信息
function appendToOutput(message) {
  const output = document.getElementById('output');
  output.textContent += message + '\n';
  output.scrollTop = output.scrollHeight;
}

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐