序言

在我使用 Ayn Thor 安装 Rocknix 后,我发现这个系统没有全局的屏幕键盘,这样产生了很多不便,比如 Ayn Thor Linux(Rocknix) 的安装和折腾过程 中提到的,游戏里打不了字完全无法创建角色的问题。

效果

方法

首先先看看 Rocknix 上有哪些屏幕键盘,无敌的 Gemini 告诉我说,可以试试 wvkbd 或者 wvkbd-mobintl

我们 SSH 上去看看

SM8550:~ # wvkbd-mobintl
Initializing keyboard
Found 54 layouts
Found 2 layers
Resize 1920x120 1.000000, 55 layouts

看来成功拉起来了,那现在问题是想办法给它拉到副屏上去,这样比较优雅,毕竟我使用的是神奇的双屏掌机嘛。

首先,确认一下双屏的屏幕名称

SM8550:~ # swaymsg -t get_outputs
Output DSI-2 'Unknown Unknown Unknown' (focused)
  Current mode: 1080x1920 @ 120.000 Hz
  Power: on
  Position: 0,0
  Scale factor: 1.000000
  Scale filter: nearest
  Subpixel hinting: unknown
  Transform: 90
  Workspace: 1
  Max render time: off
  Adaptive sync: disabled
  Allow tearing: yes
  Available modes:
    1080x1920 @ 120.000 Hz
    1080x1920 @ 60.000 Hz

Output DSI-1 'Unknown Unknown Unknown'
  Current mode: 1080x1240 @ 59.999 Hz
  Power: on
  Position: 1920,0
  Scale factor: 1.000000
  Scale filter: nearest
  Subpixel hinting: unknown
  Transform: 90
  Workspace: 2
  Max render time: off
  Adaptive sync: disabled
  Allow tearing: no
  Available modes:
    1080x1240 @ 59.999 Hz

看分辨率,显然 DSI-1 就是副屏了,我们尝试在副屏拉起键盘,并且调整一下键盘高度,让它好看点。

SM8550:~ # wvkbd-mobintl --output DSI-1 -L 500
wvkbd: preferred output set to: "DSI-1"
wvkbd: assigned preferred output to: DSI-1
Initializing keyboard
Found 54 layouts
Found 2 layers
Resize 1240x500 1.000000, 55 layouts

看起来很顺利,成功拉起来了键盘,此时其实已经可以去游戏里测试一下了,打开游戏,在 SSH 中拉起键盘,这时候键盘已经可以打字了,但是这样太不优雅了,我不能每次玩游戏都带个电脑运行命令拉起键盘吧,那我接个 USB 键盘可能还更快点。

我得想办法给键盘做个快捷键,这样就可以在游戏中用快捷键触发了,在这之前,需要先抓到快捷键的键值,我是想用 home + back (就是机器下面那两个小的按键),我们运行 evtest 选择 Xbox 控制器,之后分别按下两个键看看输出。

Event: time 1777096805.111927, type 1 (EV_KEY), code 316 (BTN_MODE), value 1

Event: time 1777096805.111927, -------------- SYN_REPORT ------------

Event: time 1777096805.278486, type 1 (EV_KEY), code 316 (BTN_MODE), value 0

Event: time 1777096805.278486, -------------- SYN_REPORT ------------

Event: time 1777096806.467924, type 1 (EV_KEY), code 167 (KEY_RECORD), value 1

Event: time 1777096806.467924, -------------- SYN_REPORT ------------

Event: time 1777096806.612957, type 1 (EV_KEY), code 167 (KEY_RECORD), value 0

Event: time 1777096806.612957, -------------- SYN_REPORT ------------

很明确了,键值一个 316 一个 167,可惜 Rocknix 使用的 Sway 并不支持这种没有修饰键的按键组合触发,所以我们需要自己做一个脚本来实现这个功能。

先找一下 Sway 的 sock 放在哪里

