diff --git a/CLAUDE.md b/CLAUDE.md index 6fc5b52..a2ba0e9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -316,6 +316,16 @@ Détails : Le cadre est peint dans `WM_ERASEBKGND` plutôt que par `WS_BORDER`, qui se sert dans les couleurs système. +**Bouton Paste (2026-10-14)** : `LAZY_ID_PASTE` / cle `paste` (desactive par +defaut) → `PasteClipboardAsKeystrokes` lit le presse-papiers **Windows** +(`CF_UNICODETEXT`) et le **tape** dans la fenetre en avant par +`ExecuteAutofill(..., AClearFirst=False)` - donc vraies touches et bascule de +disposition vers un client VNC (TigerVNC vers un Mac ne transmet pas le +presse-papiers). Insere au curseur, saut de ligne final retire (un terminal +lancerait la commande), sauts internes tapes en Entree. Marche coffre ferme : +rien ne passe par la page. Pas de texte (image, fichier) → bulle « No text in +the clipboard ». + ### Réglages de la barrette (2026-09-18) **Settings → onglet Fill bar**, et le **clic droit** sur la barrette pour les @@ -1612,6 +1622,10 @@ après chaque `DELETE /attachments/{id}`. Un petit vault sain ne paie rien. texte = fin de la commande ; un `#` apres une continuation reste du texte. Limite : un chemin Windows fini par `\` en fin de ligne passe pour une continuation. +- **Polices a chasse fixe et arabe** (2026-10-14) : aucune n'a l'arabe, et + Windows empruntait une police plus petite. Chaque pile `…, monospace` de + `css/style.css` finit par `'Segoe UI', Tahoma, monospace` : le latin reste a + chasse fixe, l'arabe prend une taille comparable. - **Settings search** : `#settingsSearch` filtre les `.setting-row` par texte ; match sur le label de section garde toute la section. Esc dans la search avec query = clear ; Esc vide = ferme Settings. diff --git a/css/style.css b/css/style.css index c2debbd..0debf7a 100644 --- a/css/style.css +++ b/css/style.css @@ -17,10 +17,14 @@ body { overflow: hidden; } +/* Les polices a chasse fixe n'ont pas l'arabe : Windows empruntait une police + au hasard, plus petite. 'Segoe UI' / Tahoma, places avant 'monospace' dans + chaque pile, prennent ces caracteres a une taille comparable ; le latin reste + dans la police a chasse fixe. */ button { font-family: inherit; cursor: pointer; } input, select, textarea { font-family: inherit; font-size: inherit; } kbd { - font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace; + font-family: 'JetBrains Mono', 'SF Mono', Consolas, 'Segoe UI', Tahoma, monospace; font-size: 11px; padding: 2px 6px; border: 1px solid var(--border); @@ -248,7 +252,7 @@ input[type="range"]::-webkit-slider-thumb { .licence-machine code { display: inline-block; padding: 6px 10px; background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-sm); - font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; + font-family: ui-monospace, "Cascadia Mono", Consolas, 'Segoe UI', Tahoma, monospace; font-size: 14px; letter-spacing: 1px; color: var(--text); user-select: all; } @@ -1216,7 +1220,7 @@ input[type="range"]::-webkit-slider-thumb { } .entry-pw { flex: 1; - font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace; + font-family: 'JetBrains Mono', 'SF Mono', Consolas, 'Segoe UI', Tahoma, monospace; font-size: 12px; color: var(--text-dim); overflow: hidden; @@ -1268,7 +1272,7 @@ input[type="range"]::-webkit-slider-thumb { } .totp-code { flex: 1; - font-family: 'JetBrains Mono', ui-monospace, monospace; + font-family: 'JetBrains Mono', ui-monospace, 'Segoe UI', Tahoma, monospace; font-size: 22px; letter-spacing: 2px; color: var(--accent); @@ -1330,7 +1334,7 @@ input[type="range"]::-webkit-slider-thumb { } .auth-card-code { flex: 1; - font-family: 'JetBrains Mono', ui-monospace, monospace; + font-family: 'JetBrains Mono', ui-monospace, 'Segoe UI', Tahoma, monospace; font-size: 26px; letter-spacing: 3px; color: var(--accent); @@ -1386,7 +1390,7 @@ input[type="range"]::-webkit-slider-thumb { .health-score.is-danger { border-color: #ef4444; color: #ef4444; } .health-score-num { font-size: 36px; font-weight: 700; - font-family: 'JetBrains Mono', ui-monospace, monospace; + font-family: 'JetBrains Mono', ui-monospace, 'Segoe UI', Tahoma, monospace; } .health-score-lbl { font-size: 11px; font-weight: 600; @@ -1417,7 +1421,7 @@ input[type="range"]::-webkit-slider-thumb { .health-bd-n { text-align: right; font-variant-numeric: tabular-nums; } .health-bd-pts { text-align: right; - font-family: 'JetBrains Mono', ui-monospace, monospace; + font-family: 'JetBrains Mono', ui-monospace, 'Segoe UI', Tahoma, monospace; color: var(--text-faint); } /* Nothing wrong in this category — dim it so the eye goes to what needs work. */ @@ -1572,7 +1576,7 @@ input[type="range"]::-webkit-slider-thumb { .history-date { font-size: 11px; color: var(--text-dim); - font-family: 'JetBrains Mono', ui-monospace, monospace; + font-family: 'JetBrains Mono', ui-monospace, 'Segoe UI', Tahoma, monospace; } .history-preview { display: flex; align-items: flex-start; gap: 6px; @@ -1581,7 +1585,7 @@ input[type="range"]::-webkit-slider-thumb { .history-value { flex: 1 1 0; min-width: 0; - font-family: 'JetBrains Mono', ui-monospace, monospace; + font-family: 'JetBrains Mono', ui-monospace, 'Segoe UI', Tahoma, monospace; font-size: 12px; color: var(--text); /* Long revealed passwords wrap to multiple lines (no ellipsis) so @@ -1634,7 +1638,7 @@ input[type="range"]::-webkit-slider-thumb { flex-wrap: wrap; } .cheatsheet-keys kbd { - font-family: 'JetBrains Mono', ui-monospace, monospace; + font-family: 'JetBrains Mono', ui-monospace, 'Segoe UI', Tahoma, monospace; font-size: 11px; padding: 2px 7px; background: var(--bg); @@ -1814,7 +1818,7 @@ input[type="range"]::-webkit-slider-thumb { .audit-row:hover { background: var(--bg); } .audit-date { color: var(--text-dim); - font-family: 'JetBrains Mono', ui-monospace, monospace; + font-family: 'JetBrains Mono', ui-monospace, 'Segoe UI', Tahoma, monospace; white-space: nowrap; } .audit-action { @@ -1823,7 +1827,7 @@ input[type="range"]::-webkit-slider-thumb { } .audit-ip { color: var(--text-faint); - font-family: 'JetBrains Mono', ui-monospace, monospace; + font-family: 'JetBrains Mono', ui-monospace, 'Segoe UI', Tahoma, monospace; text-align: right; } @@ -1969,7 +1973,7 @@ input[type="range"]::-webkit-slider-thumb { .so-note-body { min-height: 220px; resize: vertical; - font-family: 'JetBrains Mono', ui-monospace, monospace; + font-family: 'JetBrains Mono', ui-monospace, 'Segoe UI', Tahoma, monospace; font-size: 13px; line-height: 1.55; white-space: pre-wrap; @@ -1987,7 +1991,7 @@ input[type="range"]::-webkit-slider-thumb { .so-cmds-cmd { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; } .so-cmds-empty { font-size: 12px; color: var(--text-dim); } #qsBack { flex-shrink: 0; } -.qs-cmd { font-family: ui-monospace, Consolas, monospace; font-size: 13px; } +.qs-cmd { font-family: ui-monospace, Consolas, 'Segoe UI', Tahoma, monospace; font-size: 13px; } /* ---- + New dropdown ---------------------------------- */ .new-entry-wrap { @@ -2543,7 +2547,7 @@ body[data-editor-position="center"]:has(#settingsPanel.is-open)::before { background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-sm); - font-family: 'JetBrains Mono', monospace; + font-family: 'JetBrains Mono', 'Segoe UI', Tahoma, monospace; font-size: 13px; word-break: break-all; margin-bottom: 16px; @@ -2780,7 +2784,7 @@ body[data-editor-position="center"]:has(#settingsPanel.is-open)::before { /* ---- Hotkey capture buttons (Settings → Autofill) ---- */ .hotkey-capture-btn { - font-family: ui-monospace, "Cascadia Code", Menlo, monospace; + font-family: ui-monospace, "Cascadia Code", Menlo, 'Segoe UI', Tahoma, monospace; font-size: 11px; min-width: 140px; text-align: center; @@ -3240,7 +3244,7 @@ input[type="password"]::-ms-clear { margin-bottom: 28px; } .prc-code { - font-family: 'Courier New', monospace; + font-family: 'Courier New', 'Segoe UI', Tahoma, monospace; font-size: 32px; letter-spacing: 6px; text-align: center; diff --git a/delphi-backend/Source/PM.Bridge.pas b/delphi-backend/Source/PM.Bridge.pas index 7ab1ad8..fb2a5db 100644 --- a/delphi-backend/Source/PM.Bridge.pas +++ b/delphi-backend/Source/PM.Bridge.pas @@ -183,6 +183,7 @@ type // les declenche aussi, meme capture de la fenetre cible. procedure FireNewEntryRequest; procedure FireQuickSearchRequest; + procedure PasteClipboardAsKeystrokes; /// Pose l'opacite qui convient a l'etat de survol donne. procedure ApplyLazyAlpha(AHover: Boolean); /// Menu du clic droit sur la barrette : le choix de l'opacite au repos. @@ -450,6 +451,7 @@ const LAZY_ID_ADD = 106; // nouvelle entree depuis la fenetre en avant (Ctrl+Shift+A) LAZY_ID_SEARCH = 107; // recherche rapide (Ctrl+Shift+Q) LAZY_ID_SETTINGS = 108; // reglages, onglet Fill bar + LAZY_ID_PASTE = 109; // tape le presse-papiers Windows dans la fenetre en avant LAZY_MENU_ICONS = 1; // hors des valeurs d'opacite (25..100) du meme menu LAZY_MENU_SETTINGS = 2; LAZY_MENU_CLEAR = 3; @@ -1116,6 +1118,59 @@ end; // The target of a fill is whatever window owns the foreground at the moment // the user asks for it - a shortcut, or a click on the lazy strip, which takes // no foreground precisely so this stays true. +/// COLLER EN TAPANT. Certains clients a distance (TigerVNC vers un Mac) ne +/// transmettent pas le presse-papiers Windows : Ctrl+V n'y colle rien. Le texte +/// est donc TAPE dans la fenetre en avant, par le meme chemin que l'autofill - +/// vraies touches pour un client VNC, dispositions basculees au besoin. Le +/// presse-papiers est celui de Windows : coffre ouvert ou non, rien ne passe +/// par la page. Pas de Ctrl+A + Suppr avant : on insere au curseur, comme un +/// collage. +procedure TPMBridge.PasteClipboardAsKeystrokes; +var + LTarget: HWND; + LData: THandle; + LPtr: PWideChar; + LText: string; +begin + LTarget := GetForegroundWindow; + if IsOwnProcessWindow(LTarget) then + begin + ShowBalloon('Nothing to paste into', + 'Click where the text should go first, then press Paste.', True); + Exit; + end; + LText := ''; + if OpenClipboard(0) then + try + LData := GetClipboardData(CF_UNICODETEXT); + if LData <> 0 then + begin + LPtr := GlobalLock(LData); + if LPtr <> nil then + try + LText := LPtr; + finally + GlobalUnlock(LData); + end; + end; + finally + CloseClipboard; + end; + // Un retour a la ligne final, tape dans un terminal, vaudrait Entree. + // Les sauts de ligne internes partent en #13 : Entree, comme un collage. + LText := LText.Replace(#13#10, #10).Replace(#13, #10).TrimRight([#10]) + .Replace(#10, #13); + if LText = '' then + begin + // Une image ou un fichier copies ne sont pas du texte : le dire tel quel. + ShowBalloon('No text in the clipboard', 'Copy some text first, then press Paste.', True); + Exit; + end; + if not ExecuteAutofill(LTarget, '', LText, False, False, False) then + ShowBalloon('Paste blocked', + 'The window did not accept the keystrokes (it may run as administrator).', True); +end; + procedure TPMBridge.FireAutofillRequest(AKind: TAutofillKind; AFromBar: Boolean = False); var @@ -1302,6 +1357,7 @@ begin LAZY_ID_SEARCH: LGlyph := #$E721; // Search LAZY_ID_OPEN: LGlyph := #$E8A7; // OpenInNewWindow LAZY_ID_SETTINGS: LGlyph := #$E713; // Settings (roue) + LAZY_ID_PASTE: LGlyph := #$E77F; // Paste else LGlyph := #$E711; // Cancel (X) end; @@ -1505,6 +1561,7 @@ begin LAZY_ID_OPEN: if Assigned(FOnTrayRestore) then FOnTrayRestore(); LAZY_ID_ADD: FireNewEntryRequest; LAZY_ID_SEARCH: FireQuickSearchRequest; + LAZY_ID_PASTE: PasteClipboardAsKeystrokes; LAZY_ID_SETTINGS: begin if Assigned(FOnTrayRestore) then FOnTrayRestore(); @@ -1669,6 +1726,7 @@ begin AddButton('full', LAZY_ID_FULL, 'Full', 'Fill username and password', 56); AddButton('pwd', LAZY_ID_PWD, 'Password', 'Fill the password only', 76); AddButton('totp', LAZY_ID_TOTP, '2FA', 'Fill the 2FA code', 52); + AddButton('paste', LAZY_ID_PASTE, 'Paste', 'Type the Windows clipboard into the current window', 52); AddButton('add', LAZY_ID_ADD, 'Add', 'New entry from the current window', 48); AddButton('search', LAZY_ID_SEARCH, 'Search', 'Quick search', 60); // Meme raison que le X : quand la barrette est allumee, elle est souvent la diff --git a/index.html b/index.html index 1afbd8c..a3a234f 100644 --- a/index.html +++ b/index.html @@ -768,6 +768,7 @@ +