Fixed an issue where shortcuts are not working as expected on multiple keyboard layouts. #9157
parent
e5590797c0
commit
7ff3c4bbeb
|
|
@ -37,4 +37,5 @@ Bug fixes
|
|||
| `Issue #9095 <https://github.com/pgadmin-org/pgadmin4/issues/9095>`_ - Fixed an issue where pgAdmin config migration was failing while upgrading to v9.7.
|
||||
| `Issue #9114 <https://github.com/pgadmin-org/pgadmin4/issues/9114>`_ - Fixed Cross-Origin Opener Policy (COOP) vulnerability in the OAuth 2.0 authentication flow (CVE-2025-9636).
|
||||
| `Issue #9116 <https://github.com/pgadmin-org/pgadmin4/issues/9116>`_ - Fixed an issue where editor shortcuts fail when using Option key combinations on macOS, due to macOS treating Option+Key as a different key input.
|
||||
| `Issue #9125 <https://github.com/pgadmin-org/pgadmin4/issues/9125>`_ - Fixed an issue where the pgAdmin configuration database wasn't being created on a fresh install when an external database was used for the configuration.
|
||||
| `Issue #9125 <https://github.com/pgadmin-org/pgadmin4/issues/9125>`_ - Fixed an issue where the pgAdmin configuration database wasn't being created on a fresh install when an external database was used for the configuration.
|
||||
| `Issue #9157 <https://github.com/pgadmin-org/pgadmin4/issues/9157>`_ - Fixed an issue where shortcuts are not working as expected on multiple keyboard layouts.
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@
|
|||
"@date-io/core": "^3.0.0",
|
||||
"@date-io/date-fns": "3.x",
|
||||
"@emotion/sheet": "^1.0.1",
|
||||
"@fluentui/keyboard-key": "^0.4.23",
|
||||
"@fortawesome/fontawesome-free": "latest",
|
||||
"@mui/icons-material": "^7.3.2",
|
||||
"@mui/material": "^7.3.2",
|
||||
|
|
|
|||
|
|
@ -52,13 +52,13 @@ def register_editor_preferences(self):
|
|||
gettext('Replace'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'alt': False,
|
||||
'shift': False,
|
||||
'control': True,
|
||||
'ctrl_is_meta': True,
|
||||
'key': {
|
||||
'key_code': 70,
|
||||
'char': 'f'
|
||||
'key_code': 82,
|
||||
'char': 'r'
|
||||
}
|
||||
},
|
||||
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { InputText, ToggleCheckButton } from './FormComponents';
|
|||
import PropTypes from 'prop-types';
|
||||
import { isMac } from '../keyboard_shortcuts';
|
||||
import gettext from 'sources/gettext';
|
||||
import { getCode } from '@fluentui/keyboard-key';
|
||||
|
||||
export default function KeyboardShortcuts({ value, onChange, fields, name }) {
|
||||
const keyCid = `key-${name}`;
|
||||
|
|
@ -29,7 +30,7 @@ export default function KeyboardShortcuts({ value, onChange, fields, name }) {
|
|||
}
|
||||
newVal.key = {
|
||||
char: _val,
|
||||
key_code: e.keyCode
|
||||
key_code: getCode(e),
|
||||
};
|
||||
onChange(newVal);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -102,7 +102,6 @@ function handlePaste(e) {
|
|||
checkTrojanSource(copiedText, true);
|
||||
}
|
||||
|
||||
|
||||
function insertTabWithUnit({ state, dispatch }) {
|
||||
if (state.selection.ranges.some(r => !r.empty))
|
||||
return indentMore({ state, dispatch });
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import React, {useRef, useEffect, useState, useCallback, useLayoutEffect} from '
|
|||
import moment from 'moment';
|
||||
import { isMac } from './keyboard_shortcuts';
|
||||
import { getBrowser } from './utils';
|
||||
import { getCode } from '@fluentui/keyboard-key';
|
||||
|
||||
/* React hook for setInterval */
|
||||
export function useInterval(callback, delay) {
|
||||
|
|
@ -185,7 +186,7 @@ export function useKeyboardShortcuts(shortcuts, eleRef) {
|
|||
|
||||
const matchFound = (shortcut, e)=>{
|
||||
if(!shortcut) return false;
|
||||
let keyCode = e.which || e.keyCode;
|
||||
let keyCode = getCode(e);
|
||||
const ctrlKey = (isMac() && shortcut.ctrl_is_meta) ? e.metaKey : e.ctrlKey;
|
||||
|
||||
return Boolean(shortcut.alt) == e.altKey &&
|
||||
|
|
@ -193,9 +194,10 @@ export function useKeyboardShortcuts(shortcuts, eleRef) {
|
|||
Boolean(shortcut.control) == ctrlKey &&
|
||||
shortcut.key.key_code == keyCode;
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
let ele = eleRef.current ?? document;
|
||||
const keydownCallback = (e)=>{
|
||||
const dispatch = (e)=>{
|
||||
Promise.resolve(0).then(()=>{
|
||||
let allListeners = _.filter(shortcutsRef.current, (s)=>matchFound(s.shortcut, e));
|
||||
for(const {options} of allListeners) {
|
||||
|
|
@ -209,9 +211,11 @@ export function useKeyboardShortcuts(shortcuts, eleRef) {
|
|||
}
|
||||
});
|
||||
};
|
||||
ele.addEventListener('keydown', keydownCallback);
|
||||
ele.addEventListener('keydown', dispatch);
|
||||
ele.addEventListener('keyup', dispatch);
|
||||
return ()=>{
|
||||
ele.removeEventListener('keydown', keydownCallback);
|
||||
ele.removeEventListener('keydown', dispatch);
|
||||
ele.removeEventListener('keyup', dispatch);
|
||||
};
|
||||
}, [eleRef.current]);
|
||||
|
||||
|
|
|
|||
|
|
@ -80,29 +80,8 @@ function shortcut_accesskey_title(title, shortcut) {
|
|||
}
|
||||
|
||||
|
||||
function _stopEventPropagation(event) {
|
||||
event.cancelBubble = true;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
|
||||
/* Function use to validate shortcut keys */
|
||||
function validateShortcutKeys(user_defined_shortcut, event) {
|
||||
if(!user_defined_shortcut) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let keyCode = event.which || event.keyCode;
|
||||
return user_defined_shortcut.alt == event.altKey &&
|
||||
user_defined_shortcut.shift == event.shiftKey &&
|
||||
user_defined_shortcut.control == event.ctrlKey &&
|
||||
user_defined_shortcut.key.key_code == keyCode;
|
||||
}
|
||||
|
||||
export {
|
||||
validateShortcutKeys,
|
||||
_stopEventPropagation, isMac, isKeyCtrlAlt, isKeyAltShift, isKeyCtrlShift,
|
||||
isMac, isKeyCtrlAlt, isKeyAltShift, isKeyCtrlShift,
|
||||
isKeyCtrlAltShift, isAltShiftBoth, isCtrlShiftBoth, isCtrlAltBoth,
|
||||
shortcut_key, shortcut_title, shortcut_accesskey_title,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@ import usePreferences from '../../preferences/static/js/store';
|
|||
import pgAdmin from 'sources/pgadmin';
|
||||
import { isMac } from './keyboard_shortcuts';
|
||||
import { WORKSPACES } from '../../browser/static/js/constants';
|
||||
import { getCode } from '@fluentui/keyboard-key';
|
||||
|
||||
export function parseShortcutValue(obj, useKeyboardCode=false) {
|
||||
export function parseShortcutValue(obj, useCode=false) {
|
||||
let shortcut = '';
|
||||
if (!obj){
|
||||
return null;
|
||||
|
|
@ -27,11 +28,11 @@ export function parseShortcutValue(obj, useKeyboardCode=false) {
|
|||
if (obj.shift) { shortcut += 'shift+'; }
|
||||
if (isMac() && obj.ctrl_is_meta) { shortcut += 'meta+'; }
|
||||
else if (obj.control) { shortcut += 'ctrl+'; }
|
||||
shortcut += useKeyboardCode ? shortcutCharToCode(obj?.key.char) : obj?.key.char?.toLowerCase();
|
||||
shortcut += useCode ? obj?.key.key_code : obj?.key.char?.toLowerCase();
|
||||
return shortcut;
|
||||
}
|
||||
|
||||
export function parseKeyEventValue(e, useKeyboardCode=false) {
|
||||
export function parseKeyEventValue(e, useCode=false) {
|
||||
let shortcut = '';
|
||||
if(!e) {
|
||||
return null;
|
||||
|
|
@ -40,7 +41,7 @@ export function parseKeyEventValue(e, useKeyboardCode=false) {
|
|||
if (e.shiftKey) { shortcut += 'shift+'; }
|
||||
if (isMac() && e.metaKey) { shortcut += 'meta+'; }
|
||||
else if (e.ctrlKey) { shortcut += 'ctrl+'; }
|
||||
shortcut += useKeyboardCode? e.code : e.key.toLowerCase();
|
||||
shortcut += useCode? getCode(e) : e.key.toLowerCase();
|
||||
return shortcut;
|
||||
}
|
||||
|
||||
|
|
@ -49,43 +50,6 @@ export function isShortcutValue(obj) {
|
|||
return [obj.alt, obj.control, obj?.key, obj?.key?.char].every((k)=>!_.isUndefined(k));
|
||||
}
|
||||
|
||||
// Map shortcut character to key code
|
||||
export function shortcutCharToCode(char) {
|
||||
const punctuationMap = {
|
||||
'`': 'Backquote',
|
||||
'-': 'Minus',
|
||||
'=': 'Equal',
|
||||
'[': 'BracketLeft',
|
||||
']': 'BracketRight',
|
||||
'\\': 'Backslash',
|
||||
';': 'Semicolon',
|
||||
'\'': 'Quote',
|
||||
',': 'Comma',
|
||||
'.': 'Period',
|
||||
'/': 'Slash',
|
||||
' ': 'Space',
|
||||
};
|
||||
|
||||
const mappedCode = punctuationMap[char.toLowerCase()];
|
||||
if (mappedCode) {
|
||||
return mappedCode;
|
||||
}
|
||||
|
||||
// Fallback for alphanumeric keys (A-Z, 0-9)
|
||||
const isAlphanumeric = /^[a-z0-9]$/i.test(char);
|
||||
if (isAlphanumeric) {
|
||||
if (char.length === 1 && /[a-zA-Z]/.test(char)) {
|
||||
return `Key${char.toUpperCase()}`;
|
||||
}
|
||||
if (char.length === 1 && /[0-9]/.test(char)) {
|
||||
return `Digit${char}`;
|
||||
}
|
||||
}
|
||||
|
||||
return char;
|
||||
}
|
||||
|
||||
|
||||
export function getEnterKeyHandler(clickHandler) {
|
||||
return (e)=>{
|
||||
if(e.code === 'Enter'){
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import { LayoutDockerContext, LAYOUT_EVENTS } from '../../../../../../static/js/
|
|||
import ConfirmSaveContent from '../../../../../../static/js/Dialogs/ConfirmSaveContent';
|
||||
import gettext from 'sources/gettext';
|
||||
import { isMac } from '../../../../../../static/js/keyboard_shortcuts';
|
||||
import { checkTrojanSource, isShortcutValue, parseKeyEventValue, parseShortcutValue, shortcutCharToCode } from '../../../../../../static/js/utils';
|
||||
import { checkTrojanSource, isShortcutValue, parseKeyEventValue, parseShortcutValue } from '../../../../../../static/js/utils';
|
||||
import { usePgAdmin } from '../../../../../../static/js/PgAdminProvider';
|
||||
import ConfirmPromotionContent from '../dialogs/ConfirmPromotionContent';
|
||||
import ConfirmExecuteQueryContent from '../dialogs/ConfirmExecuteQueryContent';
|
||||
|
|
@ -296,7 +296,6 @@ export default function Query({onTextSelect, setQtStatePartial}) {
|
|||
// this function creates a key object from the shortcut preference
|
||||
let key = {
|
||||
keyCode: pref.key.key_code,
|
||||
code: shortcutCharToCode(pref.key.char),
|
||||
metaKey: false,
|
||||
ctrlKey: pref.control,
|
||||
shiftKey: pref.shift,
|
||||
|
|
|
|||
|
|
@ -1967,6 +1967,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@fluentui/keyboard-key@npm:^0.4.23":
|
||||
version: 0.4.23
|
||||
resolution: "@fluentui/keyboard-key@npm:0.4.23"
|
||||
dependencies:
|
||||
tslib: "npm:^2.1.0"
|
||||
checksum: 10c0/f4c159f40632387e227efc2d7f1a0b4ec088da2c2cc669bc0598b4dd3c00953dbc554d665961fd57bbb9952a5081ab7f39b2c67d4cfc46d0a2a70d54fc60def2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@fortawesome/fontawesome-common-types@npm:6.7.2":
|
||||
version: 6.7.2
|
||||
resolution: "@fortawesome/fontawesome-common-types@npm:6.7.2"
|
||||
|
|
@ -12861,6 +12870,7 @@ __metadata:
|
|||
"@emotion/sheet": "npm:^1.0.1"
|
||||
"@emotion/styled": "npm:^11.11.0"
|
||||
"@emotion/utils": "npm:^1.0.0"
|
||||
"@fluentui/keyboard-key": "npm:^0.4.23"
|
||||
"@fortawesome/fontawesome-free": "npm:latest"
|
||||
"@mui/icons-material": "npm:^7.3.2"
|
||||
"@mui/material": "npm:^7.3.2"
|
||||
|
|
@ -14351,7 +14361,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tslib@npm:^2.0.3, tslib@npm:^2.4.0, tslib@npm:^2.7.0":
|
||||
"tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.7.0":
|
||||
version: 2.8.1
|
||||
resolution: "tslib@npm:2.8.1"
|
||||
checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62
|
||||
|
|
|
|||
Loading…
Reference in New Issue