0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[後編(JIS配列対応)] Raspberry Pi Zero 2 W + gRPC + protobuf でターゲットPCに USB キーボード入力を送る

Last updated at Posted at 2025-01-08

前編・後編 (US配列) では、Raspberry Pi Zero 2 WUSB OTG ガジェットモードで「キーボード(HID)」として認識させ、ネットワーク経由で受け取ったテキストをターゲットPCへ入力する仕組みを構築しました。

しかし、前編・後編 (US配列) の実装例は主にUS配列ベースのマッピングだったため、日本語キーボード(JIS配列)を使う環境では記号の配置ズレIMEキーの扱いなど、追加の調整が必要になります。

本記事 続編(JIS配列対応) では、日本語(JIS)配列で使われるキーや記号を極力網羅したサンプルを紹介します。特に「無変換」「変換」「半角/全角」などのIME制御キーや、大文字入力(Shift)時の記号、Fキー・矢印キーなどもまとめています。環境によってはそのまま動作しないキーもあるため、参考にしながら調整いただければ幸いです。


前提

  • Raspberry Pi Zero 2 W で USB ガジェットモードを有効にし、/dev/hidg0 へ書き込みできる状態 (前編・後編参照)。
  • ターゲットPC の OS が **「日本語キーボード(106/109キー)として認識している」**こと。
    • Windows: デバイスマネージャやキーボード設定で「日本語キーボード」と認識されているか確認
    • Linux/Mac: XKB設定やシステム設定で jp106/JIS配列になっていること
  • Python でスクリプトを動かせる環境が整っている(例: Raspberry Pi OS)。

なぜJIS配列だと難しい?

  • US配列 に比べて、記号キーの配置が複雑かつ、OS依存要素が多いため。
  • 日本語IMEsでの「半角/全角キー」「無変換/変換キー」の扱いが統一されていない。
  • JIS配列のキーコードOSが期待する配列 がずれると、入力結果が変わってしまう。
  • 特に「円記号(\¥)」や「Shift + 数字キー記号」のマッピングは環境によっては異なります。

サンプル実装例 (改良版)

