mirror of
https://github.com/Kong/insomnia
synced 2024-11-08 23:00:30 +00:00
516 lines
16 KiB
JavaScript
516 lines
16 KiB
JavaScript
// @flow
|
||
import { keyboardKeys } from './keyboard-keys';
|
||
import { ALT_SYM, CTRL_SYM, isMac, META_SYM, SHIFT_SYM } from './constants';
|
||
|
||
/**
|
||
* The readable definition of a hotkey.
|
||
* The {@code id} the hotkey's reference id.
|
||
*/
|
||
export type HotKeyDefinition = {
|
||
id: string,
|
||
description: string,
|
||
};
|
||
|
||
/**
|
||
* The combination of key presses that will activate a hotkey if pressed.
|
||
*/
|
||
export type KeyCombination = {
|
||
ctrl: boolean,
|
||
alt: boolean,
|
||
shift: boolean,
|
||
meta: boolean,
|
||
keyCode: number,
|
||
};
|
||
|
||
/**
|
||
* The collection of a hotkey's key combinations for each platforms.
|
||
*/
|
||
export type KeyBindings = {
|
||
macKeys: Array<KeyCombination>,
|
||
// The key combinations for both Windows and Linux.
|
||
winLinuxKeys: Array<KeyCombination>,
|
||
};
|
||
|
||
/**
|
||
* The collection of defined hotkeys.
|
||
* The registry maps a hotkey by its reference id to its key bindings.
|
||
*/
|
||
export type HotKeyRegistry = {
|
||
[refId: string]: KeyBindings,
|
||
};
|
||
|
||
function defineHotKey(id: string, description: string): HotKeyDefinition {
|
||
return {
|
||
id: id,
|
||
description: description,
|
||
};
|
||
}
|
||
|
||
function keyComb(
|
||
ctrl: boolean,
|
||
alt: boolean,
|
||
shift: boolean,
|
||
meta: boolean,
|
||
keyCode: number,
|
||
): KeyCombination {
|
||
return {
|
||
ctrl: ctrl,
|
||
alt: alt,
|
||
shift: shift,
|
||
meta: meta,
|
||
keyCode: keyCode,
|
||
};
|
||
}
|
||
|
||
function keyBinds(
|
||
mac: KeyCombination | Array<KeyCombination>,
|
||
winLinux: KeyCombination | Array<KeyCombination>,
|
||
): KeyBindings {
|
||
if (!Array.isArray(mac)) {
|
||
mac = [mac];
|
||
}
|
||
|
||
if (!Array.isArray(winLinux)) {
|
||
winLinux = [winLinux];
|
||
}
|
||
|
||
return {
|
||
macKeys: mac,
|
||
winLinuxKeys: winLinux,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* The collection of available hotkeys' and their definitions.
|
||
*/
|
||
// Not using dot, because NeDB prohibits field names to contain dots.
|
||
export const hotKeyRefs = {
|
||
WORKSPACE_SHOW_SETTINGS: defineHotKey('workspace_showSettings', 'Show Workspace Settings'),
|
||
|
||
REQUEST_SHOW_SETTINGS: defineHotKey('request_showSettings', 'Show Request Settings'),
|
||
|
||
PREFERENCES_SHOW_KEYBOARD_SHORTCUTS: defineHotKey(
|
||
'preferences_showKeyboardShortcuts',
|
||
'Show Keyboard Shortcuts',
|
||
),
|
||
|
||
PREFERENCES_SHOW_GENERAL: defineHotKey('preferences_showGeneral', 'Show App Preferences'),
|
||
|
||
TOGGLE_MAIN_MENU: defineHotKey('toggleMainMenu', 'Toggle Main Menu'),
|
||
|
||
REQUEST_QUICK_SWITCH: defineHotKey('request_quickSwitch', 'Switch Requests'),
|
||
|
||
SHOW_RECENT_REQUESTS: defineHotKey('request_showRecent', 'Show Recent Requests'),
|
||
|
||
SHOW_RECENT_REQUESTS_PREVIOUS: defineHotKey(
|
||
'request_showRecentPrevious',
|
||
'Show Recent Requests (Previous)',
|
||
),
|
||
|
||
PLUGIN_RELOAD: defineHotKey('plugin_reload', 'Reload Plugins'),
|
||
|
||
SHOW_AUTOCOMPLETE: defineHotKey('showAutocomplete', 'Show Autocomplete'),
|
||
|
||
REQUEST_SEND: defineHotKey('request_send', 'Send Request'),
|
||
|
||
REQUEST_SHOW_OPTIONS: defineHotKey('request_showOptions', 'Send Request (Options)'),
|
||
|
||
ENVIRONMENT_SHOW_EDITOR: defineHotKey('environment_showEditor', 'Show Environment Editor'),
|
||
|
||
ENVIRONMENT_SHOW_SWITCH_MENU: defineHotKey('environment_showSwitchMenu', 'Switch Environments'),
|
||
|
||
REQUEST_TOGGLE_HTTP_METHOD_MENU: defineHotKey(
|
||
'request_toggleHttpMethodMenu',
|
||
'Change HTTP Method',
|
||
),
|
||
|
||
REQUEST_TOGGLE_HISTORY: defineHotKey('request_toggleHistory', 'Show Request History'),
|
||
|
||
REQUEST_FOCUS_URL: defineHotKey('request_focusUrl', 'Focus URL'),
|
||
|
||
REQUEST_SHOW_GENERATE_CODE_EDITOR: defineHotKey(
|
||
'request_showGenerateCodeEditor',
|
||
'Generate Code',
|
||
),
|
||
|
||
SIDEBAR_FOCUS_FILTER: defineHotKey('sidebar_focusFilter', 'Filter Sidebar'),
|
||
|
||
RESPONSE_FOCUS: defineHotKey('response_focus', 'Focus Response'),
|
||
|
||
SHOW_COOKIES_EDITOR: defineHotKey('showCookiesEditor', 'Edit Cookies'),
|
||
|
||
REQUEST_SHOW_CREATE: defineHotKey('request_showCreate', 'Create Request'),
|
||
|
||
REQUEST_QUICK_CREATE: defineHotKey('request_quickCreate', 'Create Request (Quick)'),
|
||
|
||
REQUEST_SHOW_DELETE: defineHotKey('request_showDelete', 'Delete Request'),
|
||
|
||
REQUEST_SHOW_CREATE_FOLDER: defineHotKey('request_showCreateFolder', 'Create Folder'),
|
||
|
||
REQUEST_SHOW_DUPLICATE: defineHotKey('request_showDuplicate', 'Duplicate Request'),
|
||
|
||
REQUEST_TOGGLE_PIN: defineHotKey('request_togglePin', 'Pin/Unpin Request'),
|
||
|
||
CLOSE_DROPDOWN: defineHotKey('closeDropdown', 'Close Dropdown'),
|
||
|
||
CLOSE_MODAL: defineHotKey('closeModal', 'Close Modal'),
|
||
|
||
ENVIRONMENT_UNCOVER_VARIABLES: defineHotKey('environment_uncoverVariables', 'Uncover Variables'),
|
||
};
|
||
|
||
/**
|
||
* The default key bindings values of all available hotkeys.
|
||
*/
|
||
const defaultRegistry: HotKeyRegistry = {
|
||
[hotKeyRefs.WORKSPACE_SHOW_SETTINGS.id]: keyBinds(
|
||
keyComb(false, false, true, true, keyboardKeys.comma.keyCode),
|
||
keyComb(true, false, true, false, keyboardKeys.comma.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.REQUEST_SHOW_SETTINGS.id]: keyBinds(
|
||
keyComb(false, true, true, true, keyboardKeys.comma.keyCode),
|
||
keyComb(true, true, true, false, keyboardKeys.comma.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.PREFERENCES_SHOW_KEYBOARD_SHORTCUTS.id]: keyBinds(
|
||
keyComb(false, false, true, true, keyboardKeys.forwardslash.keyCode),
|
||
keyComb(true, false, true, false, keyboardKeys.forwardslash.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.PREFERENCES_SHOW_GENERAL.id]: keyBinds(
|
||
keyComb(false, false, false, true, keyboardKeys.comma.keyCode),
|
||
keyComb(true, false, false, false, keyboardKeys.comma.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.TOGGLE_MAIN_MENU.id]: keyBinds(
|
||
keyComb(false, true, false, true, keyboardKeys.comma.keyCode),
|
||
keyComb(true, true, false, false, keyboardKeys.comma.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.REQUEST_QUICK_SWITCH.id]: keyBinds(
|
||
keyComb(false, false, false, true, keyboardKeys.p.keyCode),
|
||
keyComb(true, false, false, false, keyboardKeys.p.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.SHOW_RECENT_REQUESTS.id]: keyBinds(
|
||
keyComb(true, false, false, false, keyboardKeys.tab.keyCode),
|
||
keyComb(true, false, false, false, keyboardKeys.tab.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.SHOW_RECENT_REQUESTS_PREVIOUS.id]: keyBinds(
|
||
keyComb(true, false, true, false, keyboardKeys.tab.keyCode),
|
||
keyComb(true, false, true, false, keyboardKeys.tab.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.PLUGIN_RELOAD.id]: keyBinds(
|
||
keyComb(false, false, true, true, keyboardKeys.r.keyCode),
|
||
keyComb(true, false, true, false, keyboardKeys.r.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.SHOW_AUTOCOMPLETE.id]: keyBinds(
|
||
keyComb(true, false, false, false, keyboardKeys.space.keyCode),
|
||
keyComb(true, false, false, false, keyboardKeys.space.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.REQUEST_SEND.id]: keyBinds(
|
||
[
|
||
keyComb(false, false, false, true, keyboardKeys.enter.keyCode),
|
||
keyComb(false, false, false, true, keyboardKeys.r.keyCode),
|
||
keyComb(false, false, false, false, keyboardKeys.f5.keyCode),
|
||
],
|
||
[
|
||
keyComb(true, false, false, false, keyboardKeys.enter.keyCode),
|
||
keyComb(true, false, false, false, keyboardKeys.r.keyCode),
|
||
keyComb(false, false, false, false, keyboardKeys.f5.keyCode),
|
||
],
|
||
),
|
||
|
||
[hotKeyRefs.REQUEST_SHOW_OPTIONS.id]: keyBinds(
|
||
keyComb(false, false, true, true, keyboardKeys.enter.keyCode),
|
||
keyComb(true, false, true, false, keyboardKeys.enter.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.ENVIRONMENT_SHOW_EDITOR.id]: keyBinds(
|
||
keyComb(false, false, false, true, keyboardKeys.e.keyCode),
|
||
keyComb(true, false, false, false, keyboardKeys.e.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.ENVIRONMENT_SHOW_SWITCH_MENU.id]: keyBinds(
|
||
keyComb(false, false, true, true, keyboardKeys.e.keyCode),
|
||
keyComb(true, false, true, false, keyboardKeys.e.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.REQUEST_TOGGLE_HTTP_METHOD_MENU.id]: keyBinds(
|
||
keyComb(false, false, true, true, keyboardKeys.l.keyCode),
|
||
keyComb(true, false, true, false, keyboardKeys.l.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.REQUEST_TOGGLE_HISTORY.id]: keyBinds(
|
||
keyComb(false, false, true, true, keyboardKeys.h.keyCode),
|
||
keyComb(true, false, true, false, keyboardKeys.h.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.REQUEST_FOCUS_URL.id]: keyBinds(
|
||
keyComb(false, false, false, true, keyboardKeys.l.keyCode),
|
||
keyComb(true, false, false, false, keyboardKeys.l.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.REQUEST_SHOW_GENERATE_CODE_EDITOR.id]: keyBinds(
|
||
keyComb(false, false, true, true, keyboardKeys.g.keyCode),
|
||
keyComb(true, false, true, false, keyboardKeys.g.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.SIDEBAR_FOCUS_FILTER.id]: keyBinds(
|
||
keyComb(false, false, true, true, keyboardKeys.f.keyCode),
|
||
keyComb(true, false, true, false, keyboardKeys.f.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.RESPONSE_FOCUS.id]: keyBinds(
|
||
keyComb(false, false, false, true, keyboardKeys.singlequote.keyCode),
|
||
keyComb(true, false, false, false, keyboardKeys.singlequote.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.SHOW_COOKIES_EDITOR.id]: keyBinds(
|
||
keyComb(false, false, false, true, keyboardKeys.k.keyCode),
|
||
keyComb(true, false, false, false, keyboardKeys.k.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.REQUEST_SHOW_CREATE.id]: keyBinds(
|
||
keyComb(false, false, false, true, keyboardKeys.n.keyCode),
|
||
keyComb(true, false, false, false, keyboardKeys.n.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.REQUEST_QUICK_CREATE.id]: keyBinds(
|
||
keyComb(false, true, false, true, keyboardKeys.n.keyCode),
|
||
keyComb(true, true, false, false, keyboardKeys.n.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.REQUEST_SHOW_DELETE.id]: keyBinds(
|
||
keyComb(false, false, true, true, keyboardKeys.delete.keyCode),
|
||
keyComb(true, false, true, false, keyboardKeys.delete.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.REQUEST_SHOW_CREATE_FOLDER.id]: keyBinds(
|
||
keyComb(false, false, true, true, keyboardKeys.n.keyCode),
|
||
keyComb(true, false, true, false, keyboardKeys.n.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.REQUEST_SHOW_DUPLICATE.id]: keyBinds(
|
||
keyComb(false, false, false, true, keyboardKeys.d.keyCode),
|
||
keyComb(true, false, false, false, keyboardKeys.d.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.REQUEST_TOGGLE_PIN.id]: keyBinds(
|
||
keyComb(false, false, true, true, keyboardKeys.p.keyCode),
|
||
keyComb(true, false, true, false, keyboardKeys.p.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.CLOSE_DROPDOWN.id]: keyBinds(
|
||
keyComb(false, false, false, false, keyboardKeys.esc.keyCode),
|
||
keyComb(false, false, false, false, keyboardKeys.esc.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.CLOSE_MODAL.id]: keyBinds(
|
||
keyComb(false, false, false, false, keyboardKeys.esc.keyCode),
|
||
keyComb(false, false, false, false, keyboardKeys.esc.keyCode),
|
||
),
|
||
|
||
[hotKeyRefs.ENVIRONMENT_UNCOVER_VARIABLES.id]: keyBinds(
|
||
keyComb(false, true, true, false, keyboardKeys.u.keyCode),
|
||
keyComb(false, true, true, false, keyboardKeys.u.keyCode),
|
||
),
|
||
};
|
||
|
||
function copyKeyCombs(sources: Array<KeyCombination>): Array<KeyCombination> {
|
||
let targets: Array<KeyCombination> = [];
|
||
sources.forEach(keyComb => {
|
||
targets.push(Object.assign({}, keyComb));
|
||
});
|
||
return targets;
|
||
}
|
||
|
||
/**
|
||
* Get a new copy of key bindings with default key combinations.
|
||
* @param hotKeyRefId
|
||
* @returns {KeyBindings}
|
||
*/
|
||
export function newDefaultKeyBindings(hotKeyRefId: string): KeyBindings {
|
||
const keyBindings: KeyBindings = defaultRegistry[hotKeyRefId];
|
||
return {
|
||
macKeys: copyKeyCombs(keyBindings.macKeys),
|
||
winLinuxKeys: copyKeyCombs(keyBindings.winLinuxKeys),
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Get a new copy of hotkey registry with default values.
|
||
* @returns {HotKeyRegistry}
|
||
*/
|
||
export function newDefaultRegistry(): HotKeyRegistry {
|
||
let newDefaults: HotKeyRegistry = {};
|
||
for (const refId in defaultRegistry) {
|
||
if (!defaultRegistry.hasOwnProperty(refId)) {
|
||
continue;
|
||
}
|
||
newDefaults[refId] = newDefaultKeyBindings(refId);
|
||
}
|
||
return newDefaults;
|
||
}
|
||
|
||
/**
|
||
* Get the key combinations based on the current platform.
|
||
* @param bindings
|
||
* @returns {Array<KeyCombination>}
|
||
*/
|
||
export function getPlatformKeyCombinations(bindings: KeyBindings): Array<KeyCombination> {
|
||
if (isMac()) {
|
||
return bindings.macKeys;
|
||
}
|
||
return bindings.winLinuxKeys;
|
||
}
|
||
|
||
/**
|
||
* Determine whether two key combinations are the same by comparing each of their keys.
|
||
* @param keyComb1
|
||
* @param keyComb2
|
||
* @returns {boolean}
|
||
*/
|
||
export function areSameKeyCombinations(
|
||
keyComb1: KeyCombination,
|
||
keyComb2: KeyCombination,
|
||
): boolean {
|
||
return (
|
||
keyComb1.alt === keyComb2.alt &&
|
||
keyComb1.shift === keyComb2.shift &&
|
||
keyComb1.ctrl === keyComb2.ctrl &&
|
||
keyComb1.meta === keyComb2.meta &&
|
||
keyComb1.keyCode === keyComb2.keyCode
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Checks whether the given key bindings is the same as the default one,
|
||
* identified with hot key reference id.
|
||
* @param hotKeyRefId refers to the default key bindings to check.
|
||
* @param keyBinds to check with the default ones.
|
||
* @returns {boolean}
|
||
*/
|
||
export function areKeyBindingsSameAsDefault(hotKeyRefId: string, keyBinds: KeyBindings): boolean {
|
||
const keyCombs = getPlatformKeyCombinations(keyBinds);
|
||
const defaultKeyCombs = getPlatformKeyCombinations(defaultRegistry[hotKeyRefId]);
|
||
if (keyCombs.length !== defaultKeyCombs.length) {
|
||
return false;
|
||
}
|
||
for (const keyComb of keyCombs) {
|
||
const found = defaultKeyCombs.find(defKeyComb => {
|
||
if (areSameKeyCombinations(keyComb, defKeyComb)) {
|
||
return true;
|
||
}
|
||
});
|
||
if (found == null) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Gets the displayed text of a key code.
|
||
* @param keyCode
|
||
* @returns {string}
|
||
*/
|
||
export function getChar(keyCode: number): string {
|
||
let char;
|
||
const key = Object.keys(keyboardKeys).find(k => keyboardKeys[k].keyCode === keyCode);
|
||
|
||
if (!key) {
|
||
console.error('Invalid key code', keyCode);
|
||
} else {
|
||
char = keyboardKeys[key].label;
|
||
}
|
||
|
||
return char || 'unknown';
|
||
}
|
||
|
||
function joinHotKeys(mustUsePlus: boolean, keys: Array<string>): string {
|
||
if (!mustUsePlus && isMac()) {
|
||
return keys.join('');
|
||
}
|
||
return keys.join('+');
|
||
}
|
||
|
||
/**
|
||
* Check whether key code is a modifier key, i.e., alt, shift, ctrl, or meta.
|
||
* @param keyCode
|
||
* @returns {boolean}
|
||
*/
|
||
export function isModifierKeyCode(keyCode: number): boolean {
|
||
return (
|
||
keyCode === keyboardKeys.alt.keyCode ||
|
||
keyCode === keyboardKeys.shift.keyCode ||
|
||
keyCode === keyboardKeys.ctrl.keyCode ||
|
||
// Meta keys.
|
||
keyCode === keyboardKeys.leftwindowkey.keyCode ||
|
||
keyCode === keyboardKeys.rightwindowkey.keyCode ||
|
||
keyCode === keyboardKeys.selectkey.keyCode
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Construct the display string of a key combination based on platform.
|
||
* For example, the display of alt in Windows or Linux would be "Alt";
|
||
* while in Mac would be "⌥".
|
||
* @param keyComb
|
||
* @param mustUsePlus if true will join the characters with "+" for all platforms;
|
||
* otherwise if the platform is Mac, the characters will be next to each other.
|
||
* @returns the constructed string, if keyCode is null and the characters are joint with "+",
|
||
* it will have a dangling "+" as the last character, e.g., "Alt+Ctrl+".
|
||
*/
|
||
export function constructKeyCombinationDisplay(
|
||
keyComb: KeyCombination,
|
||
mustUsePlus: boolean,
|
||
): string {
|
||
const { ctrl, alt, shift, meta, keyCode } = keyComb;
|
||
const chars = [];
|
||
|
||
alt && chars.push(ALT_SYM);
|
||
shift && chars.push(SHIFT_SYM);
|
||
ctrl && chars.push(CTRL_SYM);
|
||
meta && chars.push(META_SYM);
|
||
if (keyCode != null && !isModifierKeyCode(keyCode)) {
|
||
chars.push(getChar(keyCode));
|
||
}
|
||
|
||
let joint = joinHotKeys(mustUsePlus, chars);
|
||
if (mustUsePlus && isModifierKeyCode(keyCode)) {
|
||
joint += '+';
|
||
}
|
||
return joint;
|
||
}
|
||
|
||
/**
|
||
* Construct the display string for a key combination
|
||
*
|
||
* @param hotKeyDef
|
||
* @param hotKeyRegistry
|
||
* @param mustUsePlus
|
||
* @returns {string} – key combination as string or empty string if not found
|
||
*/
|
||
export function getHotKeyDisplay(
|
||
hotKeyDef: HotKeyDefinition,
|
||
hotKeyRegistry: HotKeyRegistry,
|
||
mustUsePlus: boolean,
|
||
) {
|
||
const hotKey: ?KeyBindings = hotKeyRegistry[hotKeyDef.id];
|
||
if (!hotKey) {
|
||
return '';
|
||
}
|
||
|
||
const keyCombs: Array<KeyCombination> = getPlatformKeyCombinations(hotKey);
|
||
if (keyCombs.length === 0) {
|
||
return '';
|
||
}
|
||
|
||
return constructKeyCombinationDisplay(keyCombs[0], mustUsePlus);
|
||
}
|