Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
72e163a
feat: 팝업 레이어 소유권 기반으로 키보드 접근성 개편
eun-yeon Jul 14, 2026
fe587fe
fix: 키 모드 전환 레이스와 오버레이 눌림 상태 유실 수정
eun-yeon Jul 14, 2026
9306001
feat: 플러그인 표시 요소 인스턴스 생명주기 정비
eun-yeon Jul 14, 2026
329d105
fix: 폰트 CDN 의존 제거와 전량 프리로드 메모리 개선
eun-yeon Jul 14, 2026
575be19
docs: 구독 ready 반환값과 OBS 브라우저 소스 사용법 추가
eun-yeon Jul 14, 2026
39f1407
chore: store 자산·복구 안전 규칙을 프로젝트 지침에 추가
eun-yeon Jul 14, 2026
f8d35d8
fix: 번들 검증에 구식 최소 버전 기록 폴백과 판별 실패 메시지 추가
eun-yeon Jul 14, 2026
7bd1f29
fix: Dock 헬퍼가 번들 없는 메인 프로세스의 종료도 대기하도록 보완
eun-yeon Jul 14, 2026
b36e9ac
chore: 테스트 전용 수제 FFI를 libc 크레이트로 교체
eun-yeon Jul 14, 2026
d1e220b
fix: 카운터 초기화 저장 중 유입된 키 입력 유실 방지
eun-yeon Jul 14, 2026
6ef88fc
fix: 폰트 추가 라벨의 하드코딩 폴백 제거
eun-yeon Jul 14, 2026
5181ee4
fix: 화면 전환과 전면 시트의 수직 이동 모션 제거
eun-yeon Jul 14, 2026
e592c08
fix: 오버레이 생성 데드락과 키 데이터 유실 경로 수정
eun-yeon Jul 14, 2026
f55ab5e
fix: 키 저장을 원자 커맨드로 전환하고 오버레이 토글 실패를 롤백
eun-yeon Jul 14, 2026
6d956a9
fix: 상주 크롬 렌더링 비용 완화와 화면 전환 모션 제거
eun-yeon Jul 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ src-tauri/src/
- `useMemo` / `useCallback` 의존성 배열에서 배열/객체는 개별 요소 비교 고려
- 린트 자동 수정이 의도적 패턴을 덮어쓸 수 있으므로 필요시 `eslint-disable` 주석 사용

## store 자산·복구 안전 규칙

- **파일 자산 종류를 새로 추가할 때** (appData에 파일을 두고 store가 경로를 참조): `store.rs`의 orphan sweep 보호 집합(`collect_local_*_path_keys`)에 참조 수집을 추가하고, 크래시 직후·손상 복구 직후 시나리오와의 교차 테스트 필수
- **sweep 불변식**: 자산 정리는 즉시 삭제가 아니라 `trash/<세션>/` 30일 격리 — 이를 우회하는 직접 `remove_file` 정리 경로 추가 금지. store 복구가 발생한 세션은 sweep이 자동 스킵됨(`skip_asset_sweep`)
- **store에 사용자 생성 컬렉션 필드를 추가할 때**: `migration.rs`의 `recover_collection_field`에 항목 단위 복구 등록 검토 (범용 헬퍼 재사용, 한 줄). 미등록 시 그 필드만 "손상 시 통째 초기화"로 폴백
- **`keys[mode][i]` ↔ `keyPositions[mode][i]`는 인덱스 결합** — 복구·마이그레이션에서 배열 요소 제거 금지, 제자리 대체(`""` / default)만 허용

## API 문서 동기화

- 프론트엔드 플러그인 API(`dmn.*`) 또는 Tauri 커맨드에 변경이 있으면 `docs/content/` 하위 관련 MDX 문서를 업데이트
Expand Down
7 changes: 7 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ src-tauri/src/
- `useMemo` / `useCallback` 의존성 배열에서 배열/객체는 개별 요소 비교 고려
- 린트 자동 수정이 의도적 패턴을 덮어쓸 수 있으므로 필요시 `eslint-disable` 주석 사용

## store 자산·복구 안전 규칙

- **파일 자산 종류를 새로 추가할 때** (appData에 파일을 두고 store가 경로를 참조): `store.rs`의 orphan sweep 보호 집합(`collect_local_*_path_keys`)에 참조 수집을 추가하고, 크래시 직후·손상 복구 직후 시나리오와의 교차 테스트 필수
- **sweep 불변식**: 자산 정리는 즉시 삭제가 아니라 `trash/<세션>/` 30일 격리 — 이를 우회하는 직접 `remove_file` 정리 경로 추가 금지. store 복구가 발생한 세션은 sweep이 자동 스킵됨(`skip_asset_sweep`)
- **store에 사용자 생성 컬렉션 필드를 추가할 때**: `migration.rs`의 `recover_collection_field`에 항목 단위 복구 등록 검토 (범용 헬퍼 재사용, 한 줄). 미등록 시 그 필드만 "손상 시 통째 초기화"로 폴백
- **`keys[mode][i]` ↔ `keyPositions[mode][i]`는 인덱스 결합** — 복구·마이그레이션에서 배열 요소 제거 금지, 제자리 대체(`""` / default)만 허용

## API 문서 동기화

