蓝牙 Apple Magic Keyboard 的 Fn 键 (2015)

蓝牙 Apple Magic Keyboard 的 Fn 键 (2015)

我在使用时遇到问题苹果妙控键盘(蓝牙无线,带锂离子电池,用于充电和系留使用的闪电端口)与 Fedora 25(内核4.8.15-300.fc25.x86_64:)。

问题是,当在无线模式下使用时,Fn密钥似乎没有注册。我尝试过xev,该键本身不会触发任何事件,与另一个键一起按下的键也不会导致触发的事件与单独按下另一个键相比有任何不同。我想使用该键的原因Fn是因为我想分别将Fn+ /映射Home和 ,End并且还使用现在默认为功能键的多媒体键。

有趣的是,当我用闪电电缆将其连接到计算机时,该键盘充当普通的 Apple 有线键盘,我认为这是由于未使用蓝牙无线电并诉诸 USB 硬件/驱动程序(可能是通过注册的)与原装 Apple 铝制键盘不同的 USB 设备 ID,我没有验证)。这样做可以使用功能键以及您在互联网上找到的默认功能键或多媒体键等所有技巧。

但是,我希望将其用作蓝牙键盘时具有相同的功能。我会尽可能修补内核,但不知道从哪里开始以及如何测试和调试(显然我想首先尝试较少的“侵入性”手段)。

欢迎任何有关如何解决此问题的想法。

更新

当我读取时/dev/hidraw0,按下按键时我会得到一些活动Fn,所以这可能意味着fn按键已被系统注册,但在途中丢失了......

更新2

evtest按下该键时不显示任何事件Fn,并且/dev/input/event4(这是妙控键盘的事件设备)不会触发事件(其他键会触发事件)。所以我认为问题是Fn系统读取了密钥(通过/dev/hidraw0显示数据暗示),但它没有传递到/dev/input/event4.但这只是猜测,因为我不知道用户输入数据流在 Linux 中是如何工作的。

更新3

这是多次fn按键(按下+释放)产生的结果:

> sudo cat /dev/hidraw2 | hexdump
0000000 0001 0000 0000 0000 0000 0001 0000 0000
0000010 0000 0200 0001 0000 0000 0000 0000 0001
0000020 0000 0000 0000 0200 0001 0000 0000 0000
0000030 0000 0001 0000 0000 0000 0200 0001 0000
0000040 0000 0000 0000 0001 0000 0000 0000 0200
0000050 0001 0000 0000 0000 0000 0001 0000 0000
0000060 0000 0200 0001 0000 0000 0000 0000 0001
0000070 0000 0000 0000 0200 0001 0000 0000 0000
0000080 0000 0001 0000 0000 0000 0200 0001 0000
0000090 0000 0000 0000 0001 0000 0000 0000 0200
00000a0 0001 0000 0000 0000 0000 0001 0000 0000
00000b0 0000 0200 0001 0000 0000 0000 0000 0001
00000c0 0000 0000 0000 0200 0001 0000 0000 0000
00000d0 0000 0001 0000 0000 0000 0200 0001 0000
00000e0 0000 0000 0000 0001 0000 0000 0000 0200
00000f0 0001 0000 0000 0000 0000 0001 0000 0000
0000100 0000 0200 0001 0000 0000 0000 0000 0001
0000110 0000 0000 0000 0200 0001 0000 0000 0000
0000120 0000 0001 0000 0000 0000 0200 0001 0000
0000130 0000 0000 0000 0001 0000 0000 0000 0200
0000140 0001 0000 0000 0000 0000 0001 0000 0000
0000150 0000 0200 0001 0000 0000 0000 0000 0001
0000160 0000 0000 0000 0200 0001 0000 0000 0000
0000170 0000 0001 0000 0000 0000 0200 0001 0000
0000180 0000 0000 0000 0001 0000 0000 0000 0200
0000190 0001 0000 0000 0000 0000 0001 0000 0000
00001a0 0000 0200 0001 0000 0000 0000 0000 0001
00001b0 0000 0000 0000 0200 0001 0000 0000 0000
00001c0 0000 0001 0000 0000 0000 0200 0001 0000
00001d0 0000 0000 0000 0001 0000 0000 0000 0200
00001e0 0001 0000 0000 0000 0000 0001 0000 0000
00001f0 0000 0200 0001 0000 0000 0000 0000 0001
0000200 0000 0000 0000 0200 0001 0000 0000 0000
0000210 0000 0001 0000 0000 0000 0200 0001 0000
0000220 0000 0000 0000 0001 0000 0000 0000 0200
0000230 0001 0000 0000 0000 0000 0001 0000 0000

