#author("2026-09-17T10:50:05+09:00","","") #author("2026-09-19T10:41:04+09:00","","") * keyevent Event class [#q9b401c0] KeyEvent |name|type|desc| |source|KeyEventSource|発生源 "on_key" | "keymap" | "undefined"| |type|KeyEventType|"click" | "repeat" | "tap"| |ng_repeat|boolean|誤判定の可能性あり| |key|string|押されたkey ex. "j" ( "gj" の対応は未定 )| |prev_key|string|直前に押されたキー(なければ"")| |time|integer|発生経過時間(ms)| |interval|integer|前回key eventからの経過時間(最初のkey evetの場合はvimが起動してからevent発生までの経過時間)(ms)| |nt|integer|同一キー連打回数。1から始まる。| |nr|integer|hold中に発生したrepeat回数。1から始まる。type="repeat"以外では0| |hold_start|integer|hold開始時間| 廃止した項目と理由 - vim_count : rush.nvim などで独自に取得する ** key, meta parse : <C-j> -> ctrl + j [#p7bbd846] - 1文字の場合、小文字にしてkeyにセット、大文字の場合shift_maskをmetaにセット - <?>場合、?を取り出して上記処理をする - <(?-)*?>場合、全部小文字にする、最後の?をkeyにセット、"?-"の?はKEY_EVENT_META_MASKを使ってmetaにセット - その他、そのままkeyにセット ** key, meta unparse : ctrl + j -> <C-j> [#i30d6e81] - すべて <(?-)*?> 形式にする。大文字の場合も"S"をつける * KeyEvent取得方法 [#pca00764] ** keymap.set 関数で取得 [#y96e2628] keymap.set 関数内でKeyEvent.keymap_event(typed) の戻り値で取得 ** keymap.on_key 関数で取得 [#gd019f79] keymap.on_keyでcall back関数を設定して取得。詳細は未定 * アルゴリズム [#r821090f] ** interval type (内部関数) [#y408fb72] - is_hold : config.hold1 <= event.interval <= config.hold2 - is_repeat : config.rep1 <= event.interval <= config.rep2 - is_tap : config.use_tap and event.interval <= config.tap - is_hold, is_repeat は範囲が重なる場合、両方成立する場合がある ** no_hold | hold state (内部変数) [#c0da6b3b] - 状態マシンでno_hold, hold の状態を取る - キーを押しっぱなしの状態がhold, そうでない場合no_holdとする - ただしこれは推定なので実際の物理的状態を正確には反映しない - また判定のタイミングは遅れるため最初のキーダウンがhold開始かどうかの判定は次のキー入力まで保留され、リアルタイムではわからない そのアルゴリズム - 最初はno_hold stateとする - no_hold stateでevent.key == event.prev_key and is_hold が発生したらhold stateに移る - hold stateでevent.key != envent.prev_key or is_repeat 以外が発生したらno_hold stateに移る ** KeyEventType [#a9814343] キーイベント推定値 - tap : 短い間隔でキーをタイプした - click : 間隔をあけてキーをタイプした - repeat : キー押し下げでOSがrepeatした そのアルゴリズム - tap : no_hold state で is_tap - click : no_hold state で is_click - repeat : hold stateで is_repeat ng_repeatについて - ng_repeat : no_hold state で is_repeat の場合true - type = "click" | "tap" を返す - 次の可能性がある -- tap|click だが、たまたま is_repeat 範囲に入った -- hold state開始の is_hold誤判定 -- no_hold state開始の is_repeat誤判定 ** 利用例(アイデア) [#ea270e17] - keymap.setを使用し、KeyEventの内容をみてreturnする文字列や振る舞いを自由に設定することができる - rush.nvim : -- j<hold-j>(タタン)で"2j" -- タタタンで"4j" -- 続けてタタンで加速、タンで減速 - dontaka.nvim (作成中) -- ケーボードをリズミカルに叩くことでnvimとjam session - キーボードジェスチャーによるローンチャー(on_key callback) -- 例、n,<hold-n>の場合、検索履歴表示 -- 例、j,kの場合、return <esc> : これはinsert mode向きではない -- 例、j,<hold-k>の場合、女子高生とのチャットゲーム開始 ** rush.nvim [#f55c4d55] - j<hold-j>の場合:括弧の中は(nt,nr)。以下同様。 - click-j(1,0), tap-j(2,0), repeat-j(2,1), repeat-j(2,2), ... となるので - nt>=2 and nr!=0なら return 2^nt .. "j" とする - <hold-j>の場合 - click-j(1,0), repeat-j(1,1), repeat-j(1,2), ... となるので - nt==1 and nr!=0なら return vim_count .. "j" とする(vim_countはclick-jの時のnvim.v.count) ** 概要 [#u36c1611] - keymap.set で置き換えたkeymapを監視する。置き換えるキーは具体的には "j", <C-f>, "gj" など。 -- <C-f>, "gj" などはまだ実験していない - key K を長押しする操作を<hold-K>と表記する - 同時にon_keyで置き換えていないkey eventを監視する。(<C-f>などの場合どうするかは未定) - keymap.set で登録した関数が呼び出されるたびにrush eventを発生させる - rush eventの内容 -- 発生時間(vim.loop.hrtime) -- 押されたkey -- 連打開始直前に押されたキー(なければ"") -- vim_count:連打開始時のvim.v.count -- 前回key eventからの時間間隔(最初のkey evetの場合はvimが起動してからevent発生までの時間間隔) - rush eventの種類 -- tap: 前と同じキーが短時間(おおよそinterval.rep以内)に続けて押された --- 同一キー連打回数ntを提供する。連打開始はclickになるので、tapの場合2からはじまる -- start: キーを押し込んだ最初のeventはtap|clickだが2番目のkey eventはhold-startと判定する --- start2がよいか? -- repeat: キーを押し込んだ後3番目以降のkey eventはrepeat rush eventと判定する --- hold時間を提供する。hold時間とはhold開始からの経過時間。最初は≒interval.hold2+interval.rep --- repeat回数nrを提供する。repeat回数とはhold中に発生したkey event回数。3から始まる。 -- click: その他のkey event。連打でない場合、時間をおいてタイプの場合に相当する -- repeat-end: hold終了event。repeatからinterval.rep経過後repat eventがなければ発生する。またはrepeat以外のeventが発生する直前に発生する - 具体例 -- しばらく時間をおいてから"jjk<hold-k>"と連続タイプした場合のrush event概要 -- click-j(1,0), tap-j(2,0), tap-k(1,0), tap-k(2,0), start-k(2,2), repeat-k(2,3), repeat-k(2,4), ..., repeat-end(2,n) -- 括弧は(nt,nr)