SM8550:~ # find /run /var/run -name "sway-ipc*.sock" 2>/dev/null
/run/0-runtime-dir/sway-ipc.0.sock

之后我们用一个 python 脚本来实现我们想要的功能 (Rocknix 预装了 python ,我们并不用引入其他东西)

#!/usr/bin/env python3
import struct
import subprocess
import time
import os
import glob
import sys

# Format: time_sec, time_usec, type, code, value
FORMAT = 'iiHHi' if struct.calcsize('l') == 4 else 'llHHi'
EVENT_SIZE = struct.calcsize(FORMAT)

# Keycodes
BTN_MODE = 316
KEY_RECORD = 167
CONFIRMED_SWAYSOCK = "/run/0-runtime-dir/sway-ipc.0.sock"

def log(msg):
    """Compact logging: writes message and flushes immediately without extra newlines."""
    sys.stdout.write(f"{msg}\n")
    sys.stdout.flush()

def get_gamepad_device():
    """Scan all input devices to find the Xbox controller dynamically."""
    for dev in glob.glob('/dev/input/event*'):
        try:
            with open(f'/sys/class/input/{os.path.basename(dev)}/device/name', 'r') as f:
                name = f.read().strip()
                if "Xbox" in name:
                    return dev
        except:
            continue
    return None

def setup_wayland_env():
    """Inject required Sway environment variables."""
    os.environ['SWAYSOCK'] = CONFIRMED_SWAYSOCK
    os.environ['XDG_RUNTIME_DIR'] = "/run/0-runtime-dir"
    os.environ['WAYLAND_DISPLAY'] = "wayland-1"

def toggle_keyboard():
    log("Combo triggered. Toggling keyboard.")
    setup_wayland_env()
    check_proc = subprocess.run(['pgrep', '-x', 'wvkbd-mobintl'], stdout=subprocess.DEVNULL)
    if check_proc.returncode == 0:
        log("Keyboard running. Killing...")
        subprocess.run(['killall', 'wvkbd-mobintl'])
    else:
        log("Keyboard not running. Launching...")
        try:
            subprocess.Popen(['swaymsg', 'exec', 'wvkbd-mobintl --output DSI-1 -L 500'])
        except Exception as e:
            log(f"Launch error: {e}")

def main():
    mode_held = False
    log("Service starting...")

    while True:
        device_path = get_gamepad_device()
        if not device_path:
            log("Searching for Xbox controller...")
            time.sleep(3)
            continue

        try:
            with open(device_path, 'rb') as f:
                log(f"Success: Hooked into {device_path}")
                while True:
                    event = f.read(EVENT_SIZE)
                    if len(event) == EVENT_SIZE:
                        _, _, ev_type, ev_code, ev_value = struct.unpack(FORMAT, event)
                        if ev_type == 1:
                            if ev_code == BTN_MODE:
                                mode_held = (ev_value == 1)
                            elif ev_code == KEY_RECORD and ev_value == 1:
                                if mode_held:
                                    toggle_keyboard()
        except Exception as e:
            log(f"Device error or lost: {e}. Re-scanning...")
            time.sleep(3)

if __name__ == '__main__':
    main()

我把这个脚本存储为 /storage/scripts/Smart_Listener.py,此时,在 SSH 中执行脚本,我们已经能做到使用快捷键拉起副屏键盘了。

之后我们需要使用 systemd 来做开机自启动,新建一个文件 /storage/.config/system.d/kb-combo.service 写入以下内容

[Unit]
Description=Keyboard Combo Listener
After=multi-user.target

[Service]
ExecStart=/usr/bin/python3 /storage/scripts/Smart_Listener.py
Restart=always
RestartSec=5
User=root

[Install]
WantedBy=multi-user.target

接下来素质三连,完成我们的配置。

systemctl daemon-reload
systemctl enable kb-combo.service
systemctl start kb-combo.service