开发者集成文档

Player Community Integration Guide

HID定制协议 DLL Direct

高性能直驱方案,适用于宏盒子MINI。通过加载 DLL 即可直接接管物理鼠标控制流。

易语言声明示例:

================================================================
  hid.dll - HID鼠标控制 DLL
  易语言调用说明
================================================================

一、文件部署
-----------
将 hid.dll 复制到64位程序的 exe 同目录下。


二、DLL命令声明
--------------
在易语言中,新建一个"DLL命令"模块,添加以下声明:

┌─────────────────────────────────────────────────────────────┐
│ .版本 2                                                      │
│                                                              │
│ .DLL命令 MH_Open, 整数型, "hid.dll", "MH_Open"         │
│     '自动扫描并连接设备, 返回0=成功                            │
│                                                              │
│ .DLL命令 MH_Close, , "hid.dll", "MH_Close"             │
│     '断开设备                                                 │
│                                                              │
│ .DLL命令 MH_IsOpen, 整数型, "hid.dll", "MH_IsOpen"     │
│     '检查是否已连接, 返回1=已连接, 0=未连接                     │
│                                                              │
│ .DLL命令 MH_GetLastError, 整数型, "hid.dll", "MH_GetLastError" │
│     '返回错误信息字符串指针                                     │
│                                                              │
│ .DLL命令 MH_GetDeviceName, 整数型, "hid.dll", "MH_GetDeviceName" │
│     '返回设备名称字符串指针                                     │
│                                                              │
│ .DLL命令 MH_Ping, 整数型, "hid.dll", "MH_Ping"         │
│     .参数 版本缓冲区, 整数型                                   │
│     .参数 缓冲区大小, 整数型                                   │
│     '通信测试, 版本缓冲区传0则不获取版本                         │
│                                                              │
│ .DLL命令 MH_MouseMove, 整数型, "hid.dll", "MH_MouseMove" │
│     .参数 X位移, 整数型                                       │
│     .参数 Y位移, 整数型                                       │
│     '鼠标相对移动                                              │
│                                                              │
│ .DLL命令 MH_MouseButton, 整数型, "hid.dll", "MH_MouseButton" │
│     .参数 按键位图, 整数型                                     │
│     '按键控制: 1=左键 2=右键 4=中键 8=侧键1 16=侧键2, 0=全松开 │
│                                                              │
│ .DLL命令 MH_MouseClickLeft, 整数型, "hid.dll", "MH_MouseClickLeft" │
│     .参数 按住毫秒, 整数型                                     │
│     '左键点击, 传0则默认50ms                                    │
│                                                              │
│ .DLL命令 MH_MouseClickRight, 整数型, "hid.dll", "MH_MouseClickRight" │
│     .参数 按住毫秒, 整数型                                     │
│     '右键点击                                                  │
│                                                              │
│ .DLL命令 MH_MouseClickMiddle, 整数型, "hid.dll", "MH_MouseClickMiddle" │
│     .参数 按住毫秒, 整数型                                     │
│     '中键点击                                                  │
│                                                              │
│ .DLL命令 MH_MouseWheel, 整数型, "hid.dll", "MH_MouseWheel" │
│     .参数 滚轮值, 整数型                                       │
│     '滚轮: 正数=上滚, 负数=下滚, 范围-127~127                   │
│                                                              │
│ .DLL命令 MH_MouseAll, 整数型, "hid.dll", "MH_MouseAll"  │
│     .参数 按键位图, 整数型                                     │
│     .参数 X位移, 整数型                                       │
│     .参数 Y位移, 整数型                                       │
│     .参数 滚轮值, 整数型                                       │
│     '全参数控制: 一次性设置按键+移动+滚轮                        │
│                                                              │
│ .DLL命令 MH_MouseAutoMove, 整数型, "hid.dll", "MH_MouseAutoMove" │
│     .参数 步数, 整数型                                         │
│     .参数 X数组指针, 整数型                                    │
│     .参数 Y数组指针, 整数型                                    │
│     .参数 间隔毫秒, 整数型                                     │
│     '多步平滑移动, 最多10步                                     │
│                                                              │
│ .DLL命令 MH_MouseMoveClick, 整数型, "hid.dll", "MH_MouseMoveClick" │
│     .参数 X位移, 整数型                                       │
│     .参数 Y位移, 整数型                                       │
│     .参数 按住毫秒, 整数型                                     │
│     '移动后左键点击                                             │
│                                                              │
│ .DLL命令 MH_MonitorStart, 整数型, "hid.dll", "MH_MonitorStart" │
│     .参数 模式, 整数型                                         │
│     .参数 回调指针, 整数型                                     │
│     '启用按键监听: 模式1=仅按键, 2=按键+移动; 回调传0则用轮询    │
│                                                              │
│ .DLL命令 MH_MonitorStop, 整数型, "hid.dll", "MH_MonitorStop" │
│     '关闭按键监听                                              │
│                                                              │
│ .DLL命令 MH_PollButtonEvent, 整数型, "hid.dll", "MH_PollButtonEvent" │
│     .参数 按键状态, 整数型, 传址                                │
│     .参数 变化位, 整数型, 传址                                  │
│     .参数 按下位, 整数型, 传址                                  │
│     .参数 松开位, 整数型, 传址                                  │
│     '轮询按键事件, 返回1=有事件, 0=无事件                        │
└─────────────────────────────────────────────────────────────┘