- 프론트엔드 플러그인 API(`dmn.*`) 또는 Tauri 커맨드에 변경이 있으면 `docs/content/` 하위 관련 MDX 문서를 업데이트
Expand Down
52 changes: 39 additions & 13 deletions docs/content/en/api-reference/keys/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Key event subscription, mapping, and custom tab management.

## Key State Events

### `dmn.keys.onKeyState(callback): Unsubscribe`
### `dmn.keys.onKeyState(callback): ReadyUnsubscribe`

<Callout type="warning">Overlay window only.</Callout>

Expand All @@ -18,8 +18,8 @@ Subscribes to state changes for registered keys.
```typescript
interface KeyStateEvent {
key: string; // e.g., 'KeyA', 'MouseLeft'
state: "UP" | "DOWN";
mode: "keyboard" | "mouse";
state: 'UP' | 'DOWN';
mode: 'keyboard' | 'mouse';
// Elapsed time (ms) between input capture and event emit.
// Recover the real input time with `performance.now() - eventAgeMs`.
eventAgeMs?: number;
Expand All @@ -30,6 +30,16 @@ const unsub = dmn.keys.onKeyState(({ key, state, mode }) => {
});
```

The returned function also exposes a `ready` promise that resolves once the
subscription is actually registered with the backend. Events fired before
`ready` resolves may not be delivered — await it when you need a guaranteed
starting point (e.g. before requesting a snapshot):

```typescript
const unsub = dmn.keys.onKeyState(handler);
await unsub.ready; // subscription is live from this point
```

### `dmn.keys.onRawInput(callback): Unsubscribe`

<Callout type="warning">Overlay window only.</Callout>
Expand All @@ -38,10 +48,10 @@ Subscribes to all raw input events (including unregistered keys).

```typescript
interface RawInputEvent {
device: "keyboard" | "mouse" | "gamepad" | "unknown";
device: 'keyboard' | 'mouse' | 'gamepad' | 'unknown';
label: string; // e.g., 'A', 'LButton', 'HIDB:1ccf:101c:9:3'
labels: string[]; // all candidate labels for this event
state: "DOWN" | "UP";
state: 'DOWN' | 'UP';
}

const unsub = dmn.keys.onRawInput(({ device, label, state }) => {
Expand All @@ -65,7 +75,7 @@ Returns the current cumulative key counter snapshot.
type KeyCounters = Record<string, Record<string, number>>;

const counters = await dmn.keys.getCounters();
console.log(counters["4key"]);
console.log(counters['4key']);
```

### `dmn.keys.onCounterChanged(callback): Unsubscribe`
Expand Down Expand Up @@ -95,11 +105,11 @@ Subscribes to input mode changes (keyboard/mouse).

```typescript
interface ModeEvent {
mode: "keyboard" | "mouse";
mode: 'keyboard' | 'mouse';
}

const unsub = dmn.keys.onModeChanged(({ mode }) => {
console.log("Mode changed:", mode);
console.log('Mode changed:', mode);
});
```

Expand Down Expand Up @@ -135,6 +145,22 @@ await dmn.keys.set({
});
```

### `dmn.keys.updateWithPositions(mappings, positions): Promise<KeysWithPositionsResult>`

Updates key mappings and their index-coupled positions in one durable commit. Use
this method whenever keys are added, removed, or reordered. The committed values
are returned, and both `keys:changed` and `positions:changed` are emitted after
the commit succeeds.

```typescript
interface KeysWithPositionsResult {
keys: KeyMappings;
positions: KeyPositions;
}

const result = await dmn.keys.updateWithPositions(mappings, positions);
```

---

## Custom Tab
Expand All @@ -153,8 +179,8 @@ interface CustomTabOptions {
}

const unsub = dmn.keys.registerCustomTab({
id: "my-tab",
label: "My Tab",
id: 'my-tab',
label: 'My Tab',
content: (container) => {
container.innerHTML = `<div>Custom tab content</div>`;
return () => {
Expand All @@ -170,8 +196,8 @@ Restores custom tabs and selected mode atomically. Syncs backend state, overlay,

```javascript
await dmn.keys.customTabs.restore(
[{ id: "custom-123", name: "My Keys", keys: ["KeyA", "KeyS"] }],
"custom-123",
[{ id: 'custom-123', name: 'My Keys', keys: ['KeyA', 'KeyS'] }],
'custom-123',
);
```

Expand Down Expand Up @@ -238,7 +264,7 @@ dmn.stats.reset();
```javascript
// KPS counter using stats API
dmn.plugin.defineElement({
name: "KPS Counter",
name: 'KPS Counter',
maxInstances: 1,

template: (state, settings, { html }) => html`
Expand Down
8 changes: 8 additions & 0 deletions docs/content/en/guide/tips/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ To capture both game and overlay at once:
- Add the overlay with **Window Capture**.
- Place the overlay source above the game source.

### Using a Browser Source with OBS Mode

Turning on **OBS Mode** in settings lets you show the overlay as a browser source on the same network. Use **Copy URL** to get the address and paste it into an OBS browser source.

<Callout type="warning">
This share URL is not just a view link. Anyone on your network who has it can subscribe to your key input stream and modify plugin storage, so only share it on trusted networks. If you suspect it leaked, regenerate the session token to invalidate the old URL.
</Callout>

## Performance Optimization

### Graphics Troubleshooting
Expand Down
Loading
Loading