more keyboard handling

This commit is contained in:
2026-02-21 00:46:36 -05:00
parent b45e7bf538
commit c9a370a424
8 changed files with 30 additions and 32 deletions

View File

@@ -18,8 +18,9 @@ export type KeybindsResolved = {
inverseModifier: string; inverseModifier: string;
leader: string; // will not trigger while focused on input leader: string; // will not trigger while focused on input
quit: string[]; quit: string[];
select: string[]; // for selecting/activating items
"audio-toggle": string[]; "audio-toggle": string[];
"audio-pause": []; "audio-pause": string[];
"audio-play": string[]; "audio-play": string[];
"audio-next": string[]; "audio-next": string[];
"audio-prev": string[]; "audio-prev": string[];
@@ -36,6 +37,7 @@ export enum KeybindAction {
DIVE, DIVE,
OUT, OUT,
QUIT, QUIT,
SELECT,
AUDIO_TOGGLE, AUDIO_TOGGLE,
AUDIO_PAUSE, AUDIO_PAUSE,
AUDIO_PLAY, AUDIO_PLAY,
@@ -60,6 +62,7 @@ export const { use: useKeybinds, provider: KeybindProvider } =
inverseModifier: "", inverseModifier: "",
leader: "", leader: "",
quit: [], quit: [],
select: [],
refresh: [], refresh: [],
"audio-toggle": [], "audio-toggle": [],
"audio-pause": [], "audio-pause": [],

View File

@@ -29,10 +29,9 @@ export function DiscoverPage() {
(keyEvent: any) => { (keyEvent: any) => {
const isDown = keybind.match("down", keyEvent); const isDown = keybind.match("down", keyEvent);
const isUp = keybind.match("up", keyEvent); const isUp = keybind.match("up", keyEvent);
const isEnter = keyEvent.name === "Enter" || keyEvent.name === " "; const isSelect = keybind.match("select", keyEvent);
const isSpace = keyEvent.name === " ";
if (isEnter || isSpace) { if (isSelect) {
const filteredPodcasts = discoverStore.filteredPodcasts(); const filteredPodcasts = discoverStore.filteredPodcasts();
if (filteredPodcasts.length > 0 && showIndex() < filteredPodcasts.length) { if (filteredPodcasts.length > 0 && showIndex() < filteredPodcasts.length) {
setShowIndex(showIndex() + 1); setShowIndex(showIndex() + 1);

View File

@@ -39,10 +39,9 @@ export function FeedPage() {
(keyEvent: any) => { (keyEvent: any) => {
const isDown = keybind.match("down", keyEvent); const isDown = keybind.match("down", keyEvent);
const isUp = keybind.match("up", keyEvent); const isUp = keybind.match("up", keyEvent);
const isEnter = keyEvent.name === "Enter" || keyEvent.name === " "; const isSelect = keybind.match("select", keyEvent);
const isSpace = keyEvent.name === " ";
if (isEnter || isSpace) { if (isSelect) {
const episodes = allEpisodes(); const episodes = allEpisodes();
if (episodes.length > 0 && episodes[focusedIndex()]) { if (episodes.length > 0 && episodes[focusedIndex()]) {
setSelectedEpisodeID(episodes[focusedIndex()].episode.id); setSelectedEpisodeID(episodes[focusedIndex()].episode.id);

View File

@@ -14,6 +14,7 @@ import { useTheme } from "@/context/ThemeContext";
import { useAudioNavStore, AudioSource } from "@/stores/audio-nav"; import { useAudioNavStore, AudioSource } from "@/stores/audio-nav";
import { useNavigation } from "@/context/NavigationContext"; import { useNavigation } from "@/context/NavigationContext";
import { LoadingIndicator } from "@/components/LoadingIndicator"; import { LoadingIndicator } from "@/components/LoadingIndicator";
import { KeybindProvider, useKeybinds } from "@/context/KeybindContext";
enum MyShowsPaneType { enum MyShowsPaneType {
SHOWS = 1, SHOWS = 1,
@@ -32,16 +33,14 @@ export function MyShowsPage() {
const { theme } = useTheme(); const { theme } = useTheme();
const mutedColor = () => theme.muted || theme.text; const mutedColor = () => theme.muted || theme.text;
const nav = useNavigation(); const nav = useNavigation();
const keybind = useKeybinds();
onMount(() => { onMount(() => {
useKeyboard( useKeyboard(
(keyEvent: any) => { (keyEvent: any) => {
const isDown = const isDown = keybind.match("down", keyEvent);
keyEvent.key === "j" || keyEvent.key === "ArrowDown"; const isUp = keybind.match("up", keyEvent);
const isUp = const isSelect = keybind.match("select", keyEvent);
keyEvent.key === "k" || keyEvent.key === "ArrowUp";
const isSelect =
keyEvent.key === "Enter" || keyEvent.key === " ";
const shows = feedStore.getFilteredFeeds(); const shows = feedStore.getFilteredFeeds();
const episodesList = episodes(); const episodesList = episodes();

View File

@@ -4,6 +4,7 @@ import { useAudio } from "@/hooks/useAudio";
import { useAppStore } from "@/stores/app"; import { useAppStore } from "@/stores/app";
import { useTheme } from "@/context/ThemeContext"; import { useTheme } from "@/context/ThemeContext";
import { useNavigation } from "@/context/NavigationContext"; import { useNavigation } from "@/context/NavigationContext";
import { useKeybinds } from "@/context/KeybindContext";
import { useKeyboard } from "@opentui/solid"; import { useKeyboard } from "@opentui/solid";
import { onMount } from "solid-js"; import { onMount } from "solid-js";
@@ -17,24 +18,22 @@ export function PlayerPage() {
const { theme } = useTheme(); const { theme } = useTheme();
const nav = useNavigation(); const nav = useNavigation();
const keybind = useKeybinds();
onMount(() => { onMount(() => {
useKeyboard( useKeyboard(
(keyEvent: any) => { (keyEvent: any) => {
const isNext = keyEvent.key === "l" || keyEvent.key === "ArrowRight"; if (keybind.match("audio-toggle", keyEvent)) {
const isPrev = keyEvent.key === "h" || keyEvent.key === "ArrowLeft";
const isPlayPause = keyEvent.key === " " || keyEvent.key === "Enter";
if (isPlayPause) {
audio.togglePlayback(); audio.togglePlayback();
return; return;
} }
if (isNext) { if (keybind.match("audio-seek-forward", keyEvent)) {
audio.seek(audio.currentEpisode()?.duration ?? 0); audio.seek(audio.currentEpisode()?.duration ?? 0);
return; return;
} }
if (isPrev) { if (keybind.match("audio-seek-backward", keyEvent)) {
audio.seek(0); audio.seek(0);
return; return;
} }

View File

@@ -11,6 +11,7 @@ import type { SearchResult } from "@/types/source";
import { MyShowsPage } from "../MyShows/MyShowsPage"; import { MyShowsPage } from "../MyShows/MyShowsPage";
import { useTheme } from "@/context/ThemeContext"; import { useTheme } from "@/context/ThemeContext";
import { useNavigation } from "@/context/NavigationContext"; import { useNavigation } from "@/context/NavigationContext";
import { KeybindProvider, useKeybinds } from "@/context/KeybindContext";
enum SearchPaneType { enum SearchPaneType {
INPUT = 1, INPUT = 1,
@@ -26,16 +27,14 @@ export function SearchPage() {
const [historyIndex, setHistoryIndex] = createSignal(0); const [historyIndex, setHistoryIndex] = createSignal(0);
const { theme } = useTheme(); const { theme } = useTheme();
const nav = useNavigation(); const nav = useNavigation();
const keybind = useKeybinds();
onMount(() => { onMount(() => {
useKeyboard( useKeyboard(
(keyEvent: any) => { (keyEvent: any) => {
const isDown = const isDown = keybind.match("down", keyEvent);
keyEvent.key === "j" || keyEvent.key === "ArrowDown"; const isUp = keybind.match("up", keyEvent);
const isUp = const isSelect = keybind.match("select", keyEvent);
keyEvent.key === "k" || keyEvent.key === "ArrowUp";
const isSelect =
keyEvent.key === "Enter" || keyEvent.key === " ";
if (isSelect) { if (isSelect) {
const results = searchStore.results(); const results = searchStore.results();

View File

@@ -6,6 +6,7 @@ import { PreferencesPanel } from "./PreferencesPanel";
import { SyncPanel } from "./SyncPanel"; import { SyncPanel } from "./SyncPanel";
import { VisualizerSettings } from "./VisualizerSettings"; import { VisualizerSettings } from "./VisualizerSettings";
import { useNavigation } from "@/context/NavigationContext"; import { useNavigation } from "@/context/NavigationContext";
import { KeybindProvider, useKeybinds } from "@/context/KeybindContext";
enum SettingsPaneType { enum SettingsPaneType {
SYNC = 1, SYNC = 1,
@@ -27,6 +28,7 @@ const SECTIONS: Array<{ id: SettingsPaneType; label: string }> = [
export function SettingsPage() { export function SettingsPage() {
const { theme } = useTheme(); const { theme } = useTheme();
const nav = useNavigation(); const nav = useNavigation();
const keybind = useKeybinds();
// Helper function to check if a depth is active // Helper function to check if a depth is active
const isActive = (depth: SettingsPaneType): boolean => { const isActive = (depth: SettingsPaneType): boolean => {
@@ -36,12 +38,9 @@ export function SettingsPage() {
onMount(() => { onMount(() => {
useKeyboard( useKeyboard(
(keyEvent: any) => { (keyEvent: any) => {
const isDown = const isDown = keybind.match("down", keyEvent);
keyEvent.key === "j" || keyEvent.key === "ArrowDown"; const isUp = keybind.match("up", keyEvent);
const isUp = const isSelect = keybind.match("select", keyEvent);
keyEvent.key === "k" || keyEvent.key === "ArrowUp";
const isSelect =
keyEvent.key === "Enter" || keyEvent.key === " ";
if (isSelect) { if (isSelect) {
nav.setActiveDepth((nav.activeDepth() % SettingsPaneCount) + 1); nav.setActiveDepth((nav.activeDepth() % SettingsPaneCount) + 1);

View File

@@ -27,6 +27,7 @@ const DEFAULT_KEYBINDS: KeybindsResolved = {
right: ["right", "l"], right: ["right", "l"],
cycle: ["tab"], cycle: ["tab"],
dive: ["return"], dive: ["return"],
select: ["return"],
out: ["esc"], out: ["esc"],
inverseModifier: "shift", inverseModifier: "shift",
leader: ":", leader: ":",