feat(desktop): support clearing hotkey bindings in ShortcutManager (#12727)

* 🔧 chore: update @lobehub/ui dependency to a specific version URL and enhance ShortcutManager functionality

- Updated @lobehub/ui dependency in package.json to a specific version URL.
- Improved ShortcutManager to handle empty accelerator bindings, allowing users to clear shortcuts.
- Updated tests to reflect changes in shortcut handling and added localization for clear binding messages in both Chinese and English.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update @lobehub/ui dependency to version 5.4.0 in package.json

- Changed the @lobehub/ui dependency from a specific version URL to version 5.4.0 for improved stability and consistency.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update @lobehub/ui dependency to use caret versioning in package.json

- Changed the @lobehub/ui dependency from a fixed version to caret versioning (^5.4.0) to allow for minor updates and improvements.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
Innei
2026-03-05 21:23:58 +08:00
committed by GitHub
parent 92c70d2485
commit 5920500371
8 changed files with 89 additions and 29 deletions

View File

@@ -84,13 +84,23 @@ export class ShortcutManager {
}
// 2. Basic format validation
if (!accelerator || typeof accelerator !== 'string' || accelerator.trim() === '') {
if (typeof accelerator !== 'string') {
logger.error(`Invalid accelerator format: ${accelerator}`);
return { errorType: 'INVALID_FORMAT', success: false };
}
const trimmedAccelerator = accelerator.trim();
// Empty value means disable this shortcut binding
if (trimmedAccelerator === '') {
this.shortcutsConfig[id] = '';
this.saveShortcutsConfig();
this.registerConfiguredShortcuts();
return { success: true };
}
// Convert frontend format to Electron format
const convertedAccelerator = this.convertAcceleratorFormat(accelerator.trim());
const convertedAccelerator = this.convertAcceleratorFormat(trimmedAccelerator);
const cleanAccelerator = convertedAccelerator.toLowerCase();
logger.debug(`Converted accelerator from ${accelerator} to ${convertedAccelerator}`);
@@ -221,7 +231,7 @@ export class ShortcutManager {
// If no configuration, use default configuration
if (!config || Object.keys(config).length === 0) {
logger.debug('No shortcuts config found, using defaults');
this.shortcutsConfig = DEFAULT_SHORTCUTS_CONFIG;
this.shortcutsConfig = { ...DEFAULT_SHORTCUTS_CONFIG };
this.saveShortcutsConfig();
} else {
// Filter out invalid shortcuts that are not in DEFAULT_SHORTCUTS_CONFIG
@@ -257,7 +267,7 @@ export class ShortcutManager {
logger.debug('Loaded shortcuts config:', this.shortcutsConfig);
} catch (error) {
logger.error('Error loading shortcuts config:', error);
this.shortcutsConfig = DEFAULT_SHORTCUTS_CONFIG;
this.shortcutsConfig = { ...DEFAULT_SHORTCUTS_CONFIG };
this.saveShortcutsConfig();
}
}

View File

@@ -175,11 +175,17 @@ describe('ShortcutManager', () => {
expect(result.errorType).toBe('INVALID_ID');
});
it('should reject empty accelerator', () => {
it('should clear shortcut when accelerator is empty', () => {
const result = shortcutManager.updateShortcutConfig('showApp', '');
expect(result.success).toBe(false);
expect(result.errorType).toBe('INVALID_FORMAT');
expect(result.success).toBe(true);
expect(result.errorType).toBeUndefined();
expect(mockStoreManager.set).toHaveBeenCalledWith(
'shortcuts',
expect.objectContaining({
showApp: '',
}),
);
});
it('should reject accelerator without modifier keys', () => {