feat: custom shortcuts

This commit is contained in:
qier222 2021-06-09 20:39:00 +08:00
parent 78d90f15f5
commit e54c606c6d
No known key found for this signature in database
GPG Key ID: 9C85007ED905F14D
9 changed files with 439 additions and 56 deletions

View File

@ -366,14 +366,10 @@ class Background {
this.initOSDLyrics();
// init ipcMain
initIpcMain(
this.window,
{
resizeOSDLyrics: height => this.resizeOSDLyrics(height),
toggleOSDLyrics: () => this.toggleOSDLyrics(),
},
this.store
);
initIpcMain(this.window, this.store, {
resizeOSDLyrics: height => this.resizeOSDLyrics(height),
toggleOSDLyrics: () => this.toggleOSDLyrics(),
});
// set proxy
const proxyRules = this.store.get('proxy');
@ -387,13 +383,7 @@ class Background {
this.checkForUpdates();
// create menu
createMenu(this.window, {
openDevTools: () => {
if (this.osdlyrics) {
this.osdlyrics.webContents.openDevTools();
}
},
});
createMenu(this.window, this.store);
// create tray
if (
@ -411,7 +401,7 @@ class Background {
// register global shortcuts
if (this.store.get('settings.enableGlobalShortcut')) {
registerGlobalShortcut(this.window);
registerGlobalShortcut(this.window, this.store);
}
});

View File

@ -1,25 +1,58 @@
import defaultShortcuts from '@/utils/shortcuts';
const { globalShortcut } = require('electron');
export function registerGlobalShortcut(win) {
globalShortcut.register('Alt+CommandOrControl+P', () => {
win.webContents.send('play');
});
globalShortcut.register('Alt+CommandOrControl+Right', () => {
win.webContents.send('next');
});
globalShortcut.register('Alt+CommandOrControl+Left', () => {
win.webContents.send('previous');
});
globalShortcut.register('Alt+CommandOrControl+Up', () => {
win.webContents.send('increaseVolume');
});
globalShortcut.register('Alt+CommandOrControl+Down', () => {
win.webContents.send('decreaseVolume');
});
globalShortcut.register('Alt+CommandOrControl+L', () => {
win.webContents.send('like');
});
globalShortcut.register('Alt+CommandOrControl+M', () => {
win.isVisible() ? win.hide() : win.show();
});
const clc = require('cli-color');
const log = text => {
console.log(`${clc.blueBright('[globalShortcut.js]')} ${text}`);
};
export function registerGlobalShortcut(win, store) {
log('registerGlobalShortcut');
let shortcuts = store.get('settings.shortcuts');
if (shortcuts === undefined) {
shortcuts = defaultShortcuts;
}
globalShortcut.register(
shortcuts.find(s => s.id === 'play').globalShortcut,
() => {
win.webContents.send('play');
}
);
globalShortcut.register(
shortcuts.find(s => s.id === 'next').globalShortcut,
() => {
win.webContents.send('next');
}
);
globalShortcut.register(
shortcuts.find(s => s.id === 'previous').globalShortcut,
() => {
win.webContents.send('previous');
}
);
globalShortcut.register(
shortcuts.find(s => s.id === 'increaseVolume').globalShortcut,
() => {
win.webContents.send('increaseVolume');
}
);
globalShortcut.register(
shortcuts.find(s => s.id === 'decreaseVolume').globalShortcut,
() => {
win.webContents.send('decreaseVolume');
}
);
globalShortcut.register(
shortcuts.find(s => s.id === 'like').globalShortcut,
() => {
win.webContents.send('like');
}
);
globalShortcut.register(
shortcuts.find(s => s.id === 'minimize').globalShortcut,
() => {
win.isVisible() ? win.hide() : win.show();
}
);
}

View File

@ -1,10 +1,18 @@
import { app, dialog, globalShortcut, ipcMain } from 'electron';
import match from '@revincx/unblockneteasemusic';
import { registerGlobalShortcut } from '@/electron/globalShortcut';
import cloneDeep from 'lodash/cloneDeep';
import shortcuts from '@/utils/shortcuts';
import { createMenu } from './menu';
const clc = require('cli-color');
const log = text => {
console.log(`${clc.blueBright('[ipcMain.js]')} ${text}`);
};
const client = require('discord-rich-presence')('818936529484906596');
export function initIpcMain(win, lrc, store) {
export function initIpcMain(win, store, lrc) {
ipcMain.on('unblock-music', (event, track) => {
// 兼容 unblockneteasemusic 所使用的 api 字段
track.alias = track.alia || [];
@ -23,7 +31,7 @@ export function initIpcMain(win, lrc, store) {
event.returnValue = res;
})
.catch(err => {
console.log('unblock music error: ', err);
log('unblock music error: ', err);
event.returnValue = null;
});
});
@ -53,7 +61,7 @@ export function initIpcMain(win, lrc, store) {
}
})
.catch(err => {
console.log(err);
log(err);
});
});
@ -69,13 +77,10 @@ export function initIpcMain(win, lrc, store) {
ipcMain.on('settings', (event, options) => {
store.set('settings', options);
const isRegisterShortcut = globalShortcut.isRegistered(
'Alt+CommandOrControl+P'
);
if (options.enableGlobalShortcut) {
!isRegisterShortcut && registerGlobalShortcut(win);
registerGlobalShortcut(win, store);
} else {
isRegisterShortcut && globalShortcut.unregisterAll();
globalShortcut.unregisterAll();
}
});
@ -112,13 +117,13 @@ export function initIpcMain(win, lrc, store) {
proxyRules,
},
() => {
console.log('finished setProxy');
log('finished setProxy');
}
);
});
ipcMain.on('removeProxy', (event, arg) => {
console.log('removeProxy');
log('removeProxy');
win.webContents.session.setProxy({});
store.set('proxy', '');
});
@ -130,4 +135,33 @@ export function initIpcMain(win, lrc, store) {
ipcMain.on('toggleOSDLyrics', () => {
lrc.toggleOSDLyrics();
});
ipcMain.on('switchGlobalShortcutStatusTemporary', (e, status) => {
if (status === 'disable') {
globalShortcut.unregisterAll();
} else {
registerGlobalShortcut(win, store);
}
});
ipcMain.on('updateShortcut', (e, { id, type, shortcut }) => {
log('updateShortcut');
let shortcuts = store.get('settings.shortcuts');
let newShortcut = shortcuts.find(s => s.id === id);
newShortcut[type] = shortcut;
store.set('settings.shortcuts', shortcuts);
createMenu(win, store);
globalShortcut.unregisterAll();
registerGlobalShortcut(win, store);
});
ipcMain.on('restoreDefaultShortcuts', () => {
log('restoreDefaultShortcuts');
store.set('settings.shortcuts', cloneDeep(shortcuts));
createMenu(win, store);
globalShortcut.unregisterAll();
registerGlobalShortcut(win, store);
});
}

