物理キーボードに繋いだiPadでカーソル移動する

物理キーボードに繋いだiPadでカーソル移動する

2019/5/20

iPadOSではなく、iOSの話です

前提共有
Scrapboxの編集エリアは
contenteditableではない
目に見えるtextareaやinputは存在しない
その代わり、隠しtextareaが存在する
IMEでの日本語変換するために使っている
PCやAndroidではここで矢印キーのkey eventを監視している

これまでのiOSブラウザに関する調査
隠しtextareaにfocusが当たっている状態で、矢印キーを押すと
onKeyDown, onKeyPress, onKeyUp など、すべてeventが飛んでこない
隠さないtextareaを置いて試しても同様
→ onKeyXXX をソースとして矢印キーの押下を判定するのは無理

解決
既存の隠しtextareaに役割を一つ増やす
onselectionchangeもlistenする
textarea内の隠しテキストを工夫する
上下左右の移動を検出するため 2列 × 3行 の隠しテキストを用意し、常にカーソルを中央で待機させる

以下、詳説

onselectionchange とは
以下の事象が発生した時にeventを発行する
選択範囲が変わった時
カーソル位置が変わった時
selectionStart === selectionEnd である範囲選択の特殊な状態、と捉える
iOSでもしっかり発火された。これは使える daiizdaiiz


モードが2つ存在する
カーソル移動 (onselectionchange) を検知するモード
従来の隠しtextareaでの文字入力モード
モードごとに隠しtextareaが必要になる
モードの切り替えとして、適切なタイミングでfocusを移し合わないといけない
これはかなり難しく、絶対に安定しない


上のアイデアを改良した本手法でのミソ
隠しtextareaは、既存のもの1個でよい
focus移し合い問題がなくなった
モードの切り替え判定
onKeyDownを検知した時
→ 文字入力モード
実装に即した説明としては「カーソル移動検知モード OFF」
disableCursorMovementDetector()
(矢印キーが押された場合は絶対にevent来ない。来たらこんな苦労要らない。)
onFocus、入力確定、action完了した時
→ カーソル移動検知モード
resetAndEnableCursorMovementDetector()


各モードでの動作
文字入力モード
入力開始直後ならば、textarea内のテキストをクリア
他は従来どおり、変更なし

カーソル移動検知モード
textarea.selectionStart の値を取得して移動方向を判断する
移動方向を知るために、textarea内のテキストを \t\t\n\t\t\n\t\t にしてある
カーソルの初期位置を中央 (4) にしておき、移動検出のたびに4に戻すことで無限に検出できる
戻さない場合、4 → 1 に移動した以降は上方向を検出できなくなる
番号は textarea.selectionStart で取得できる値
得られた値に応じて Cursor.goUp, Cursor.goLeft, ... すればいい

操作動画撮った daiiz


今後 daiiz
個人的にはこの2つは対応したい
iPad × 物理キーボードで範囲選択する (リリース済み)
const shiftKey = textarea.selectionStart !== textarea.selectionEnd
const direction = (selectionStart === 4) ? selectionEnd : selectionStart
iPad × 物理キーボードで Ctrl+I する (リリース済み)
可能ならアウトライン編集も挑戦したい
便利ツールも作った
Powered by Helpfeel