Skip to content

Commit 48d85ad

Browse files
committed
Merge PR #28: feat: add channel history buffer system
Resolved conflicts in PreferencesStore.tsx (added SetKeyboard action alongside existing SetHaptics) and preferences.tsx (added KeyboardTab alongside existing HapticsTab).
2 parents 7c930c8 + a8ceff5 commit 48d85ad

File tree

5 files changed

+608
-3
lines changed

5 files changed

+608
-3
lines changed

src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import {
4646
GMCPRedirect, // Added
4747
GMCPRoom, // Added
4848
} from "./gmcp";
49+
import { useChannelHistory } from "./hooks/useChannelHistory";
4950
import { FileTransferOffer, useClientEvent } from "./hooks/useClientEvent";
5051
import {
5152
McpAwnsPing,
@@ -61,6 +62,7 @@ function App() {
6162
const [showFileTransfer, setShowFileTransfer] = useState<boolean>(false);
6263
const [fileTransferExpanded, setFileTransferExpanded] =
6364
useState<boolean>(false);
65+
useChannelHistory(client);
6466
const players = useClientEvent<"userlist">(client, "userlist", []) || [];
6567
const outRef = React.useRef<OutputWindow | null>(null);
6668
const inRef = React.useRef<HTMLTextAreaElement | null>(null);

src/PreferencesStore.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ export type EditorPreferences = {
3131
accessibilityMode: boolean;
3232
};
3333

34+
export type NavigationKeyScheme = "jkli" | "wasd" | "dvorak-rh" | "dvorak-lh";
35+
36+
export type KeyboardPreferences = {
37+
navigationKeyScheme: NavigationKeyScheme;
38+
};
39+
3440
export type MidiPreferences = {
3541
enabled: boolean;
3642
lastInputDeviceId?: string;
@@ -49,6 +55,7 @@ export type PrefState = {
4955
sound: SoundPreferences;
5056
channels?: { [channelId: string]: ChannelPreferences };
5157
editor: EditorPreferences;
58+
keyboard: KeyboardPreferences;
5259
midi: MidiPreferences;
5360
haptics: HapticsPreferences;
5461
};
@@ -60,6 +67,7 @@ export enum PrefActionType {
6067
SetChannels = "SET_CHANNELS",
6168
SetEditorAutocompleteEnabled = "SET_EDITOR_AUTOCOMPLETE_ENABLED",
6269
SetEditorAccessibilityMode = "SET_EDITOR_ACCESSIBILITY_MODE",
70+
SetKeyboard = "SET_KEYBOARD",
6371
SetMidi = "SET_MIDI",
6472
SetHaptics = "SET_HAPTICS",
6573
}
@@ -71,6 +79,7 @@ export type PrefAction =
7179
| { type: PrefActionType.SetChannels; data: { [channelId: string]: ChannelPreferences } }
7280
| { type: PrefActionType.SetEditorAutocompleteEnabled; data: boolean }
7381
| { type: PrefActionType.SetEditorAccessibilityMode; data: boolean }
82+
| { type: PrefActionType.SetKeyboard; data: KeyboardPreferences }
7483
| { type: PrefActionType.SetMidi; data: MidiPreferences }
7584
| { type: PrefActionType.SetHaptics; data: HapticsPreferences };
7685

@@ -121,6 +130,9 @@ class PreferencesStore {
121130
autocompleteEnabled: true,
122131
accessibilityMode: true,
123132
},
133+
keyboard: {
134+
navigationKeyScheme: "jkli",
135+
},
124136
midi: {
125137
enabled: false,
126138
},
@@ -144,6 +156,7 @@ class PreferencesStore {
144156
sound: { ...initial.sound, ...stored.sound },
145157
channels: stored.channels ? { ...initial.channels, ...stored.channels } : initial.channels,
146158
editor: { ...initial.editor, ...stored.editor },
159+
keyboard: { ...initial.keyboard, ...stored.keyboard },
147160
midi: { ...initial.midi, ...stored.midi },
148161
haptics: { ...initial.haptics, ...cleanHaptics },
149162
};
@@ -163,6 +176,8 @@ class PreferencesStore {
163176
return { ...state, editor: { ...state.editor, autocompleteEnabled: action.data } };
164177
case PrefActionType.SetEditorAccessibilityMode:
165178
return { ...state, editor: { ...state.editor, accessibilityMode: action.data } };
179+
case PrefActionType.SetKeyboard:
180+
return { ...state, keyboard: action.data };
166181
case PrefActionType.SetMidi:
167182
return { ...state, midi: action.data };
168183
case PrefActionType.SetHaptics:

src/components/input.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,14 @@ const CommandInput = ({ onSend, inputRef, client }: Props) => {
202202
} else if (e.key === "Enter" && !e.shiftKey) {
203203
e.preventDefault();
204204
handleSend();
205+
} else if (e.altKey && (
206+
e.key === "ArrowUp" || e.key === "ArrowDown" || e.key === "ArrowLeft" || e.key === "ArrowRight" ||
207+
"ijklwasdchtnoe,".includes(e.key.toLowerCase()) ||
208+
"IJKLWASDCHTNOE".split("").some(c => e.code === `Key${c}`) || e.code === "Comma"
209+
)) {
210+
e.preventDefault();
211+
} else if (e.altKey && e.code === "Space") {
212+
e.preventDefault();
205213
} else if (e.key === "ArrowUp") {
206214
e.preventDefault();
207215
const prevCommand = commandHistory.navigateUp(currentInputText);

src/components/preferences.tsx

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useState, useEffect } from "react";
2-
import { PrefActionType } from "../PreferencesStore";
2+
import { PrefActionType, NavigationKeyScheme } from "../PreferencesStore";
33
import { usePreferences } from "../hooks/usePreferences";
44
import { useVoices } from "../hooks/useVoices";
55
import { midiService, MidiDevice } from "../MidiService";
@@ -170,7 +170,7 @@ const PreviewButton: React.FC = () => {
170170
if (!isMounted.current) return; // Don't proceed if unmounted
171171

172172
const utterance = new SpeechSynthesisUtterance("This is a preview of the selected voice settings.");
173-
173+
174174
// Find the selected voice
175175
const voices = speechSynthesis.getVoices();
176176
console.log("Available voices:", voices.map(v => v.name));
@@ -354,7 +354,7 @@ const MidiTab: React.FC = () => {
354354
</label>
355355
<br />
356356
<br />
357-
357+
358358
{state.midi.enabled && (
359359
<p style={{ color: "#666", fontSize: "0.9em" }}>
360360
Device selection and management is available in the MIDI tab when connected to a server.
@@ -430,12 +430,42 @@ const HapticsTab: React.FC = () => {
430430
);
431431
};
432432

433+
const KeyboardTab: React.FC = () => {
434+
const [state, dispatch] = usePreferences();
435+
436+
return (
437+
<div>
438+
<label>
439+
Buffer Navigation Keys:
440+
<select
441+
value={state.keyboard.navigationKeyScheme}
442+
onChange={(e) =>
443+
dispatch({
444+
type: PrefActionType.SetKeyboard,
445+
data: { navigationKeyScheme: e.target.value as NavigationKeyScheme },
446+
})
447+
}
448+
>
449+
<option value="jkli">JKLI (QWERTY right-hand)</option>
450+
<option value="wasd">WASD (QWERTY left-hand)</option>
451+
<option value="dvorak-rh">HTNC (Dvorak right-hand)</option>
452+
<option value="dvorak-lh">,OAE (Dvorak left-hand)</option>
453+
</select>
454+
</label>
455+
<p style={{ color: "#666", fontSize: "0.9em", marginTop: "0.5em" }}>
456+
Arrow keys always work in addition to the selected scheme.
457+
</p>
458+
</div>
459+
);
460+
};
461+
433462
const Preferences: React.FC = () => {
434463
const tabs = [
435464
{ label: "General", content: <GeneralTab /> },
436465
{ label: "Speech", content: <SpeechTab /> },
437466
{ label: "Sounds", content: <SoundsTab /> },
438467
{ label: "Editor", content: <EditorTab /> },
468+
{ label: "Keyboard", content: <KeyboardTab /> },
439469
{ label: "MIDI", content: <MidiTab /> },
440470
{ label: "Haptics", content: <HapticsTab /> },
441471
];

0 commit comments

Comments
 (0)