View File

@ -1,10 +1,16 @@
import defaultShortcuts from '@/utils/shortcuts';
const { app, Menu } = require('electron');
// import { autoUpdater } from "electron-updater"
// const version = app.getVersion();
const isMac = process.platform === 'darwin';
export function createMenu(win, lrc) {
export function createMenu(win, store, lrc) {
let shortcuts = store.get('settings.shortcuts');
if (shortcuts === undefined) {
shortcuts = defaultShortcuts;
}
let menu = null;
const template = [
...(isMac
@ -19,7 +25,7 @@ export function createMenu(win, lrc) {
{ type: 'separator' },
{
label: 'Preferences...',
accelerator: (() => (isMac ? 'CmdOrCtrl+,' : 'Ctrl+,'))(),
accelerator: 'CmdOrCtrl+,',
click: () => {
win.webContents.send('changeRouteTo', '/settings');
},
@ -69,41 +75,42 @@ export function createMenu(win, lrc) {
submenu: [
{
label: 'Play',
accelerator: shortcuts.find(s => s.id === 'play').shortcut,
click: () => {
win.webContents.send('play');
},
},
{
label: 'Next',
accelerator: 'CmdOrCtrl+Right',
accelerator: shortcuts.find(s => s.id === 'next').shortcut,
click: () => {
win.webContents.send('next');
},
},
{
label: 'Previous',
accelerator: 'CmdOrCtrl+Left',
accelerator: shortcuts.find(s => s.id === 'previous').shortcut,
click: () => {
win.webContents.send('previous');
},
},
{
label: 'Increase Volume',
accelerator: 'CmdOrCtrl+Up',
accelerator: shortcuts.find(s => s.id === 'increaseVolume').shortcut,
click: () => {
win.webContents.send('increaseVolume');
},
},
{
label: 'Decrease Volume',
accelerator: 'CmdOrCtrl+Down',
accelerator: shortcuts.find(s => s.id === 'decreaseVolume').shortcut,
click: () => {
win.webContents.send('decreaseVolume');
},
},
{
label: 'Like',
accelerator: 'CmdOrCtrl+L',
accelerator: shortcuts.find(s => s.id === 'like').shortcut,
click: () => {
win.webContents.send('like');
},
@ -208,6 +215,7 @@ export function createMenu(win, lrc) {
// ],
// });
// }
menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
}

View File

@ -1,4 +1,5 @@
import { playlistCategories } from '@/utils/staticData';
import shortcuts from '@/utils/shortcuts';
console.debug('[debug][initLocalStorage.js]');
const enabledPlaylistCategories = playlistCategories
@ -31,6 +32,7 @@ let localStorage = {
server: '',
port: null,
},
shortcuts: shortcuts,
},
data: {
user: {},

View File

@ -1,4 +1,6 @@
import { disableScrolling, enableScrolling } from '@/utils/ui';
import shortcuts from '@/utils/shortcuts';
import cloneDeep from 'lodash/cloneDeep';
export default {
updateLikedXXX(state, { name, data }) {
@ -58,4 +60,15 @@ export default {
updateLastfm(state, session) {
state.lastfm = session;
},
updateShortcut(state, { id, type, shortcut }) {
let newShortcut = state.settings.shortcuts.find(s => s.id === id);
newShortcut[type] = shortcut;
state.settings.shortcuts = state.settings.shortcuts.map(s => {
if (s.id !== id) return s;
return newShortcut;
});
},
restoreDefaultShortcuts(state) {
state.settings.shortcuts = cloneDeep(shortcuts);
},
};

47
src/utils/shortcuts.js Normal file
View File

@ -0,0 +1,47 @@
// default shortcuts
// for more info, check https://www.electronjs.org/docs/api/accelerator
export default [
{
id: 'play',
name: '播放/暂停',
shortcut: 'CommandOrControl+P',
globalShortcut: 'Alt+CommandOrControl+P',
},
{
id: 'next',
name: '下一首',
shortcut: 'CommandOrControl+Right',
globalShortcut: 'Alt+CommandOrControl+Right',
},
{
id: 'previous',
name: '上一首',
shortcut: 'CommandOrControl+Left',
globalShortcut: 'Alt+CommandOrControl+Left',
},
{
id: 'increaseVolume',
name: '增加音量',
shortcut: 'CommandOrControl+Up',
globalShortcut: 'Alt+CommandOrControl+Up',
},
{
id: 'decreaseVolume',
name: '减少音量',
shortcut: 'CommandOrControl+Down',
globalShortcut: 'Alt+CommandOrControl+Down',
},
{
id: 'like',
name: '喜欢歌曲',
shortcut: 'CommandOrControl+L',
globalShortcut: 'Alt+CommandOrControl+L',
},
{
id: 'minimize',
name: '隐藏/显示播放器',
shortcut: 'CommandOrControl+M',
globalShortcut: 'Alt+CommandOrControl+M',
},
];

View File

@ -8,6 +8,21 @@ const updateSetting = () => {
...parsedSettings,
};
if (
settings.shortcuts.length !== initLocalStorage.settings.shortcuts.length
) {
// 当新增 shortcuts 时
const oldShortcutsId = settings.shortcuts.map(s => s.id);
const newShortcutsId = initLocalStorage.settings.shortcuts.filter(
s => oldShortcutsId.includes(s.id) === false
);
newShortcutsId.map(id => {
settings.shortcuts.push(
initLocalStorage.settings.shortcuts.find(s => s.id === id)
);
});
}
localStorage.setItem('settings', JSON.stringify(settings));
};

View File

@ -1,5 +1,5 @@
<template>
<div class="settings-page">
<div class="settings-page" @click="clickOutside">
<div class="container">
<div v-if="showUserInfo" class="user">
<div class="left">
@ -141,6 +141,7 @@
<option :value="1024"> 1GB </option>
<option :value="2048"> 2GB </option>
<option :value="4096"> 4GB </option>
<option :value="8192"> 8GB </option>
</select>
</div>
</div>
@ -402,6 +403,69 @@
</div>
</div>
</div>
<div
id="shortcut-table"
:class="{ 'global-disabled': !enableGlobalShortcut }"
tabindex="0"
@keydown="handleShortcutKeydown"
>
<div class="row row-head">
<div class="col">功能</div>
<div class="col">快捷键</div>
<div class="col">全局快捷键</div>
</div>
<div
v-for="shortcut in settings.shortcuts"
:key="shortcut.id"
class="row"
>
<div class="col">{{ shortcut.name }}</div>
<div class="col">
<div
class="keyboard-input"
:class="{
active:
shortcutInput.id === shortcut.id &&
shortcutInput.type === 'shortcut',
}"
@click.stop="readyToRecordShortcut(shortcut.id, 'shortcut')"
>
{{
shortcutInput.id === shortcut.id &&
shortcutInput.type === 'shortcut' &&
recordedShortcutComputed !== ''
? formatShortcut(recordedShortcutComputed)
: formatShortcut(shortcut.shortcut)
}}
</div>
</div>
<div class="col">
<div
class="keyboard-input"
:class="{
active:
shortcutInput.id === shortcut.id &&
shortcutInput.type === 'globalShortcut',
}"
@click.stop="
readyToRecordShortcut(shortcut.id, 'globalShortcut')
"
>{{
shortcutInput.id === shortcut.id &&
shortcutInput.type === 'globalShortcut' &&
recordedShortcutComputed !== ''
? formatShortcut(recordedShortcutComputed)
: formatShortcut(shortcut.globalShortcut)
}}</div
>
</div>
</div>
<button
class="restore-default-shortcut"
@click="restoreDefaultShortcuts"
>恢复默认快捷键</button
>
</div>
</div>
<div class="footer">
@ -428,6 +492,8 @@ const electron =
const ipcRenderer =
process.env.IS_ELECTRON === true ? electron.ipcRenderer : null;
const validShortcutCodes = ['=', '-', '~', '[', ']', ';', "'", ',', '.', '/'];
export default {
name: 'Settings',
data() {
@ -442,6 +508,12 @@ export default {
label: 'settings.permissionRequired',
},
],
shortcutInput: {
id: '',
type: '',
recording: false,
},
recordedShortcut: [],
};
},
computed: {
@ -458,6 +530,51 @@ export default {
showUserInfo() {
return isLooseLoggedIn() && this.data.user.nickname;
},
recordedShortcutComputed() {
let shortcut = [];
this.recordedShortcut.map(e => {
if (e.keyCode >= 65 && e.keyCode <= 90) {
// A-Z
shortcut.push(e.code.replace('Key', ''));
} else if (e.key === 'Meta') {
// Command on macOS
shortcut.push('Command');
} else if (['Alt', 'Control', 'Shift'].includes(e.key)) {
shortcut.push(e.key);
} else if (e.keyCode >= 48 && e.keyCode <= 57) {
// 0-9
shortcut.push(e.code.replace('Digit', ''));
} else if (e.keyCode >= 112 && e.keyCode <= 123) {
// F1-F12
shortcut.push(e.code);
} else if (
['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(e.key)
) {
// Arrows
shortcut.push(e.code.replace('Arrow', ''));
} else if (validShortcutCodes.includes(e.key)) {
shortcut.push(e.key);
}
});
const sortTable = {
Control: 1,
Shift: 2,
Alt: 3,
Command: 4,
};
shortcut = shortcut.sort((a, b) => {
if (!sortTable[a] || !sortTable[b]) return 0;
if (sortTable[a] - sortTable[b] <= -1) {
return -1;
} else if (sortTable[a] - sortTable[b] >= 1) {
return 1;
} else {
return 0;
}
});
shortcut = shortcut.join('+');
return shortcut;
},
lang: {
get() {
@ -786,6 +903,77 @@ export default {
}
this.showToast('已更新代理设置');
},
clickOutside() {
this.exitRecordShortcut();
},
formatShortcut(shortcut) {
shortcut = shortcut
.replaceAll('+', ' + ')
.replace('Up', '↑')
.replace('Down', '↓')
.replace('Right', '→')
.replace('Left', '←');
if (this.settings.lang === 'zh-CN') {
shortcut = shortcut.replace('Space', '空格');
}
if (process.platform === 'darwin') {
return shortcut
.replace('CommandOrControl', '⌘')
.replace('Command', '⌘')
.replace('Alt', '⌥')
.replace('Control', '⌃')
.replace('Shift', '⇧');
}
return shortcut.replace('CommandOrControl', 'Ctrl');
},
readyToRecordShortcut(id, type) {
this.shortcutInput = { id, type, recording: true };
this.recordedShortcut = [];
ipcRenderer.send('switchGlobalShortcutStatusTemporary', 'disable');
},
handleShortcutKeydown(e) {
if (this.shortcutInput.recording === false) return;
e.preventDefault();
if (this.recordedShortcut.find(s => s.keyCode === e.keyCode)) return;
this.recordedShortcut.push(e);
if (
(e.keyCode >= 65 && e.keyCode <= 90) || // A-Z
(e.keyCode >= 48 && e.keyCode <= 57) || // 0-9
(e.keyCode >= 112 && e.keyCode <= 123) || // F1-F12
['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(e.key) || // Arrows
validShortcutCodes.includes(e.key)
) {
this.saveShortcut();
}
},
handleShortcutKeyup(e) {
if (this.recordedShortcut.find(s => s.keyCode === e.keyCode)) {
this.recordedShortcut = this.recordedShortcut.filter(
s => s.keyCode !== e.keyCode
);
}
},
saveShortcut() {
const { id, type } = this.shortcutInput;
const payload = {
id,
type,
shortcut: this.recordedShortcutComputed,
};
this.$store.commit('updateShortcut', payload);
ipcRenderer.send('updateShortcut', payload);
this.showToast('快捷键已保存');
this.recordedShortcut = [];
},
exitRecordShortcut() {
this.shortcutInput = { id: '', type: '', recording: false };
this.recordedShortcut = [];
ipcRenderer.send('switchGlobalShortcutStatusTemporary', 'enable');
},
restoreDefaultShortcuts() {
this.$store.commit('restoreDefaultShortcuts');
ipcRenderer.send('restoreDefaultShortcuts');
},
},
};
</script>
@ -963,6 +1151,59 @@ input[type='number'] {
}
}
#shortcut-table {
font-size: 14px;
/* border: 1px solid black; */
user-select: none;
color: var(--color-text);
.row {
display: flex;
}
.row.row-head {
opacity: 0.58;
font-size: 13px;
font-weight: 500;
}
.col {
min-width: 192px;
padding: 8px;
display: flex;
align-items: center;
/* border: 1px solid red; */
&:first-of-type {
padding-left: 0;
min-width: 128px;
}
}
.keyboard-input {
font-weight: 600;
background-color: var(--color-secondary-bg);
padding: 8px 12px 8px 12px;
border-radius: 0.5rem;
min-width: 146px;
min-height: 34px;
box-sizing: border-box;
&.active {
color: var(--color-primary);
background-color: var(--color-primary-bg);
}
}
.restore-default-shortcut {
margin-top: 12px;
}
&.global-disabled {
.row .col:last-child {
opacity: 0.48;
}
.row.row-head .col:last-child {
opacity: 1;
}
}
&:focus {
outline: none;
}
}
.footer {
text-align: center;
margin-top: 6rem;