三、常量定义
-----------
  返回码:
    0  = 成功
    -1 = 未找到设备
    -2 = 打开设备失败
    -3 = 设备未打开
    -4 = 发送失败
    -5 = 响应超时
    -6 = 参数错误

  按键位图:
    1  = 左键   (0x01)
    2  = 右键   (0x02)
    4  = 中键   (0x04)
    8  = 侧键1  (0x08)
    16 = 侧键2  (0x10)

  可以用"位或"组合多个按键, 例如: 1 + 2 = 同时按左键和右键


四、使用示例
-----------

【示例1: 基本使用】

  .子程序 测试鼠标控制
  .局部变量 结果, 整数型

  ' 连接设备
  结果 = MH_Open ()
  如果 (结果 ≠ 0)
      信息框 ("连接设备失败!", 0, )
      返回 ()
  如果结束

  ' 移动鼠标
  MH_MouseMove (100, 50)    ' 向右100, 向下50

  延时 (500)

  ' 左键点击
  MH_MouseClickLeft (0)     ' 默认50ms

  延时 (500)

  ' 右键点击
  MH_MouseClickRight (80)   ' 按住80ms

  延时 (500)

  ' 滚轮上滚
  MH_MouseWheel (3)

  ' 断开
  MH_Close ()


【示例2: 独立按键控制】

  ' 按下左键 (不松开)
  MH_MouseButton (1)

  延时 (1000)

  ' 同时按下左键+右键
  MH_MouseButton (1 + 2)

  延时 (500)

  ' 只松开左键, 保持右键
  MH_MouseButton (2)

  延时 (500)

  ' 全部松开
  MH_MouseButton (0)


【示例3: 移动+按键+滚轮 同时控制】

  ' 按住左键的同时移动并滚轮
  MH_MouseAll (1, 50, -30, 2)

  延时 (100)

  ' 松开所有
  MH_MouseAll (0, 0, 0, 0)


【示例4: 按键监听 (定时器轮询方式)】

  .子程序 启动监听
  MH_MonitorStart (1, 0)    ' 模式1, 不用回调
  时钟1.时钟周期 = 10       ' 10ms轮询

  .子程序 时钟1_周期事件
  .局部变量 按键, 整数型
  .局部变量 变化, 整数型
  .局部变量 按下, 整数型
  .局部变量 松开, 整数型

  如果 (MH_PollButtonEvent (按键, 变化, 按下, 松开) = 1)
      ' 有按键变化事件
      如果 (位与 (按下, 1) ≠ 0)
          ' 左键被按下
      如果结束
      如果 (位与 (松开, 2) ≠ 0)
          ' 右键被松开
      如果结束
  如果结束


五、编译 DLL
-----------
1. 安装 Visual Studio (需要 C/C++ 工具)
2. 双击运行 build.bat
3. 首次运行会自动下载 hidapi 源码 (需要 git)
4. 编译完成后 hid.dll 在当前目录

如果没有 git, 手动下载:
  https://github.com/libusb/hidapi/archive/refs/heads/master.zip
  解压后将 hidapi-master 文件夹重命名为 hidapi, 放到 dll 目录下


