fix(lock): lock screen swallowed every keystroke; add Ctrl+L to lock

The renderer-side guard added in v1.0.17 called preventDefault on every
keydown while locked. A keydown's default action IS inserting the
character into the focused field, so the lock screen's password box
received nothing and a locked app could never be unlocked. Menu
accelerators are already stopped in main (before-input-event); the
renderer guard now just skips its own logic.

Also: Ctrl+L locks the screen from anywhere in the app, terminals
included. The chord is only taken when a lock actually engages, so an
unconfigured app keeps Ctrl+L for the shell's clear-screen.
This commit is contained in:
Bill committed 2026-09-24 22:53:27 +08:00
1 parent 244199c512
commit 83dc3f15cc
7 files changed
+31 -15

No files matched your search

+18 -1
View File
@@ -166,12 +166,29 @@ function createWindow(): void {
}
})
// Ctrl+L is the panic lock: it must work from anywhere in the app, terminals
// included, so it is captured here ahead of the page. It only takes the chord
// away when a lock actually engages — an unconfigured app keeps Ctrl+L for
// the shell's clear-screen.
// Swallow the menu accelerators that would otherwise act behind the lock
// overlay (see isLockBlockedShortcut). A throw in here would break typing
// altogether, so the whole guard is defensive.
win.webContents.on('before-input-event', (event, input) => {
try {
if (input.type !== 'keyDown' || !getLockController().isLocked()) return
if (input.type !== 'keyDown') return
const lock = getLockController()
if (
!lock.isLocked() &&
input.control &&
!input.shift &&
!input.alt &&
!input.meta &&
input.key.toLowerCase() === 'l'
) {
if (lock.lockNow().locked) event.preventDefault()
return
}
if (!lock.isLocked()) return
if (isLockBlockedShortcut(input)) event.preventDefault()
} catch {
/* an input guard must never take the window down with it */
+7 -9
View File
@@ -157,15 +157,13 @@ function FontHotkeyListener(): null {
useEffect(() => {
const onKeyDown = (e: KeyboardEvent): void => {
// The lock overlay leaves Workspace mounted; window-capture hotkeys must
// not mutate font size on a shell hidden behind it. preventDefault matters
// here: returning alone lets the chord reach Electron's default menu
// accelerators (zoomIn/zoomOut/resetZoom), which rescale the whole UI
// behind the opaque mask and make Chromium persist that zoom per origin.
if (document.documentElement.dataset.locked === 'true') {
e.preventDefault()
return
}
// While locked, skip only this listener's own logic — and NEVER call
// preventDefault here. The default action of a keydown is inserting the
// character into the focused field, and it runs after the whole dispatch:
// preventing it at window level kills every keystroke the lock screen's
// password field would receive (shipped broken in v1.0.17). The menu
// accelerators are stopped in main, on before-input-event, instead.
if (document.documentElement.dataset.locked === 'true') return
if (!e.ctrlKey || e.metaKey) return
const target = e.target as HTMLElement | null
const isXtermHelper =
+1 -1
View File
@@ -134,7 +134,7 @@ const settings: Record<string, string> = {
'settings.lock.lockAtStartup': 'Lock at startup',
'settings.lock.lockAtStartupDesc': 'Ask for the password right after every launch',
'settings.lock.lockNow': 'Lock now',
'settings.lock.lockNowDesc': 'Lock the main window immediately (sessions keep running)',
'settings.lock.lockNowDesc': 'Lock the main window immediately (sessions keep running, Ctrl+L)',
'settings.lock.title': 'Locked',
'settings.lock.screenDesc': 'Enter the lock password to unlock',
'settings.lock.passwordPlaceholder': 'Password',
+1 -1
View File
@@ -131,7 +131,7 @@ const settings: Record<string, string> = {
'settings.lock.lockAtStartup': '起動時にロック',
'settings.lock.lockAtStartupDesc': '起動直後にパスワードの入力を求めます',
'settings.lock.lockNow': '今すぐロック',
'settings.lock.lockNowDesc': 'メインウィンドウをすぐにロックします(セッションは動作を続けます)',
'settings.lock.lockNowDesc': 'メインウィンドウをすぐにロックします(セッションは動作を続けます、Ctrl+L)',
'settings.lock.title': 'ロック中',
'settings.lock.screenDesc': 'ロックパスワードを入力して解除します',
'settings.lock.passwordPlaceholder': 'パスワード',
+1 -1
View File
@@ -126,7 +126,7 @@ const settings: Record<string, string> = {
'settings.lock.lockAtStartup': '启动时锁屏',
'settings.lock.lockAtStartupDesc': '每次启动后先要求输入密码',
'settings.lock.lockNow': '立即锁屏',
'settings.lock.lockNowDesc': '马上锁定主窗口(会话保持运行)',
'settings.lock.lockNowDesc': '马上锁定主窗口(会话保持运行,快捷键 Ctrl+L)',
'settings.lock.title': '已锁定',
'settings.lock.screenDesc': '输入锁屏密码解锁',
'settings.lock.passwordPlaceholder': '密码',
+1 -1
View File
@@ -126,7 +126,7 @@ const settings: Record<string, string> = {
'settings.lock.lockAtStartup': '啟動時鎖定',
'settings.lock.lockAtStartupDesc': '每次啟動後先要求輸入密碼',
'settings.lock.lockNow': '立即鎖定',
'settings.lock.lockNowDesc': '馬上鎖定主視窗(工作階段保持運作)',
'settings.lock.lockNowDesc': '馬上鎖定主視窗(工作階段保持運作,快捷鍵 Ctrl+L)',
'settings.lock.title': '已鎖定',
'settings.lock.screenDesc': '輸入鎖定密碼以解鎖',
'settings.lock.passwordPlaceholder': '密碼',