奇怪的是,release 后有时会打印 2 行,但大多数情况下会打印 1 行fn

F2Fn+分别如下所示F2

sudo cat /dev/hidraw2 | hexdump
0000000 0001 0000 0000 0000 0000 0001 3b00 0000
^[OQ0000010 0000 0000 0001 0000 0000 0000 0000 0001
^[OQ0000020 3b00 0000 0000 0000 0001 0000 0000 0000
^[OQ0000030 0000 0001 3b00 0000 0000 0000 0001 0000
0000040 0000 0000 0000 0001 3b00 0000 0000 0000
^[OQ0000050 0001 0000 0000 0000 0000 0001 3b00 0000
^[OQ0000060 0000 0000 0001 0000 0000 0000 0000 0001
^[OQ0000070 3b00 0000 0000 0000 0001 0000 0000 0000
0000080 0000 0101 0000 0000 0000 0000 0101 0600
^C

Fn+ F2:

> sudo cat /dev/hidraw2 | hexdump
0000000 0001 0000 0000 0000 0000 0001 0000 0000
^[OQ0000010 0000 0200 0001 3b00 0000 0000 0200 0001
0000020 0000 0000 0000 0200 0001 3b00 0000 0000
^[OQ0000030 0200 0001 0000 0000 0000 0200 0001 3b00
^[OQ0000040 0000 0000 0200 0001 0000 0000 0000 0200
^[OQ0000050 0001 3b00 0000 0000 0200 0001 0000 0000
^[OQ0000060 0000 0200 0001 3b00 0000 0000 0200 0001
0000070 0000 0000 0000 0200 0001 3b00 0000 0000
^[OQ0000080 0200 0001 0000 0000 0000 0200 0001 3b00
^[OQ0000090 0000 0000 0200 0001 0000 0000 0000 0200
^[OQ00000a0 0001 3b00 0000 0000 0200 0001 0000 0000
00000b0 0000 0200 0001 0000 0000 0000 0000 0101
00000c0 0000 0000 0000 0000 0101 0600 0000 0000
^C

更新4

根据 @dirkt 的要求,这里是报告描述符信息(我无法按照评论运行该行,所以这里是完整转储;另请注意,现在hidraw2我必须更换键盘):

> sudo ./hid-desc /dev/hidraw2
Report Descriptor Size: 171
Report Descriptor:
05 01 09 06 a1 01 85 01 05 07 15 00 25 01 19 e0 29 e7 75 01 95 08 81 02 95 05 75 01 05 08 19 01 29 05 91 02 95 01 75 03 91 03 95 08 75 01 15 00 25 01 06 00 ff 09 03 81 03 95 06 75 08 15 00 25 65 05 07 19 00 29 65 81 00 95 01 75 01 15 00 25 01 05 0c 09 b8 81 02 95 01 75 01 06 00 ff 09 03 81 02 95 01 75 06 81 03 06 02 ff 09 55 85 55 15 00 26 ff 00 75 08 95 40 b1 a2 c0 06 00 ff 09 14 a1 01 85 90 05 84 75 01 95 03 15 00 25 01 09 61 05 85 09 44 09 46 81 02 95 05 81 01 75 08 95 01 15 00 26 ff 00 09 65 81 02 c0 00 

Raw Name: Magic Keyboard
Raw Phys: 00:c2:c6:f7:eb:57
Raw Info:
    bustype: 5 (Bluetooth)
    vendor: 0x004c
    product: 0x0267

答案1

在上述提示的帮助下,我们能够创建一个补丁,使 Fn 键在通过蓝牙连接 Apple Magic Keyboard 键盘时起作用。

部分问题是 Magic Keyboard 显示的供应商 ID 为 0x004c(Apple 的蓝牙供应商 ID),而 hid-apple 只查找 0x05ac(Apple USB 供应商 ID),因此使用了 hid-generic 模块而不是 hid-apple。

第二个问题最初来自git 日志apple_input_mapping中的代码。hidinput_configure_usage

补丁发布在这里:https://bugzilla.kernel.org/show_bug.cgi?id=99881#c41

答案2

部分答案:了解 HID 基础设施和 HID 原始数据

(免责声明:我只针对 USB 完成了所有这些操作,但我认为它将以与蓝牙相同或类似的方式应用)。

HID 设备可以以明确定义的格式发送和接收报告。特定设备的格式由以下给出HID 描述符,对于 USB 而言,它与其他 USB 描述符非常相似(例如,lsusb如果未绑定,则可以列出它们)。详细信息(USB)可以在人机接口设备 (HID) 的设备类定义 PDF文档

可以找到 HID 的内核文档Documentation/hid。正如所hiddev.txt解释的,事件的数据流如下:

 usb.c --> hid-core.c --> hid-input.c --> input-subsystem

在 中drivers/hid/hid-input.c,特别是在例程 中hidinput_configure_usage,根据 HID 描述符解析报告。

因此,如果您看不到Fn钥匙,那就是出了问题的地方。

看到的输出hidraw0看起来很可疑,就像有几种具有不同 ID 的报告(此报告的 ID 为 1,普通键盘报告的 ID 为 0)。

但为了确保这一点,我们需要 HID 描述符。 HID 描述符可通过设备上的 ioctl 获得hidraw。例如,您可以使用https://github.com/DIGImend/usbhid-dump获取描述符(仅限 USB)并https://github.com/DIGImend/hidrd解析它。内核源代码中还有一个/samples/hidraw/hid-example.c文件展示了如何通过 ioctl 获取 HID 描述符;可以轻松修改它以生成类似于 的十六进制转储usbhid-dump。您必须将其用于蓝牙,所以我将其放在帕斯特宾。编译用make.

(如果您不习惯编译外部项目:下载两者的zip文件,将每个文件解压到一个空目录中,,,,./bootstrap./configure现在make您可以直接使用二进制文件,添加它们$PATH等)

现在您可以使用解析描述符

sudo ./hid-desc /dev/hidraw0 | tail -n+3 | head -1 | hidrd-convert -ihex -ospec

除了提供此输出(或十六进制转储,如果有任何功能不起作用)之外,请测试hidraw如果Fn与其他各种键(字母、箭头)组合按下会发生什么。还要测试正常按键时会发生什么。

如果无法使内核识别特殊报告,我不确定继续进行的最佳方法。也许最简单的方法是编写一个 C 程序来分析事件hidraw并生成额外的输入事件,类似于输入创建

更新:HID 描述符00末尾包含一个额外的内容。如果删除它,它会解析为

Usage Page (Desktop),                           ; Generic desktop controls (01h)
Usage (Keyboard),                               ; Keyboard (06h, application collection)
Collection (Application),
    Report ID (1),                      ; +00 report id
    Usage Page (Keyboard),                      ; Keyboard/keypad (07h)
    Logical Minimum (0),
    Logical Maximum (1),
    Usage Minimum (KB Leftcontrol),             ; Keyboard left control (E0h, dynamic value)
    Usage Maximum (KB Right GUI),               ; Keyboard right GUI (E7h, dynamic value)
    Report Size (1),
    Report Count (8),
    Input (Variable),                   ; +01 modifier
    Report Count (5),
    Report Size (1),
    Usage Page (LED),                           ; LEDs (08h)
    Usage Minimum (01h),
    Usage Maximum (05h),
    Output (Variable),
    Report Count (1),
    Report Size (3),
    Output (Constant, Variable),
    Report Count (8),
    Report Size (1),
    Logical Minimum (0),
    Logical Maximum (1),
    Usage Page (FF00h),                         ; FF00h, vendor-defined
    Usage (03h),
    Input (Constant, Variable),         ; +02 vendor
    Report Count (6),
    Report Size (8),
    Logical Minimum (0),
    Logical Maximum (101),
    Usage Page (Keyboard),                      ; Keyboard/keypad (07h)
    Usage Minimum (None),                       ; No event (00h, selector)
    Usage Maximum (KB Application),             ; Keyboard Application (65h, selector)
    Input,                              ; +03 6 keysym bytes
    Report Count (1),
    Report Size (1),
    Logical Minimum (0),
    Logical Maximum (1),
    Usage Page (Consumer),                      ; Consumer (0Ch)
    Usage (Eject),                              ; Eject (B8h, one-shot control)
    Input (Variable),                   : +09.0
    Report Count (1),
    Report Size (1),
    Usage Page (FF00h),                         ; FF00h, vendor-defined
    Usage (03h),
    Input (Variable),                   ; +09.1
    Report Count (1),
    Report Size (6),
    Input (Constant, Variable),         : +09.2-7
    Usage Page (FF02h),                         ; FF02h, vendor-defined
    Usage (55h),
    Report ID (85),
    Logical Minimum (0),
    Logical Maximum (255),
    Report Size (8),
    Report Count (64),
    Feature (Variable, No Preferred, Volatile),
End Collection,
Usage Page (FF00h),                             ; FF00h, vendor-defined
Usage (14h),
Collection (Application),
    Report ID (144),
    Usage Page (Power Device),                  ; Power device (84h, power page)
    Report Size (1),
    Report Count (3),
    Logical Minimum (0),
    Logical Maximum (1),
    Usage (61h),
    Usage Page (Power Batsys),                  ; Power battery system (85h, power page)
    Usage (44h),
    Usage (46h),
    Input (Variable),
    Report Count (5),
    Input (Constant),
    Report Size (8),
    Report Count (1),
    Logical Minimum (0),
    Logical Maximum (255),
    Usage (65h),
    Input (Variable),
End Collection

有一份 id hex 的输入事件报告01、一份 id hex 的电池状态报告90、一项用于照常设置 LED 的输出,以及一项供应商特定的功能控制。

我标记了输入事件报告的字节。有几个供应商定义的字段,我们不知道他们做什么,只能猜测。

输入事件报告由 10 个字节组成,您的示例解码如下:

ID MM VA K1 K2 K3 K4 K5 K6 VB

01 00 00 00 00 00 00 00 00 02  ; press? Fn 
01 00 00 00 00 00 00 00 00 00  ; release? Fn

01 00 00 3b 00 00 00 00 00 00  ; press F2
01 00 00 00 00 00 00 00 00 00  ; release

01 00 00 00 00 00 00 00 00 00  ;
01 00 00 00 00 00 00 00 00 02  ; press Fn?
01 00 00 3b 00 00 00 00 00 02  ; press F2
01 00 00 00 00 00 00 00 00 02  ; release F2 (but not Fn?)

ID就是报告吧。MM是标准的 8 个修饰符位,没有空间容纳Fn键。K1toK6最多可同时按下 6 个键。VA并且VB是特定于供应商的。假设您在上一个示例中按住Fn并刚刚按下并释放F2,我的猜测是位 1VB代表修饰符Fn(或至少与它相关的东西)。

用于hexdump -e '10/1 "%02X ""\n"'获取每行 9 个字节的输出,并通过Fn与多个键组合(包括您最终想要重新定义的组合)来测试此假设。

更新:为了完整性和将来的参考,尽管我认为它与这种特殊情况不再相关:可以使用 UHID 注入 HID 事件,请参阅Documentation/hid/uhid.txt内核samples/uhid/uhid-example.c

相关内容