fix/refactor(frontend): hotkeyの改修 (#14157)
* improve(frontend): hotkeyの改修 (#234) (cherry picked from commit 678be147f4db709dadf25d007cc2e679e98a370e) * Change path, add missing script Co-authored-by: taiy <53635909+taiyme@users.noreply.github.com> * fix * fix * add missing keycodes * fix * update changelog --------- Co-authored-by: taiy <53635909+taiyme@users.noreply.github.com>
This commit is contained in:
@@ -80,6 +80,7 @@ import type { MenuItem } from '@/types/menu.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import * as os from '@/os.js';
|
||||
import { type Keymap } from '@/scripts/hotkey.js';
|
||||
import bytes from '@/filters/bytes.js';
|
||||
import { hms } from '@/filters/hms.js';
|
||||
import MkMediaRange from '@/components/MkMediaRange.vue';
|
||||
@@ -90,32 +91,44 @@ const props = defineProps<{
|
||||
}>();
|
||||
|
||||
const keymap = {
|
||||
'up': () => {
|
||||
if (hasFocus() && audioEl.value) {
|
||||
volume.value = Math.min(volume.value + 0.1, 1);
|
||||
}
|
||||
'up': {
|
||||
allowRepeat: true,
|
||||
callback: () => {
|
||||
if (hasFocus() && audioEl.value) {
|
||||
volume.value = Math.min(volume.value + 0.1, 1);
|
||||
}
|
||||
},
|
||||
},
|
||||
'down': () => {
|
||||
if (hasFocus() && audioEl.value) {
|
||||
volume.value = Math.max(volume.value - 0.1, 0);
|
||||
}
|
||||
'down': {
|
||||
allowRepeat: true,
|
||||
callback: () => {
|
||||
if (hasFocus() && audioEl.value) {
|
||||
volume.value = Math.max(volume.value - 0.1, 0);
|
||||
}
|
||||
},
|
||||
},
|
||||
'left': () => {
|
||||
if (hasFocus() && audioEl.value) {
|
||||
audioEl.value.currentTime = Math.max(audioEl.value.currentTime - 5, 0);
|
||||
}
|
||||
'left': {
|
||||
allowRepeat: true,
|
||||
callback: () => {
|
||||
if (hasFocus() && audioEl.value) {
|
||||
audioEl.value.currentTime = Math.max(audioEl.value.currentTime - 5, 0);
|
||||
}
|
||||
},
|
||||
},
|
||||
'right': () => {
|
||||
if (hasFocus() && audioEl.value) {
|
||||
audioEl.value.currentTime = Math.min(audioEl.value.currentTime + 5, audioEl.value.duration);
|
||||
}
|
||||
'right': {
|
||||
allowRepeat: true,
|
||||
callback: () => {
|
||||
if (hasFocus() && audioEl.value) {
|
||||
audioEl.value.currentTime = Math.min(audioEl.value.currentTime + 5, audioEl.value.duration);
|
||||
}
|
||||
},
|
||||
},
|
||||
'space': () => {
|
||||
if (hasFocus()) {
|
||||
togglePlayPause();
|
||||
}
|
||||
},
|
||||
};
|
||||
} as const satisfies Keymap;
|
||||
|
||||
// PlayerElもしくはその子要素にフォーカスがあるかどうか
|
||||
function hasFocus() {
|
||||
|
@@ -112,6 +112,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
import { ref, shallowRef, computed, watch, onDeactivated, onActivated, onMounted } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import type { MenuItem } from '@/types/menu.js';
|
||||
import { type Keymap } from '@/scripts/hotkey.js';
|
||||
import bytes from '@/filters/bytes.js';
|
||||
import { hms } from '@/filters/hms.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
@@ -127,32 +128,44 @@ const props = defineProps<{
|
||||
}>();
|
||||
|
||||
const keymap = {
|
||||
'up': () => {
|
||||
if (hasFocus() && videoEl.value) {
|
||||
volume.value = Math.min(volume.value + 0.1, 1);
|
||||
}
|
||||
'up': {
|
||||
allowRepeat: true,
|
||||
callback: () => {
|
||||
if (hasFocus() && videoEl.value) {
|
||||
volume.value = Math.min(volume.value + 0.1, 1);
|
||||
}
|
||||
},
|
||||
},
|
||||
'down': () => {
|
||||
if (hasFocus() && videoEl.value) {
|
||||
volume.value = Math.max(volume.value - 0.1, 0);
|
||||
}
|
||||
'down': {
|
||||
allowRepeat: true,
|
||||
callback: () => {
|
||||
if (hasFocus() && videoEl.value) {
|
||||
volume.value = Math.max(volume.value - 0.1, 0);
|
||||
}
|
||||
},
|
||||
},
|
||||
'left': () => {
|
||||
if (hasFocus() && videoEl.value) {
|
||||
videoEl.value.currentTime = Math.max(videoEl.value.currentTime - 5, 0);
|
||||
}
|
||||
'left': {
|
||||
allowRepeat: true,
|
||||
callback: () => {
|
||||
if (hasFocus() && videoEl.value) {
|
||||
videoEl.value.currentTime = Math.max(videoEl.value.currentTime - 5, 0);
|
||||
}
|
||||
},
|
||||
},
|
||||
'right': () => {
|
||||
if (hasFocus() && videoEl.value) {
|
||||
videoEl.value.currentTime = Math.min(videoEl.value.currentTime + 5, videoEl.value.duration);
|
||||
}
|
||||
'right': {
|
||||
allowRepeat: true,
|
||||
callback: () => {
|
||||
if (hasFocus() && videoEl.value) {
|
||||
videoEl.value.currentTime = Math.min(videoEl.value.currentTime + 5, videoEl.value.duration);
|
||||
}
|
||||
},
|
||||
},
|
||||
'space': () => {
|
||||
if (hasFocus()) {
|
||||
togglePlayPause();
|
||||
}
|
||||
},
|
||||
};
|
||||
} as const satisfies Keymap;
|
||||
|
||||
// PlayerElもしくはその子要素にフォーカスがあるかどうか
|
||||
function hasFocus() {
|
||||
|
@@ -98,6 +98,7 @@ import { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuRadio
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { isTouchUsing } from '@/scripts/touch.js';
|
||||
import { type Keymap } from '@/scripts/hotkey.js';
|
||||
|
||||
const childrenCache = new WeakMap<MenuParent, MenuItem[]>();
|
||||
</script>
|
||||
@@ -125,11 +126,20 @@ const items2 = ref<InnerMenuItem[]>();
|
||||
|
||||
const child = shallowRef<InstanceType<typeof XChild>>();
|
||||
|
||||
const keymap = computed(() => ({
|
||||
'up|k|shift+tab': focusUp,
|
||||
'down|j|tab': focusDown,
|
||||
'esc': close,
|
||||
}));
|
||||
const keymap = {
|
||||
'up|k|shift+tab': {
|
||||
allowRepeat: true,
|
||||
callback: () => focusUp(),
|
||||
},
|
||||
'down|j|tab': {
|
||||
allowRepeat: true,
|
||||
callback: () => focusDown(),
|
||||
},
|
||||
'esc': {
|
||||
allowRepeat: true,
|
||||
callback: () => close(false),
|
||||
},
|
||||
} as const satisfies Keymap;
|
||||
|
||||
const childShowingItem = ref<MenuItem | null>();
|
||||
|
||||
|
@@ -47,6 +47,7 @@ import * as os from '@/os.js';
|
||||
import { isTouchUsing } from '@/scripts/touch.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { deviceKind } from '@/scripts/device-kind.js';
|
||||
import { type Keymap } from '@/scripts/hotkey.js';
|
||||
|
||||
function getFixedContainer(el: Element | null): Element | null {
|
||||
if (el == null || el.tagName === 'BODY') return null;
|
||||
@@ -154,8 +155,11 @@ if (type.value === 'drawer') {
|
||||
}
|
||||
|
||||
const keymap = {
|
||||
'esc': () => emit('esc'),
|
||||
};
|
||||
'esc': {
|
||||
allowRepeat: true,
|
||||
callback: () => emit('esc'),
|
||||
},
|
||||
} as const satisfies Keymap;
|
||||
|
||||
const MARGIN = 16;
|
||||
const SCROLLBAR_THICKNESS = 16;
|
||||
|
@@ -198,6 +198,7 @@ import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
|
||||
import { shouldCollapsed } from '@/scripts/collapsed.js';
|
||||
import { isEnabledUrlPreview } from '@/instance.js';
|
||||
import { type Keymap } from '@/scripts/hotkey.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
note: Misskey.entities.Note;
|
||||
@@ -294,15 +295,53 @@ function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string
|
||||
}
|
||||
|
||||
const keymap = {
|
||||
'r': () => reply(true),
|
||||
'e|a|plus': () => react(true),
|
||||
'q': () => renote(true),
|
||||
'up|k|shift+tab': focusBefore,
|
||||
'down|j|tab': focusAfter,
|
||||
'esc': blur,
|
||||
'm|o': () => showMenu(true),
|
||||
's': () => showContent.value !== showContent.value,
|
||||
};
|
||||
'r': () => {
|
||||
if (renoteCollapsed.value) return;
|
||||
reply();
|
||||
},
|
||||
'e|a|plus': () => {
|
||||
if (renoteCollapsed.value) return;
|
||||
react();
|
||||
},
|
||||
'q': () => {
|
||||
if (renoteCollapsed.value) return;
|
||||
renote();
|
||||
},
|
||||
'm': () => {
|
||||
if (renoteCollapsed.value) return;
|
||||
showMenu();
|
||||
},
|
||||
'c': () => {
|
||||
if (renoteCollapsed.value) return;
|
||||
if (!defaultStore.state.showClipButtonInNoteFooter) return;
|
||||
clip();
|
||||
},
|
||||
'o': () => {
|
||||
if (renoteCollapsed.value) return;
|
||||
galleryEl.value?.openGallery();
|
||||
},
|
||||
'v|enter': () => {
|
||||
if (renoteCollapsed.value) {
|
||||
renoteCollapsed.value = false;
|
||||
} else if (appearNote.value.cw != null) {
|
||||
showContent.value = !showContent.value;
|
||||
} else if (isLong) {
|
||||
collapsed.value = !collapsed.value;
|
||||
}
|
||||
},
|
||||
'esc': {
|
||||
allowRepeat: true,
|
||||
callback: () => blur(),
|
||||
},
|
||||
'up|k|shift+tab': {
|
||||
allowRepeat: true,
|
||||
callback: () => focusBefore(),
|
||||
},
|
||||
'down|j|tab': {
|
||||
allowRepeat: true,
|
||||
callback: () => focusAfter(),
|
||||
},
|
||||
} as const satisfies Keymap;
|
||||
|
||||
provide('react', (reaction: string) => {
|
||||
misskeyApi('notes/reactions/create', {
|
||||
|
@@ -233,6 +233,7 @@ import MkPagination, { type Paging } from '@/components/MkPagination.vue';
|
||||
import MkReactionIcon from '@/components/MkReactionIcon.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import { isEnabledUrlPreview } from '@/instance.js';
|
||||
import { type Keymap } from '@/scripts/hotkey.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
note: Misskey.entities.Note;
|
||||
@@ -294,13 +295,24 @@ const replies = ref<Misskey.entities.Note[]>([]);
|
||||
const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || appearNote.value.userId === $i?.id);
|
||||
|
||||
const keymap = {
|
||||
'r': () => reply(true),
|
||||
'e|a|plus': () => react(true),
|
||||
'q': () => renote(true),
|
||||
'esc': blur,
|
||||
'm|o': () => showMenu(true),
|
||||
's': () => showContent.value !== showContent.value,
|
||||
};
|
||||
'r': () => reply(),
|
||||
'e|a|plus': () => react(),
|
||||
'q': () => renote(),
|
||||
'm': () => showMenu(),
|
||||
'c': () => {
|
||||
if (!defaultStore.state.showClipButtonInNoteFooter) return;
|
||||
clip();
|
||||
},
|
||||
'v|enter': () => {
|
||||
if (appearNote.value.cw != null) {
|
||||
showContent.value = !showContent.value;
|
||||
}
|
||||
},
|
||||
'esc': {
|
||||
allowRepeat: true,
|
||||
callback: () => blur(),
|
||||
},
|
||||
} as const satisfies Keymap;
|
||||
|
||||
provide('react', (reaction: string) => {
|
||||
misskeyApi('notes/reactions/create', {
|
||||
|
Reference in New Issue
Block a user