feat(설정 마우스): 화면 옮기기 단추 · 바꾼 키 칸 읽기 — panButton · isPanButton · buttonMask (PLAN 588-4 이음 · 요구 445 C3)
- input-prefs 에 panButton(왼 · 가운데 · 오른 · 기본 가운데) · keys(바꾼 키만) 칸 - isPanButton = 고른 단추 또는 가운데 · 585-1 카카오 부품이 부름 - test_input_prefs 기본값 · 단추 판정 · 깨진 값 거름 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -56,6 +56,8 @@ const KEY_ROWS: [LocaleKey, LocaleKey][] = [
|
||||
/** 비교 · 저장 꼴 — 별칭 명령 차례를 맞춤 */
|
||||
const normalize = (p: InputPrefs): InputPrefs => ({
|
||||
wheelZoom: p.wheelZoom,
|
||||
panButton: p.panButton,
|
||||
keys: Object.fromEntries(Object.entries(p.keys).sort(([a], [b]) => (a < b ? -1 : 1))),
|
||||
cadAliases: Object.fromEntries(Object.entries(p.cadAliases).sort(([a], [b]) => (a < b ? -1 : 1))),
|
||||
});
|
||||
const snapshot = (p: InputPrefs): string => JSON.stringify(normalize(p));
|
||||
|
||||
@@ -6,13 +6,20 @@
|
||||
* - 없음 · 깨짐 · Node(저장소 없음) = 기본값(= 지금 동작) · 의존 없음 · 불러올 때 window 안 만짐(CAD 도 import)
|
||||
* - 휠 확대 방향 하나로 모든 화면 일체 — 기본 밂 = 휠을 앞으로(deltaY < 0) 굴리면 확대(오토캐드) · 당김 = 몸 쪽으로
|
||||
* - 핀치(트랙패드 · 손가락)는 설정과 상관없이 늘 벌리면 확대(deltaY < 0)
|
||||
* - 화면 옮기기 단추 하나(PLAN 588-4) — 고른 단추로 끌면 옮김 · 안 끌고 떼면 그 단추 제 몫 · 가운데는 늘 옮김
|
||||
* - 바꾼 키(`keys`)는 기본과 다른 것만 — 판정 · 등록부는 `key_registry.ts`
|
||||
* ========================================================================== */
|
||||
|
||||
export type WheelZoom = "pull" | "push";
|
||||
export type PanButton = "left" | "middle" | "right";
|
||||
|
||||
export interface InputPrefs {
|
||||
/** 휠 확대 방향 — pull = 당기면 확대 · push = 밀면 확대 */
|
||||
wheelZoom: WheelZoom;
|
||||
/** 화면 옮기기 단추 */
|
||||
panButton: PanButton;
|
||||
/** 바꾼 단축키 `{동작 id: [키]}` — 기본과 다른 것만(`key_registry.ts`) */
|
||||
keys: Record<string, string[]>;
|
||||
/** CAD 내 별칭 `{명령: [별칭]}`(대문자 · acad.pgp 식 — 명령 이름 > 내 별칭 > 기본 별칭) */
|
||||
cadAliases: Record<string, string[]>;
|
||||
}
|
||||
@@ -20,7 +27,25 @@ export interface InputPrefs {
|
||||
/** `stateKey("input-prefs")` 와 같은 키(시험이 맞춰 봄) — 등록표를 불러오면 window 가 딸려 와서 글자로 둠 */
|
||||
export const INPUT_PREFS_KEY = "aislo:pref:input-prefs";
|
||||
|
||||
export const DEFAULT_INPUT_PREFS: InputPrefs = { wheelZoom: "push", cadAliases: {} };
|
||||
export const DEFAULT_INPUT_PREFS: InputPrefs = {
|
||||
wheelZoom: "push",
|
||||
panButton: "middle",
|
||||
keys: {},
|
||||
cadAliases: {},
|
||||
};
|
||||
|
||||
const PAN_BUTTONS: PanButton[] = ["left", "middle", "right"];
|
||||
|
||||
const defaults = (): InputPrefs => ({ ...DEFAULT_INPUT_PREFS, keys: {}, cadAliases: {} });
|
||||
|
||||
const cleanKeys = (raw: unknown): Record<string, string[]> => {
|
||||
const out: Record<string, string[]> = {};
|
||||
if (!raw || typeof raw !== "object") return out;
|
||||
for (const [id, list] of Object.entries(raw as Record<string, unknown>)) {
|
||||
if (Array.isArray(list)) out[id] = list.filter((k): k is string => typeof k === "string");
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
const cleanAliases = (raw: unknown): Record<string, string[]> => {
|
||||
const out: Record<string, string[]> = {};
|
||||
@@ -39,17 +64,31 @@ const cleanAliases = (raw: unknown): Record<string, string[]> => {
|
||||
export function inputPrefs(): InputPrefs {
|
||||
try {
|
||||
const raw = globalThis.localStorage?.getItem(INPUT_PREFS_KEY);
|
||||
if (!raw) return { ...DEFAULT_INPUT_PREFS, cadAliases: {} };
|
||||
if (!raw) return defaults();
|
||||
const value = JSON.parse(raw) as Partial<InputPrefs> | null;
|
||||
return {
|
||||
wheelZoom: value?.wheelZoom === "pull" ? "pull" : "push",
|
||||
panButton: PAN_BUTTONS.includes(value?.panButton as PanButton)
|
||||
? (value!.panButton as PanButton)
|
||||
: "middle",
|
||||
keys: cleanKeys(value?.keys),
|
||||
cadAliases: cleanAliases(value?.cadAliases),
|
||||
};
|
||||
} catch {
|
||||
return { ...DEFAULT_INPUT_PREFS, cadAliases: {} };
|
||||
return defaults();
|
||||
}
|
||||
}
|
||||
|
||||
/** 고른 화면 옮기기 단추 */
|
||||
export const panButton = (): PanButton => inputPrefs().panButton;
|
||||
|
||||
/** 이 단추(`MouseEvent.button` 0 왼 · 1 가운데 · 2 오른)로 끌면 화면 옮김 — 고른 단추 · 가운데는 늘 */
|
||||
export const isPanButton = (button: number): boolean =>
|
||||
button === 1 || button === PAN_BUTTONS.indexOf(panButton());
|
||||
|
||||
/** 단추 번호 → `buttons` 비트(왼 1 · 오른 2 · 가운데 4) — 끄는 중 놓침 알아채기 */
|
||||
export const buttonMask = (button: number): number => [1, 4, 2][button] ?? 0;
|
||||
|
||||
/** 휠 한 번이 확대인가 — 설정 방향을 따름 */
|
||||
export const wheelIn = (deltaY: number): boolean =>
|
||||
inputPrefs().wheelZoom === "pull" ? deltaY > 0 : deltaY < 0;
|
||||
|
||||
@@ -31,6 +31,7 @@ const sample = () => ({
|
||||
padPinch: prefs.wheelEventIn({ ctrlKey: true, deltaY: 3.5 }),
|
||||
fingerSpread: prefs.wheelEventIn({ ctrlKey: true, deltaY: -9.5 }, true),
|
||||
bridgePull: bridge.wheelZoomsIn({ ctrlKey: false, deltaY: 100 }),
|
||||
pan: [0, 1, 2].map((button) => prefs.isPanButton(button)),
|
||||
});
|
||||
out.node = { key: prefs.INPUT_PREFS_KEY, default: prefs.DEFAULT_INPUT_PREFS, ...sample() };
|
||||
out.registryKey = page.stateKey("input-prefs");
|
||||
@@ -46,6 +47,10 @@ globalThis.localStorage = {
|
||||
const set = (v) => store.set(prefs.INPUT_PREFS_KEY, v);
|
||||
set(JSON.stringify({ wheelZoom: "pull", cadAliases: { line: ["ll", 3], ARC: [] } }));
|
||||
out.saved = sample(); // 기본 밂(337) 의 반대를 저장
|
||||
for (const button of ["left", "right", "sideways"]) {
|
||||
set(JSON.stringify({ panButton: button, keys: { "plan.delete": ["X", 3], bad: "Y" } }));
|
||||
out[`pan_${button}`] = sample();
|
||||
}
|
||||
set("{깨짐");
|
||||
out.broken = sample();
|
||||
set(JSON.stringify({ wheelZoom: "sideways" }));
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
· 기본 = 밂(휠을 앞으로 = 확대 · 오토캐드 · 337) · 당김 저장 뒤 뒤집힘 · 깨짐 · 모르는 값 · 막힌 저장소 · Node = 기본
|
||||
· 핀치(트랙패드 · 손가락)는 설정과 상관없이 늘 벌리면 확대
|
||||
· 키 = 등록표 `input-prefs`(pref · global) 와 같은 글자
|
||||
· 화면 옮기기 단추(588-4) = 기본 가운데 · 고른 단추 + 가운데 · 모르는 값 = 가운데 · 바꾼 키 = 글자 목록만
|
||||
짝: `helper_input_prefs.cjs`(실제 TS 를 Node 로 돌림).
|
||||
"""
|
||||
|
||||
@@ -45,6 +46,7 @@ def r() -> dict:
|
||||
PULL = {"pull": True, "push": False, "mouseCtrl": True, "bridgePull": True}
|
||||
PUSH = {"pull": False, "push": True, "mouseCtrl": False, "bridgePull": False}
|
||||
PINCH = {"padSpread": True, "padPinch": False, "fingerSpread": True}
|
||||
DEFAULT = {"wheelZoom": "push", "panButton": "middle", "keys": {}, "cadAliases": {}}
|
||||
|
||||
|
||||
def _pick(case: dict, keys: dict) -> dict:
|
||||
@@ -53,7 +55,7 @@ def _pick(case: dict, keys: dict) -> dict:
|
||||
|
||||
def test_Node_기본_밂(r):
|
||||
n = r["node"]
|
||||
assert n["default"] == {"wheelZoom": "push", "cadAliases": {}}
|
||||
assert n["default"] == DEFAULT
|
||||
assert n["prefs"] == n["default"]
|
||||
assert _pick(n, PULL) == PUSH and _pick(n, PINCH) == PINCH
|
||||
|
||||
@@ -70,7 +72,7 @@ def test_당김_저장_뒤_뒤집힘_핀치는_그대로(r):
|
||||
@pytest.mark.parametrize("case", ["broken", "unknown", "empty", "blocked"])
|
||||
def test_깨짐_모르는_값_없음_막힘_기본(r, case):
|
||||
c = r[case]
|
||||
assert c["prefs"] == {"wheelZoom": "push", "cadAliases": {}}
|
||||
assert c["prefs"] == DEFAULT
|
||||
assert _pick(c, PULL) == PUSH and _pick(c, PINCH) == PINCH
|
||||
|
||||
|
||||
@@ -112,3 +114,20 @@ def test_휠_자리_공용_판정(rel):
|
||||
def test_700줄_안():
|
||||
for rel in WHEEL_SITES:
|
||||
assert _read(rel).count("\n") <= 700, rel
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("case", "button", "pan"),
|
||||
[
|
||||
("node", "middle", [False, True, False]),
|
||||
("pan_left", "left", [True, True, False]),
|
||||
("pan_right", "right", [False, True, True]),
|
||||
("pan_sideways", "middle", [False, True, False]),
|
||||
],
|
||||
)
|
||||
def test_화면_옮기기_단추_고른_것_더하기_가운데(r, case, button, pan):
|
||||
c = r[case]
|
||||
assert c["prefs"]["panButton"] == button
|
||||
assert c["pan"] == pan
|
||||
if case != "node":
|
||||
assert c["prefs"]["keys"] == {"plan.delete": ["X"]} # 글자 아닌 것 · 목록 아닌 것 버림
|
||||
|
||||
Reference in New Issue
Block a user