Skip to content

Commit eef3327

Browse files
authored
Merge pull request #5 from tomoemon/keymap
キーコード自体を最初に入れ替える Keymap 対応
2 parents eaa5e8e + 48df6c9 commit eef3327

File tree

6 files changed

+58
-33
lines changed

6 files changed

+58
-33
lines changed

src/browser/eventHandler.ts

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,37 @@ import { VirtualKey, VirtualKeys } from "../core/virtualKey";
44

55
/**
66
* @param target addEventListener,removeEventListener を持つ Window object のような型
7-
* @param handler キー入力を受け取るハンドラ
7+
* @param keyEventHandler キー操作に関するイベントハンドラ
8+
* @param options.handleKeyDown キーが押されたときにkeyEventHandlerを呼び出す(default: true)
9+
* @param options.handleKeyUp キーが離されたときにkeyEventHandlerを呼び出す(default: false)
10+
* @param options.keyMap 入力されたキーを別のキーへ置換するマッピング (default: {})
811
* @returns イベントハンドラを解除する関数を返す
912
*/
1013
export function activate(
1114
target: EventTarget,
12-
onKeyDown?: (evt: InputEvent) => void,
13-
onKeyUp?: (evt: InputEvent) => void,
15+
keyEventHandler: (evt: InputEvent) => void,
16+
options?: {
17+
handleKeyDown?: boolean;
18+
handleKeyUp?: boolean;
19+
keyMap?: Map<VirtualKey, VirtualKey>,
20+
}
1421
) {
22+
const {
23+
handleKeyDown = true,
24+
handleKeyUp = false,
25+
keyMap = new Map<VirtualKey, VirtualKey>()
26+
} = options ?? {};
1527
const keyboardState = new KeyboardState();
1628
const keyDownEventHandler = (evt: Event) => {
1729
const keyStroke = toInputKeyStrokeFromKeyboardEvent(
1830
"keydown",
19-
evt as KeyboardEvent
31+
evt as KeyboardEvent,
32+
keyMap,
2033
);
2134
keyboardState.keydown(keyStroke.key);
22-
if (onKeyDown) {
23-
const now = new Date();
24-
onKeyDown(
35+
const now = new Date();
36+
if (handleKeyDown) {
37+
keyEventHandler(
2538
new InputEvent(
2639
keyStroke,
2740
// キー入力ごとのその時点での KeyboardState を渡す
@@ -34,12 +47,13 @@ export function activate(
3447
const keyUpEventHandler = (evt: Event) => {
3548
const keyStroke = toInputKeyStrokeFromKeyboardEvent(
3649
"keyup",
37-
evt as KeyboardEvent
50+
evt as KeyboardEvent,
51+
keyMap,
3852
);
3953
keyboardState.keyup(keyStroke.key);
40-
if (onKeyUp) {
54+
if (handleKeyUp) {
4155
const now = new Date();
42-
onKeyUp(
56+
keyEventHandler(
4357
new InputEvent(
4458
keyStroke,
4559
// キー入力ごとのその時点での KeyboardState を渡す
@@ -59,10 +73,12 @@ export function activate(
5973

6074
function toInputKeyStrokeFromKeyboardEvent(
6175
evtType: KeyEventType,
62-
evt: KeyboardEvent
76+
evt: KeyboardEvent,
77+
keyMap: Map<VirtualKey, VirtualKey>
6378
): InputStroke {
6479
const vkey = toVirtualKeyFromEventCode(evt.code);
65-
return new InputStroke(vkey, evtType);
80+
const replaced = keyMap.get(vkey) ?? vkey;
81+
return new InputStroke(replaced, evtType);
6682
}
6783

6884
function toVirtualKeyFromEventCode(code: string): VirtualKey {

src/impl/alphaNumericRule.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { expect, test } from "vitest";
2-
import { getAlphaNumericRuleByLayout } from "./alphaNumericRule";
2+
import { newAlphaNumericRuleByLayout } from "./alphaNumericRule";
33
import { loadPresetKeyboardLayoutQwertyJis } from "./defaultKeyboardLayout";
44

55
test("import alphaNumericRule", () => {
6-
const alphaNumericRule = getAlphaNumericRuleByLayout(
6+
const alphaNumericRule = newAlphaNumericRuleByLayout(
77
loadPresetKeyboardLayoutQwertyJis()
88
);
99
expect(alphaNumericRule.entries.length).toBe(96);

src/impl/alphaNumericRule.ts

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
import { KeyboardLayout } from "../core/keyboardLayout";
22
import { Rule, RuleEntry } from "../core/rule";
3-
import { setDefaultFunc } from "../utils/map";
43
import { defaultAlphaNumericNormalize } from "./charNormalizer";
54

6-
const alphaNumericRuleByLayout = new Map<string, Rule>();
7-
8-
export function getAlphaNumericRuleByLayout(
5+
export function newAlphaNumericRuleByLayout(
96
layout: KeyboardLayout
107
): Rule {
11-
return setDefaultFunc(alphaNumericRuleByLayout, layout.name, () => {
12-
const entries = Array.from(layout.mapping).map(
13-
([key, stroke]) => new RuleEntry([stroke], key, [], false)
14-
);
15-
return new Rule(
16-
"alpha-numeric",
17-
entries,
18-
layout.modifierGroup,
19-
defaultAlphaNumericNormalize
20-
);
21-
});
8+
const entries = Array.from(layout.mapping).map(
9+
([key, stroke]) => new RuleEntry([stroke], key, [], false)
10+
);
11+
return new Rule(
12+
"alpha-numeric",
13+
entries,
14+
layout.modifierGroup,
15+
defaultAlphaNumericNormalize
16+
);
2217
}

src/impl/defaultRules.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,27 @@ import nicola from "../assets/rules/nicola.json";
44
import { KeyboardLayout } from "../core/keyboardLayout";
55
import { Rule } from "../core/rule";
66
import { mergeRule } from "../core/ruleMerger";
7-
import { getAlphaNumericRuleByLayout } from "./alphaNumericRule";
7+
import { newAlphaNumericRuleByLayout } from "./alphaNumericRule";
88
import { loadJsonRule } from "./jsonRuleLoader";
99
import { loadMozcRule } from "./mozcRuleLoader";
1010

1111
export function loadPresetRuleRoman(layout: KeyboardLayout): Rule {
1212
return mergeRule(
1313
loadMozcRule("roman", roman, layout),
14-
getAlphaNumericRuleByLayout(layout)
14+
newAlphaNumericRuleByLayout(layout)
1515
)
1616
}
1717

1818
export function loadPresetRuleJisKana(layout: KeyboardLayout): Rule {
1919
return mergeRule(
2020
loadJsonRule("jis-kana", jis_kana),
21-
getAlphaNumericRuleByLayout(layout)
21+
newAlphaNumericRuleByLayout(layout)
2222
)
2323
}
2424

2525
export function loadPresetRuleNicola(layout: KeyboardLayout): Rule {
2626
return mergeRule(
2727
loadJsonRule("nicola", nicola),
28-
getAlphaNumericRuleByLayout(layout)
28+
newAlphaNumericRuleByLayout(layout)
2929
)
3030
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export { InputResult } from "./core/automaton";
2323
export { KeyboardGuide, type KeyRect, type KeyTop } from "./impl/keyboardGuide";
2424

2525
export { detectKeyboardLayout } from "./browser/osKeyboardLayout";
26+
export * from "./impl/alphaNumericRule";
2627
export * from "./impl/defaultKeyboardLayout";
2728
export { loadJsonKeyboardLayout } from "./impl/keyboardLayoutLoader";
2829

設計ノート.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,19 @@ aliasKey という仕様もあったが、これも同様の理由でなしに
262262
modifierGroup に関しても、入力ルールのエントリ内で使わない場合でも、Shift 等の定義をいちいち記載しておく必要があったが(ここに定義している modifier の中で、各エントリで使われない modifier が unnecesaryModifier の扱いになり、押してはいけない修飾キーになる)、Shift, Control, Alt(Meta) は基本的に modifier として扱って問題ないと思われるため、デフォルトで定義された状態にする。追加で modifierGroup を定義したい場合のみ、json に記載させる。
263263
→ と考えていたが、暗黙的なルールはできるだけない方が後から理解しやすいので、明示する形式に変更する。また、グループに名前をつけて管理する方法も多少 easy にするだけで、仕様の複雑化につながるので、なしにする。
264264

265+
# Keyboard Layout の概念の整理
266+
267+
202502 現在の KeyboardLayout はキーコードから英数記号文字への対応表を意味している
268+
これとは別で、キーコード自体を入れ替えるような、キーコード to キーコードの対応表も考えられる
269+
270+
後者を KeyMap として、emiel.activate 時に渡す
271+
eventHandler でブラウザから渡されるキーコードを内部のキーコードに変換しているが、そこからさらに KeyMap を使って変換するようにする。ブラウザから渡されるキーコードから直接変換するものを KeyMap とすることも考えられるが、OS やブラウザの違いによって同じ位置にあるキーでも異なるキーコードが渡されることがあるため、最初にまず emiel 用のキーコードに変換した方が KeyMap が扱いやすくなると考えた。
272+
273+
用途としては、例えば backspace キーや space キー、shift キー等も含めたキーの入れ替えを行う配列で使えそう。
274+
275+
また、前者の名前を KeyCharMap とするような案はあるが、
276+
OS のキーボード設定等は KeyboardLayout という名前なので、それに対応する概念として、名前は維持する
277+
265278
# 参考資料
266279

267280
Microsoft キーボード入力の概要(真ん中以下にスキャンコード表がある)

0 commit comments

Comments
 (0)