六、注意事项
-----------
1. DLL 为 64 位, 程序也必须是 64位
2. 设备必须已通过 USB 连接到电脑
3. 同一时间只能有一个程序打开该设备
4. MH_Open 会自动扫描并选择最匹配的设备 (接口2)
5. 所有移动命令都是相对位移, 不是绝对坐标
6. MH_MouseButton 发送的是完整按键状态, 不是增量
   例如: 先发 MH_MouseButton(1) 按下左键
         再发 MH_MouseButton(0) 松开左键
         不能发 MH_MouseButton(1) 然后 MH_MouseButton(2) 来"追加"右键
         应该发 MH_MouseButton(1+2) = MH_MouseButton(3)
网络协议 TCP/UDP

通过 IP 连接,支持强大的监控模式(Monitor)。可以监听物理鼠标状态并同步发送补偿指令。

鼠标状态检测与移动控制 :

'''

按住鼠标左键右下移动
按住鼠标右键左上移动

'''
import kmNet
import time
#连接盒子
ip='192.168.2.188'
port ='8888'
uuid ='1234abcd'
kmNet.init(ip,port,uuid)
print('连接盒子ok')
kmNet.monitor(12345)  # 开启物理键鼠监控功能。使用端口号12345接收物理键鼠数据
kmNet.mask_left(1)
kmNet.mask_right(1)
print('按下鼠标左键斜向下移动,按下鼠标右键斜向上移动,按下鼠标中键退出测试')
while 1:
    if kmNet.isdown_left() == 1:#如果鼠标左键按下
        print('left down')
        kmNet.move(1, 1)
    if kmNet.isdown_right() == 1:#如果鼠标右键按下
        print('right down')
        kmNet.move(-1, -1)
    if kmNet.isdown_middle() == 1:#如果鼠标中键按下
        print('exit')
        break
    time.sleep(0.01)  # 10ms移动一次

kmNet.monitor(0)  #关闭监控
kmNet.unmask_all()#解除所有屏蔽

基础移动任务 (鼠标移动任务.py):

import kmNet
import time
#连接盒子
ip='192.168.1.10'
port ='1000'
uuid ='25ABDBB2'
kmNet.init(ip,port,uuid)


time.sleep(3)
kmNet.left(1)
time.sleep(0.05)
kmNet.left(0)
time.sleep(0.05)
kmNet.right(1)
time.sleep(0.05)
kmNet.right(0)
time.sleep(0.05)

kmNet.enc_move_beizer(10,10,10,10,10,10,10)
time.sleep(0.05)
kmNet.enc_move_auto(10,10,10)
time.sleep(0.05)
kmNet.enc_move(10,10)
time.sleep(0.05)
kmNet.move(10,10)
time.sleep(0.05)
kmNet.move_auto(10,10,10)
time.sleep(0.05)
kmNet.move_beizer(10,10,10,10,10,10,10)
time.sleep(0.05)


串口协议 COM

基于标准串口通信。适用于通过 USB 直接连接电脑的应用场景。

按键映射与移动测试 (test_button_and_move.py):

import serial
import time

print('打开串口\n')
ser = serial.Serial('COM3', 115200, timeout=0.1)  # 添加超时
print('向kmbox发送 import km')
ser.write('import km\r\n'.encode('utf-8'))
time.sleep(0.1)
print('kmbox回码如下:', ser.read(ser.in_waiting or 1))

# ========== 配置 ==========
# 监听的按键: 'left' 左键, 'right' 右键, 'middle' 中键, 'side1' 侧键1, 'side2' 侧键2
BUTTON = 'middle'
MOVE_STEP = 1       # 每次移动的像素
MOVE_DELAY = 0.001  # 移动间隔时间(秒)
# ==========================

# 按键配置映射
BUTTON_CONFIG = {
    'left':   {'cmd': 'km.left()',   'name': '左键',   'dx': -MOVE_STEP, 'dy': -MOVE_STEP},
    'right':  {'cmd': 'km.right()',  'name': '右键',   'dx': MOVE_STEP,  'dy': MOVE_STEP},
    'middle': {'cmd': 'km.middle()', 'name': '中键',   'dx': 0,          'dy': -MOVE_STEP},
    'side1':  {'cmd': 'km.side1()',  'name': '侧键1',  'dx': -MOVE_STEP, 'dy': 0},
    'side2':  {'cmd': 'km.side2()',  'name': '侧键2',  'dx': MOVE_STEP,  'dy': 0},
}