以下のコードは、JIS配列+IME制御キーも含め、できる限り広く対応するためのサンプルです。

  • 大文字 (A–Z) を入力する際は、自動的に Shift + 対応する小文字 を送信します。
  • Shiftが必要な記号 (例: !, " , #, (, ), など) もマッピング済み。
  • IMEキー (半角/全角, 無変換, 変換, カタカナ/ひらがな) も追加しています。
  • Fキー・矢印キー などは JIS/US共通 なので、同じUsage IDを使用しています。
import time

#
# 修飾キーのビット定義 (modifier)
#
MOD_LCTRL   = 0x01
MOD_LSHIFT  = 0x02
MOD_LALT    = 0x04
MOD_LGUI    = 0x08
MOD_RCTRL   = 0x10
MOD_RSHIFT  = 0x20
MOD_RALT    = 0x40
MOD_RGUI    = 0x80

#
# JIS配列で「Shift不要」の文字(英小文字・数字・一部記号など)
#
KEYMAP_JIS = {
    # --- 英小文字 ---
    'a': 0x04, 'b': 0x05, 'c': 0x06, 'd': 0x07,
    'e': 0x08, 'f': 0x09, 'g': 0x0A, 'h': 0x0B,
    'i': 0x0C, 'j': 0x0D, 'k': 0x0E, 'l': 0x0F,
    'm': 0x10, 'n': 0x11, 'o': 0x12, 'p': 0x13,
    'q': 0x14, 'r': 0x15, 's': 0x16, 't': 0x17,
    'u': 0x18, 'v': 0x19, 'w': 0x1A, 'x': 0x1B,
    'y': 0x1C, 'z': 0x1D,

    # --- 数字 (Shift不要) ---
    '1': 0x1E, '2': 0x1F, '3': 0x20, '4': 0x21,
    '5': 0x22, '6': 0x23, '7': 0x24, '8': 0x25,
    '9': 0x26, '0': 0x27,

    # --- 制御・空白系 ---
    '\n': 0x28,      # Enter
    '\r': 0x28,      # Enter(別表現)
    '\t': 0x2B,      # Tab
    ' ': 0x2C,       # Space
    '\b': 0x2A,      # Backspace
    '\x1b': 0x29,    # ESC (ASCII 0x1B)

    # --- JIS配列での「そのまま」記号 ---
    '-': 0x2D,   # '-'
    '^': 0x2E,   # '^'
    '@': 0x2F,   # '@'
    '[': 0x30,   # '['
    ']': 0x31,   # ']' (実際のキーボード刻印では省略されがち)
    ';': 0x33,   # ';'
    ':': 0x34,   # ':'
    ',': 0x36,   # ','
    '.': 0x37,   # '.'
    '/': 0x38,   # '/'

    # --- 円記号/バックスラッシュ問題 ---
    #   環境によって円記号が 0x31 や 0x89 など異なる実装がある。
    #   ここでは便宜上 '\' を 0x31, '¥' を 0x89 にしてみる。
    '\\': 0x31,  # バックスラッシュ(US配列で']'位置相当)
    '¥': 0x89,   # Keyboard International3 などを使う例
}

#
# JIS配列で「Shiftが必要」な記号
# (例: '!' は Shift + '1', '"' は Shift + '2' 等)
#
SHIFTKEYMAP_JIS = {
    '!': 0x1E,  # Shift + '1'
    '"': 0x1F,  # Shift + '2'
    '#': 0x20,  # Shift + '3'
    '$': 0x21,  # Shift + '4'
    '%': 0x22,  # Shift + '5'
    '&': 0x23,  # Shift + '6'
    '\'': 0x24, # Shift + '7' => アポストロフィ
    '(': 0x25,  # Shift + '8'
    ')': 0x26,  # Shift + '9'
    '=': 0x2D,  # Shift + '-'
    '~': 0x2E,  # Shift + '^'
    '`': 0x2F,  # Shift + '@' (バッククォート)
    '{': 0x30,  # Shift + '['
    '+': 0x33,  # Shift + ';'
    '*': 0x34,  # Shift + ':'
    '<': 0x36,  # Shift + ','
    '>': 0x37,  # Shift + '.'
    '?': 0x38,  # Shift + '/'
    '|': 0x89,  # Shift + '¥' (例: '|')
}

#
# 日本語特有キー (IME切替など)
# 実際に機能するかは OS&IME設定次第
#
SPECIAL_KEYS_JIS = {
    "HANKAKU_ZENKAKU": 0x35,  # 半角/全角キー(IME ON/OFF)の例
    "MUHENKAN":       0x88,   # 無変換
    "HENKAN":         0x8A,   # 変換
    "KATAHIRA":       0x90,   # カタカナ/ひらがな
}

#
# Fキー、矢印キーなど (JIS/US共通)
#
FUNCTION_KEYS = {
    "F1": 0x3A, "F2": 0x3B, "F3": 0x3C, "F4": 0x3D,
    "F5": 0x3E, "F6": 0x3F, "F7": 0x40, "F8": 0x41,
    "F9": 0x42, "F10": 0x43, "F11": 0x44, "F12": 0x45,

    "PRINT_SCREEN": 0x46,
    "SCROLL_LOCK":  0x47,
    "PAUSE":        0x48,

    "INSERT":       0x49, "HOME":       0x4A, "PAGE_UP":    0x4B,
    "DELETE":       0x4C, "END":        0x4D, "PAGE_DOWN":  0x4E,
    "RIGHT_ARROW":  0x4F, "LEFT_ARROW": 0x50,
    "DOWN_ARROW":   0x51, "UP_ARROW":   0x52,
}

def convert_jis_key(ch: str) -> tuple[int,int]:
    """
    1文字/特殊キー名を受け取り、(modifier, usage_id) を返す。
    usage_id=0 は押下なしとみなす。
    """

    # --- 大文字A-Z => Shift + 小文字キー
    if 'A' <= ch <= 'Z':
        keycode = KEYMAP_JIS.get(ch.lower(), 0)
        if keycode != 0:
            return (MOD_LSHIFT, keycode)
        else:
            return (0, 0)

    # --- 小文字/数字/記号(Shift不要)
    if ch in KEYMAP_JIS:
        return (0, KEYMAP_JIS[ch])

    # --- Shift必須記号
    if ch in SHIFTKEYMAP_JIS:
        return (MOD_LSHIFT, SHIFTKEYMAP_JIS[ch])

    # --- 日本語特有キー
    if ch in SPECIAL_KEYS_JIS:
        return (0, SPECIAL_KEYS_JIS[ch])

    # --- Fキー・矢印・他特殊キー
    if ch in FUNCTION_KEYS:
        return (0, FUNCTION_KEYS[ch])

    # --- 未定義
    return (0, 0)

def make_report(modifier: int, usage_id: int) -> bytes:
    """
    8バイトのHIDレポートを組み立てる。
    [modifier, 0x00, usage_id, 0x00, 0x00, 0x00, 0x00, 0x00]
    """
    return bytes([modifier, 0x00, usage_id, 0x00, 0x00, 0x00, 0x00, 0x00])

def send_jis_keys(sequence):
    """
    引数 sequence は:
      - 文字列("Hello!\n")なら1文字ずつ処理
      - リスト(["F1","LEFT_ARROW","HANKAKU_ZENKAKU"])なら各要素を1キーとみなす
    """
    if isinstance(sequence, str):
        items = list(sequence)
    else:
        items = sequence

    with open("/dev/hidg0", "wb") as f:
        for ch in items:
            mod, usage = convert_jis_key(ch)
            if usage != 0:
                # 押下
                f.write(make_report(mod, usage))
                time.sleep(0.01)
                # 離す
                f.write(make_report(0, 0))
                time.sleep(0.01)

使用例

# 例1: 通常の文字列送信
send_jis_keys("Hello, World!\n")

# 例2: 半角/全角キーでIME ON/OFFトグルを試す
send_jis_keys(["HANKAKU_ZENKAKU"])

# 例3: 大文字+記号などを混在
send_jis_keys("ABC!@#(JIS)\n")

# 例4: Fキーや矢印キー
send_jis_keys(["F1", "LEFT_ARROW", "RIGHT_ARROW"])

IME周りの動作について

  • 半角/全角 (HANKAKU_ZENKAKU)
    • WindowsではIMEのON/OFFトグルとして働くことが多いですが、設定やIMEによっては動作が異なる場合もあります。
  • 無変換 / 変換 / カタカナ/ひらがな
    • OS・IMEによって挙動はまちまち。全く反応しないIMEもあれば、変換モードを切り替えるIMEも。
  • IMEでの日本語入力
    • "あいうえお" のように 直接全角文字を送る ことはできません。キーボードはあくまでキー押下イベントを送るため、最終的に文字を確定するのはOS側のIMEです。

Fキー、矢印キー、Home/End/Insert/Delete

  • これらは JIS/US配列に依存しないUsage ID を使います。
  • 多くの場合、そのまま正常に動作しますが、一部キー(ScrollLockなど)が期待通りに動かない例もあります。
  • 必要に応じて OS側の設定やキーマッピングを確認してください。

よくある質問

  1. 「¥」が入力できない / 「\」になってしまう

    • Windows日本語環境では、ASCII 0x5C(バックスラッシュ) をフォント上「円記号」で表示する仕様があり混乱しがち。
    • キーコードレベルとフォント表示が一致しない例も多いので、レジストリやIMEの設定を調整する場合があります。
  2. 大文字や記号が合わない

    • ターゲットPC側が US配列 として認識している可能性。必ず JIS配列(106/109キー) になっているか確認してください。
  3. IMEキー(無変換/変換/カタカナ/ひらがな等)が効かない

    • IMEの設定で無効化されている / 別のキー割り当てになっている可能性があります。
    • WindowsやLinuxのIME設定を見直してみてください。
  4. Unicode文字や絵文字を入力したい

    • キー入力レベルではASCIIやJP106配列の範囲しか送れません。絵文字や特殊文字は、OS側のIMEやソフトウェアで入力対応している必要があります。

まとめ

  • JIS配列 で記号や大文字入力、IME制御キーまで幅広くカバーするには、相応のマッピング辞書が必要です。
  • 本記事のサンプルコードでは「Shift記号」や「大文字(A–Z)」も考慮した改良版マップを用意しています。
  • ただし、OSやIME、キーボード固有の違いによって挙動が変わる場合があるため、自環境に合わせて微調整 してください。
  • Raspberry Pi Zero 2 W を USBキーボードとしてエミュレートし、遠隔で入力する用途などにぜひ活用してみてください。

参考リンク


以上

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?