625|0

20

帖子

8

TA的资源

一粒金砂(中级)

楼主
 

【DigiKey“智造万物,快乐不停”创意大赛】2,Pi400 HID 键盘功能的实现 [复制链接]

 

在github上有一个zero_hid的库,可以实现使用树莓派zero模拟hid键盘。但这个库有一些问题,直接使用在组合键上会出很多的问题,因此我参考这个项目,重写了一下这个库。

首先科普一下HID协议,HID键盘协议是一种基于报文的协议,通过在USB总线上进行通信。当用户按下键盘上的按键时,键盘将生成一个HID报文,并将其发送到计算机。计算机收到报文后,根据报文的内容来模拟相应的键盘操作,例如在文本编辑器中输入字符或执行特定的功能。

HID键盘报文包含多个字段,其中最重要的是按键码(Keycode)。按键码表示按下的键的唯一标识符,例如“A”键的按键码是0x04。除了按键码外,报文还可以包含其他信息,如修饰键(如Shift、Ctrl和Alt键)的状态和组合键的状态。

因此,在合成报文前,我们先要知道我们想输入的按键哪些是修饰键,而哪些是按键,他们要分开进行处理。

在进入代码部分前,我们需要先安装一下驱动。首先先新建一个文件,命名为isticktoit_usb,添加可执行权限,并填入以下内容:

···

#!/bin/bash

cd /sys/kernel/config/usb_gadget/

mkdir -p isticktoit

cd isticktoit

echo 0x1d6b > idVendor # Linux Foundation

echo 0x0104 > idProduct # Multifunction Composite Gadget

echo 0x0100 > bcdDevice # v1.0.0

echo 0x0200 > bcdUSB # USB2

mkdir -p strings/0x409

echo "fedcba9876543210" > strings/0x409/serialnumber

echo "Tobias Girstmair" > strings/0x409/manufacturer

echo "iSticktoit.net USB Device" > strings/0x409/product

mkdir -p configs/c.1/strings/0x409

echo "Config 1: ECM network" > configs/c.1/strings/0x409/configuration

echo 250 > configs/c.1/MaxPower



# Add functions here

mkdir -p functions/hid.usb0

echo 1 > functions/hid.usb0/protocol

echo 1 > functions/hid.usb0/subclass

echo 8 > functions/hid.usb0/report_length

echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > functions/hid.usb0/report_desc

ln -s functions/hid.usb0 configs/c.1/

# End functions



ls /sys/class/udc > UDC

···

接着运行以下命令,完成驱动配置:

···

#!/bin/bash

echo "" | sudo tee -a /boot/config.txt

echo "# BEGIN HID Keyboard Simulation" | sudo tee -a /boot/config.txt

echo "dtoverlay=dwc2" | sudo tee -a /boot/config.txt

echo "# END HID Keyboard Simulation" | sudo tee -a /boot/config.txt



echo "" | sudo tee -a /etc/modules

echo "# BEGIN HID Keyboard Simulation" | sudo tee -a /etc/modules

echo "dwc2" | sudo tee -a /etc/modules

echo "libcomposite" | sudo tee -a /etc/modules

echo "# END HID Keyboard Simulation" | sudo tee -a /etc/modules



# Move to before exit 0

echo "" | sudo tee -a /etc/rc.local

echo "# BEGIN HID Keyboard Simulation" | sudo tee -a /etc/rc.local

echo "sudo ./isticktoit_usb" | sudo tee -a /etc/rc.local

echo "# END HID Keyboard Simulation" | sudo tee -a /etc/rc.local

···

完成后,以后每次重启完成,只需要运行一下isticktoit_usb即可。

处理报文部分的代码如下:

···

from typing import List



from .hid import hidwrite

from .hid.keycodes import KeyCodes

from time import sleep

import json

import pkgutil

import os

import pathlib



class Keyboard:

   

    def __init__(self, dev='/dev/hidg0') -> None:

        self.dev = dev

        self.set_layout()

        self.control_pressed = []

        self.key_pressed = []

   

    def list_layout(self):

        keymaps_dir = pathlib.Path(__file__).parent.absolute() / 'keymaps'

        keymaps = os.listdir(keymaps_dir)

        files = [f for f in keymaps if f.endswith('.json')]

        for count, fname in enumerate(files, 1):

            with open(keymaps_dir / fname , encoding='UTF-8') as f:

                content = json.load(f)

                name, desc = content['Name'], content['Description']

            print(f'{count}. {name}: {desc}')

       

    def set_layout(self,  language='US'):

        self.layout = json.loads( pkgutil.get_data(__name__, f"keymaps/{language}.json").decode() )



    def gen_list(self, keys = []):

        _control_pressed = []

        _key_pressed = []

        for key in keys:

            if key[:3] == "MOD":

                _control_pressed.append(KeyCodes[key])

            else:

                _key_pressed.append(KeyCodes[key])

        return _control_pressed, _key_pressed

   

    def gen_buf(self):

        self.buf = [sum(self.control_pressed),0] + self.key_pressed

        self.buf += [0] * (8 - len(self.buf)) # fill to lenth 8



    ##########################################################################

    # For user

   

    def press(self, keys = [], additive=False, hold=False):

        _control_pressed, _key_pressed = self.gen_list(keys)

       

        if not additive:

            self.control_pressed = []

            self.key_pressed = []

           

        self.control_pressed.extend(_control_pressed)

        self.control_pressed = list(set(self.control_pressed)) # remove repeated items

        self.key_pressed.extend(_key_pressed)

        self.key_pressed = list(set(self.key_pressed))[:6] # remove repeated items and cut until 6 items

       

        self.gen_buf()

        hidwrite.write_to_hid_interface(self.dev, self.buf)

       

        if not hold:

            self.release(keys)

       

    def release(self, keys = []):

        _control_pressed, _key_pressed = self.gen_list(keys)

        try:

            self.control_pressed = list(set(self.control_pressed) - set(_control_pressed))

        except:

            pass

        try:

            self.key_pressed = list(set(self.key_pressed) - set(_key_pressed))

        except:

            pass

       

        self.gen_buf()

        hidwrite.write_to_hid_interface(self.dev, self.buf)

       

    def release_all(self):

        self.control_pressed = []

        self.key_pressed = []

       

        self.gen_buf()

        hidwrite.write_to_hid_interface(self.dev, self.buf)

   

    def text(self, string, delay=0):

            for c in string:

                key_map = self.layout['Mapping'][c]

                key_map = key_map[0]

                mods = key_map['Modifiers']

                keys = key_map['Keys']



                self.press(mods + keys)

                sleep(delay)

···

上面这段代码把想要输出的按键分为control(修饰按键)和key(普通按键)两块,再组合形成报文列表。使用的逻辑是输入当前想要按下的按键状态,然后程序发送对应的报文。

测试一下:

···

import os

import zero_hid

if os.geteuid() != 0:

    raise ImportError('You must be root to use this library on linux.')

k = zero_hid.Keyboard()

k.press(["KEY_H"], additive=False, hold=False)

k.press(["KEY_E"], additive=False, hold=False)

k.press(["KEY_L"], additive=False, hold=False)

k.press(["KEY_L"], additive=False, hold=False)

k.press(["KEY_O"], additive=False, hold=False)

···

press方法中填入的是一个list,表示当前按下的所有按键。具体的键值列表在zero_hid/keymaps/US.json中。

如果电脑成功打印,表示功能正常。

 

点赞 关注
 
 

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表