Flutter で低レベルのキーボード入力を取得する

Flutter

Flutter で低レベルのキーボード入力(押されたキーやキーのアップ/ダウン、キーコードなど)を取得する方法について解説します。

※ macOS デスクトップアプリでのみ動作を確認しています。

スポンサーリンク

RawKeyboardListener

低レベルのキー入力を取得する場合は、RawKeyboardListener ウィジェットを使います。このウィジェットで囲った中の child: 以下に配置したウィジェットにフォーカスが当たるとリスナーが機能するようになっています。

var _controller = TextEditingController();
var _focusNode = FocusNode();

RawKeyboardListener(
  focusNode: _focusNode,
  onKey: (event) {
    setState(() {
      print(event.logicalKey.debugName);
    });
  },
  child: TextField(
    // ↓はenterが押された時の動作を「何もしない」に指定しています(デフォルトだとフォーカスが外れるため)
    textInputAction: TextInputAction.none,
    controller: _controller,
  ),
),

上記のコードで TextField に文字を入力すると、以下のように押されたキーがコンソールに表示されると思います。

同じキーが2回表示されていますが、これはキーのダウンイベントアップイベントがそれぞれ発生しているからです。(キーのアップ/ダウン判別は後述します)

RawKeyEvent(キー入力インベント)

onKey: (event) {} に渡ってくるデータは RawKeyEvent です。

関数で書くとこんな感じです。

// キーイベントハンドリング用関数
void _handleKeyEvent(RawKeyEvent event) {
  setState(() {
    print(event.logicalKey.debugName);
  });
}

// RawKeyboardListener での関指定は以下
onKey: _handleKeyEvent,

キーダウンイベント/キーアップイベントの判定

キーのイベントがダウンイベントなのかアップイベントか判定する場合は、RawKeyEvent のサブクラスの型をチェックします。

// キーダウン
if(event is RawKeyDownEvent){
  print('KeyDown : ${event.logicalKey.debugName}');
}
// キーアップ
if(event is RawKeyUpEvent){
  print('KeyUp : ${event.logicalKey.debugName}');
}

入力文字/文字コードの取得

入力文字や文字コードを取得したい場合は、RawKeyEventData のサブクラスをチェックします。

// 論理キーオブジェクトの値を参照
String c = event.logicalKey.keyLabel; //入力された文字(String)
int code = event.logicalKey.keyId; // 文字コード

// 又は、プラットフォームを見て処理する場合
if (event.data is RawKeyEventDataMacOs) { // macOSの場合
  final RawKeyEventDataMacOs d = event.data;
  String c = d.keyLabel;
  int code = d.keyCode;
}

RawKeyEventData のサブクラスは以下が定義されていますが、動作はコメントのとおりです。

RawKeyEventDataAndroid // シミュレーターでは取れなかった
RawKeyEventDataFuchsia // 未確認
RawKeyEventDataLinux // 未確認
RawKeyEventDataMacOs // 動作している
RawKeyEventDataWeb // 2020年2月時点で動作していない

その他

リスナーの登録

Focus と TextEditController のリスナーもついでに書いておきます。

var _controller = TextEditingController();
var _focusNode = FocusNode();

// TextFieldの入力内容が変更された時に呼ばれる
void _handleTextField() {
  // なんか処理書く
  print(_controller.text);
}

// フォーカスが変更された時に呼ばれる
void _handleFocus(){
  // なんか処理書く
  print('${_focusNode.hasFocus}');
}

// ウィジェットの初期化時にリスナーを登録
@override
void initState() {
  super.initState();
  _focusNode.addListener(_handleFocus);
  _controller.addListener(_handleTextField);
}

強制的にフォーカスを当てる方法

特定のウィジェットに強制的にフォーカスを当てたい場合は以下のようします。

FocusScope.of(context).requestFocus(_focusNode);

コメント

タイトルとURLをコピーしました