config = BUTTON_CONFIG.get(BUTTON, BUTTON_CONFIG['right'])
BUTTON_CMD = config['cmd']
BUTTON_NAME = config['name']
MOVE_DX = config['dx']
MOVE_DY = config['dy']

def get_button_state():
    """发送命令并获取按钮状态,返回1表示按住,0表示松开,-1表示无效"""
    ser.write(f'{BUTTON_CMD}\r\n'.encode('utf-8'))
    time.sleep(0.01)  # 等待回码返回
    response = ser.read(ser.in_waiting or 1).decode('utf-8', errors='ignore').strip()
    print(f'{BUTTON_CMD} 回码: [{response}]')
    try:
        return int(response)
    except:
        return -1

def move_mouse():
    """移动鼠标"""
    ser.write(f'km.move({MOVE_DX},{MOVE_DY})\r\n'.encode('utf-8'))

# 按键状态
pressed = False

print(f'监听 {BUTTON_NAME},按 Ctrl+C 退出...')
try:
    while True:
        state = get_button_state()
        
        if state == 1:
            if not pressed:
                print(f'{BUTTON_NAME}按下 -> 开始移动')
            pressed = True
        elif state == 0:
            if pressed:
                print(f'{BUTTON_NAME}松开 -> 停止移动')
            pressed = False
        # state == -1 保持原状态
        
        if pressed:
            move_mouse()
        
        time.sleep(MOVE_DELAY)

except KeyboardInterrupt:
    print('\n退出程序')
finally:
    ser.close()
    print('串口已关闭')

点击测试 (test_left_click.py):

import serial
import time

# ========== 配置 ==========
# 测试的按键: 'left' 左键, 'right' 右键, 'middle' 中键, 'side1' 侧键1, 'side2' 侧键2
BUTTON = 'left'
HOLD_TIME = 5  # 按住时间(秒)
# ==========================

# 按键配置
BUTTONS = {
    'left':   {'press': 'km.left(1)',   'release': 'km.left(0)',   'name': '左键'},
    'right':  {'press': 'km.right(1)',  'release': 'km.right(0)',  'name': '右键'},
    'middle': {'press': 'km.middle(1)', 'release': 'km.middle(0)', 'name': '中键'},
    'side1':  {'press': 'km.side1(1)',  'release': 'km.side1(0)',  'name': '侧键1'},
    'side2':  {'press': 'km.side2(1)',  'release': 'km.side2(0)',  'name': '侧键2'},
}

def send_cmd(cmd):
    """发送命令并打印回码"""
    ser.write(f'{cmd}\r\n'.encode('utf-8'))
    time.sleep(0.01)
    response = ser.read(ser.in_waiting or 1).decode('utf-8', errors='ignore').strip()
    print(f'{cmd} 回码: [{response}]')
    return response

def test_button(button_key):
    """测试单个按键的按下和松开"""
    if button_key not in BUTTONS:
        print(f'未知按键: {button_key}')
        return
    
    btn = BUTTONS[button_key]
    print(f'\n===== 测试 {btn["name"]} =====')
    
    # 按下
    print(f'按下 {btn["name"]}...')
    send_cmd(btn['press'])
    
    # 保持
    print(f'保持 {HOLD_TIME} 秒...')
    time.sleep(HOLD_TIME)
    
    # 松开
    print(f'松开 {btn["name"]}...')
    send_cmd(btn['release'])
    print(f'{btn["name"]} 测试完成')

print('打开串口\n')
ser = serial.Serial('COM3', 115200, timeout=0.1)

print('向kmbox发送 import km')
ser.write('import km\r\n'.encode('utf-8'))
time.sleep(0.1)
print('kmbox回码如下:', ser.read(ser.in_waiting or 1))

# 测试指定按键
test_button(BUTTON)

# 如需测试所有按键,取消下面注释:
# for btn in ['left', 'right', 'middle', 'side1', 'side2']:
#     test_button(btn)
#     time.sleep(0.5)

ser.close()
print('\n串口已关闭')