feat(hotkeys): chaque raccourci se desactive (Suppr pendant la capture)
Off = vk 0, non enregistre : la combinaison reste libre pour les autres applis. Combinaisons retenues en pref DPAPI et rejouees au demarrage, pour qu'un raccourci coupe le reste coffre ferme. Esc annule enfin la capture au lieu de fermer les reglages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -198,6 +198,19 @@ Retour Delphi → JS via `WebBrowser.ExecuteJavaScript('Bridge.onX(...)')`.
|
||||
Combos autofill configurables depuis Settings (synced en DB
|
||||
via `settings_json`).
|
||||
|
||||
**Desactiver un raccourci (2026-10-05)** : clic sur le bouton, puis **Suppr**
|
||||
(ou Retour arriere) → `key: ''` → vk 0, que Delphi n'enregistre pas ; libelle
|
||||
*Off*. Les combinaisons sont aussi **retenues en pref DPAPI `hotkeys`** (la
|
||||
requete `autofill/hotkeys` telle quelle, hors suspension de capture) et
|
||||
**rejouees au demarrage** a la place des valeurs par defaut : `settings_json`
|
||||
n'arrive qu'apres la connexion, et un `Ctrl+Shift+A` desactive restait pris
|
||||
tant que le coffre etait ferme. Piege corrige au passage : l'Esc des reglages
|
||||
(ecouteur `document` en capture, enregistre avant) fermait Settings au lieu
|
||||
d'annuler la capture — il ignore Esc tant qu'un `[data-capturing="1"]` existe.
|
||||
**La barrette remplit meme raccourcis coupes** : `onAutofillRequest` recoit
|
||||
`fromBar`, l'option « Autofill with global hotkey » ne bloque que les
|
||||
raccourcis.
|
||||
|
||||
## Fill bar (remplir à la souris)
|
||||
|
||||
Menu du tray → **Fill bar** : une barrette de trois
|
||||
|
||||
@@ -364,7 +364,13 @@ begin
|
||||
FBridge.OnNewEntryHotkey := BridgeNewEntryHotkey;
|
||||
FBridge.OnQuickSearchRequest := BridgeQuickSearchRequest;
|
||||
FBridge.OnQuickSearchHotkey := BridgeQuickSearchHotkey;
|
||||
FBridge.RegisterAutofillHotkey; // Ctrl+Shift+L active from startup
|
||||
// Les combinaisons de la derniere session (dont les raccourcis desactives),
|
||||
// sinon les valeurs par defaut.
|
||||
var LSavedHotkeys := PM.UserPrefs.GetPref('hotkeys');
|
||||
if LSavedHotkeys <> '' then
|
||||
HandleBridgeCommand('autofill/hotkeys', LSavedHotkeys)
|
||||
else
|
||||
FBridge.RegisterAutofillHotkey; // Ctrl+Shift+L active from startup
|
||||
FBridge.ApplyTitleBarTheme(True); // dark by default, JS may toggle later
|
||||
// Apres le theme et apres OnTrayRestore : la barrette se peint elle-meme, et
|
||||
// son bouton Open passe par cet evenement.
|
||||
@@ -1146,6 +1152,13 @@ begin
|
||||
// Ids, not labels: JS owns the wording AND uses them to flag the exact
|
||||
// row in Settings. A combo the user cleared (vk=0) is never listed.
|
||||
var LFailed := '';
|
||||
// RETENU EN PREF DPAPI pour etre rejoue au demarrage : les combinaisons
|
||||
// vivent dans settings_json, lu seulement apres la connexion - un raccourci
|
||||
// desactive restait donc pris par les valeurs par defaut tant que le coffre
|
||||
// etait ferme. Pas la suspension de la capture (sans full_vk). Rien de
|
||||
// secret dedans.
|
||||
if GetParam('full_vk') <> '' then
|
||||
PM.UserPrefs.SetPref('hotkeys', AParams);
|
||||
// Quick-search combo is set unconditionally (independent of the
|
||||
// autofill enabled flag) so the picker stays armed even when the
|
||||
// autofill hotkeys are turned off.
|
||||
@@ -1198,9 +1211,10 @@ begin
|
||||
// One notification for the whole batch, naming the combos that failed —
|
||||
// empty string = everything registered.
|
||||
LFailed := LFailed.TrimRight([',', ' ']);
|
||||
WebBrowser.ExecuteJavaScript(
|
||||
'if(window.Bridge&&Bridge.onAutofillHotkeysResult)' +
|
||||
'Bridge.onAutofillHotkeysResult("' + LFailed.Replace('"', '') + '")');
|
||||
if FBrowserInitialized then
|
||||
WebBrowser.ExecuteJavaScript(
|
||||
'if(window.Bridge&&Bridge.onAutofillHotkeysResult)' +
|
||||
'Bridge.onAutofillHotkeysResult("' + LFailed.Replace('"', '') + '")');
|
||||
end
|
||||
|
||||
// execute: JS has matched an entry, decrypted the password, and is
|
||||
|
||||
+1
-1
@@ -734,7 +734,7 @@
|
||||
<button class="btn btn-ghost btn-sm hotkey-capture-btn" id="settingNewEntryCombo">Ctrl+Shift+A</button>
|
||||
</div>
|
||||
<p style="font-size:11px;color:var(--text-faint);margin:6px 0 0;line-height:1.4">
|
||||
Click a button, then press your new combo. Needs Ctrl, Alt or Win + a letter / digit / F-key.
|
||||
Click a button, then press your new combo. Needs Ctrl, Alt or Win + a letter / digit / F-key. Press Delete instead to turn that hotkey off.
|
||||
</p>
|
||||
<button class="btn btn-ghost btn-sm" id="settingAutofillResetHotkeys" style="margin-top:6px">
|
||||
Reset to defaults
|
||||
|
||||
+4
-1
@@ -51,7 +51,7 @@ function renderHotkeyConflicts() {
|
||||
|
||||
// Format a combo for human display: "Ctrl+Shift+L".
|
||||
function autofillComboLabel(c) {
|
||||
if (!c || !c.key) return '— not set —';
|
||||
if (!c || !c.key) return 'Off';
|
||||
const parts = [];
|
||||
if (c.ctrl) parts.push('Ctrl');
|
||||
if (c.alt) parts.push('Alt');
|
||||
@@ -92,6 +92,9 @@ function autofillComboValid(c) {
|
||||
function autofillCaptureFromEvent(e) {
|
||||
const k = e.key;
|
||||
if (k === 'Escape') return 'cancel';
|
||||
// Suppr / Retour arriere pendant la capture = raccourci DESACTIVE : il
|
||||
// n'est plus enregistre, la combinaison reste libre pour une autre appli.
|
||||
if (k === 'Delete' || k === 'Backspace') return 'off';
|
||||
// Ignore pure-modifier keydowns (user is still building the combo).
|
||||
if (k === 'Control' || k === 'Shift' || k === 'Alt' ||
|
||||
k === 'Meta' || k === 'OS') return null;
|
||||
|
||||
@@ -8043,6 +8043,9 @@ async function init() {
|
||||
if (e.key !== 'Escape') return;
|
||||
if (!$('#settingsPanel').classList.contains('is-open')) return;
|
||||
if (document.querySelector('.modal:not(.is-hidden)')) return;
|
||||
// Capture de raccourci armee : Esc l'annule (son propre ecouteur,
|
||||
// enregistre APRES celui-ci), il ne ferme pas les reglages.
|
||||
if (document.querySelector('[data-capturing="1"]')) return;
|
||||
// Busy overlay up (sync/backup running) — don't close under it.
|
||||
if ($('#busyOverlay') && !$('#busyOverlay').classList.contains('is-hidden')) return;
|
||||
// When the search box has focus AND a query, the input's own
|
||||
@@ -8390,7 +8393,7 @@ async function init() {
|
||||
btn.dataset.capturing = '1';
|
||||
btn.classList.add('is-capturing');
|
||||
const original = btn.textContent;
|
||||
btn.textContent = 'Press combo… (Esc to cancel)';
|
||||
btn.textContent = 'Press combo… (Esc cancel · Del off)';
|
||||
// Free our own combos so they reach this listener instead of
|
||||
// firing their hotkey. Restored by finish() / the success path.
|
||||
hotkeyPushSilent = true;
|
||||
@@ -8445,6 +8448,20 @@ async function init() {
|
||||
return;
|
||||
}
|
||||
if (captured === 'cancel') { finish(true); return; }
|
||||
// Cle vide = vk 0 : Delphi n'enregistre pas ce raccourci.
|
||||
if (captured === 'off') {
|
||||
const off = { ctrl: false, shift: false, alt: false, win: false, key: '' };
|
||||
if (kind === 'full') state.autofillHotkeyFull = off;
|
||||
else if (kind === 'password') state.autofillHotkeyPwd = off;
|
||||
else if (kind === 'totp') state.autofillHotkeyTotp = off;
|
||||
else if (kind === 'quickSearch') state.quickSearchHotkey = off;
|
||||
else /* newEntry */ state.newEntryHotkey = off;
|
||||
btn.textContent = autofillComboLabel(off);
|
||||
finish(false);
|
||||
autofillPushHotkeys();
|
||||
saveServerSettings();
|
||||
return;
|
||||
}
|
||||
if (captured === 'invalid'){
|
||||
toast('Unsupported key — use a letter, digit or F-key', 'warning');
|
||||
finish(true);
|
||||
|
||||
Reference in New Issue
Block a user