【Ratatui】ショートカットキーを実装する!Ctrlキー等のコンボ入力

ratatuiで文字入力に加えて、コンボ処理を実装する方法を紹介します。

前回は文字を入力する方法を解説しましたが、それだけでは「保存」や「終了」などのコマンド操作が不便です。 今回は、Ctrl + Q で終了、Ctrl + S で保存といった、複数のキーを組み合わせる「コンボ入力(修飾キー)」の実装方法を紹介します。

前回 入力受付の実装:【Ratatui】Rustで作るTUIツール:ユーザーからの文字入力を受け取る(Input Formの実装)

1. 主要部分の実装例:matchガードを活用する

Rustの match 文には、条件を追加できる「ガード(if文をそのまま使える)」という機能があります。これを使って、Ctrlキーが押されているかどうかを判定します。

// イベント処理セクションの書き換え例
if let Event::Key(key) = event::read()? {
    if key.kind == KeyEventKind::Press {
        match key.code {
            // Ctrl + 'q' でプログラムを終了する
            KeyCode::Char('q') if key.modifiers.contains(event::KeyModifiers::CONTROL) => {
                break; 
            }
            
            // 通常の文字入力(Ctrlが押されていないときだけ反応させる)
            KeyCode::Char(c) if !key.modifiers.contains(event::KeyModifiers::CONTROL) => {
                input.push(c);
            }

            // Backspaceなどは前回同様なので略
            KeyCode::Backspace => { input.pop(); }
            
            _ => {}
        }
    }
}

2. 実装結果

このコードを適用すると、以下のような挙動になります。

  • q と打てば、画面に「q」と表示される。
  • Ctrl + Q を押すと、即座にプログラムが終了する。

これによって、「入力モード」と「コマンドモード」を切り替えなくても、自然なショートカット操作が可能になります。

ctrl + qなどのコンボ入力を実装し、q単体だと動かないことを検証

qは普通に打ち込むことができる

3. ちょこっと解説:modifiers(修飾キー)の仕組み

今回のコードのポイントを3つに絞って解説します。

key.modifiers とは?

event::read() で受け取った KeyEvent 構造体の中には、code(どのキーか)の他に、modifiers(どの修飾キーが一緒に押されているか)という情報が含まれています。

  • CONTROL: Ctrlキー
  • SHIFT: Shiftキー
  • ALT: Altキー

match ガード(if ...

match の枝に if を添えることで、「キーが ‘q’ である」かつ「Ctrlが含まれている」という複合的な条件を一行でスマートに記述できます。Rustらしい、安全で読みやすい書き方ですね。

③ なぜ「通常の入力」にもガードが必要なのか?

ここが重要なのですが、machはif elseifのような分岐処理ではないため、もし通常の文字入力側に if !key.modifiers.contains(...) を入れないと、Ctrl + Q を押したときに「終了処理」が走ると同時に、文字としての ‘q’ も入力欄に追加されてしまいます。

4. machgurdの書き方の例

今回実装したコンボは ctrlとのコンボですが、他のキーともコンボ入力の設定が可能です。修飾キー(Modifiers)を変えることで、さまざまな組み合わせに対応できます。

実装したいコンボmatch ガードの書き方
Ctrl + AKeyCode::Char('a') if key.modifiers.contains(event::KeyModifiers::CONTROL)
Alt + EnterKeyCode::Enter if key.modifiers.contains(event::KeyModifiers::ALT)
Shift + TabKeyCode::BackTab (※Tab + Shiftは専用のCodeが割り当てられることが多いです(環境に依る))

Tip: > KeyCode::Char('A') のように大文字で書く必要はありません。基本は小文字の 'a' を指定し、modifiersCONTROL が押されているかを判定するのが一般的です。

2. 複数の修飾キーを組み合わせる(Ctrl + Altなど)

「Ctrl と Alt を両方押しているとき」という複雑な判定も、ビット演算のようにチェックできます。

// Ctrl + Alt + S で「特別保存」のような処理
KeyCode::Char('s') if key.modifiers.contains(event::KeyModifiers::CONTROL | event::KeyModifiers::ALT) => {
    // 処理を書く
}

3. 特殊キーと修飾キーの組み合わせ

文字キー以外(矢印キーなど)と修飾キーを組み合わせると、一気に「本格的なソフト」っぽくなります。

match key.code {
    // Ctrl + 矢印右 で単語単位の移動
    KeyCode::Right if key.modifiers.contains(event::KeyModifiers::CONTROL) => {
        // カーソルを次の単語へ飛ばす処理など
    }

    // Shift + 矢印上 で範囲選択
    KeyCode::Up if key.modifiers.contains(event::KeyModifiers::SHIFT) => {
        // 選択範囲を広げる処理など
    }
    
    _ => {}
}

最後に

コンボ入力ができるようになると、Ctrl + C の強制終了を自前でハンドルしたり、Enter キーで入力を確定させたりと、作れるツールの幅が爆発的に広がります。

次回は、画面を分割して「入力欄」と「ログ表示欄」を作る、Layoutの実践編に挑戦しましょう!

分割レイアウトを作ってみる: 【Ratatui】画面を分割して「ツール」らしくする(Layout編)

ここまで読んでいただきありがとうございます。

では、次の記事で。 lumenHero