Skip to content

Commit 6be6904

Browse files
fix: handle shortcuts by default if no WebPreferences object exists (electron#14766)
DevTools webcontents do not have webpreferences Fixes electron#14685
1 parent 0d2a0c7 commit 6be6904

File tree

6 files changed

+582
-44
lines changed

6 files changed

+582
-44
lines changed

atom/browser/common_web_contents_delegate_mac.mm

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,20 @@ - (void)redispatchKeyEvent:(NSEvent*)event;
2828
if (event.windows_key_code == ui::VKEY_ESCAPE && is_html_fullscreen())
2929
ExitFullscreenModeForTab(source);
3030

31-
if (auto* web_preferences = WebContentsPreferences::From(source)) {
32-
if (!web_preferences->IsEnabled("ignoreMenuShortcuts", false)) {
33-
// Send the event to the menu before sending it to the window
34-
if (event.os_event.type == NSKeyDown &&
35-
[[NSApp mainMenu] performKeyEquivalent:event.os_event])
36-
return;
37-
38-
if (event.os_event.window &&
39-
[event.os_event.window isKindOfClass:[EventDispatchingWindow class]])
40-
[event.os_event.window redispatchKeyEvent:event.os_event];
41-
}
42-
}
31+
// Check if the webContents has preferences and to ignore shortcuts
32+
auto* web_preferences = WebContentsPreferences::From(source);
33+
if (web_preferences &&
34+
web_preferences->IsEnabled("ignoreMenuShortcuts", false))
35+
return;
36+
37+
// Send the event to the menu before sending it to the window
38+
if (event.os_event.type == NSKeyDown &&
39+
[[NSApp mainMenu] performKeyEquivalent:event.os_event])
40+
return;
41+
42+
if (event.os_event.window &&
43+
[event.os_event.window isKindOfClass:[EventDispatchingWindow class]])
44+
[event.os_event.window redispatchKeyEvent:event.os_event];
4345
}
4446

4547
} // namespace atom

atom/browser/common_web_contents_delegate_views.cc

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,15 @@ void CommonWebContentsDelegate::HandleKeyboardEvent(
2424
if (event.windows_key_code == ui::VKEY_ESCAPE && is_html_fullscreen())
2525
ExitFullscreenModeForTab(source);
2626

27+
// Check if the webContents has preferences and to ignore shortcuts
28+
auto* web_preferences = WebContentsPreferences::From(source);
29+
if (web_preferences &&
30+
web_preferences->IsEnabled("ignoreMenuShortcuts", false))
31+
return;
32+
2733
// Let the NativeWindow handle other parts.
28-
if (auto* web_preferences = WebContentsPreferences::From(source)) {
29-
if (owner_window() &&
30-
!web_preferences->IsEnabled("ignoreMenuShortcuts", false)) {
31-
owner_window()->HandleKeyboardEvent(source, event);
32-
}
34+
if (owner_window()) {
35+
owner_window()->HandleKeyboardEvent(source, event);
3336
}
3437
}
3538

spec/api-web-contents-spec.js

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const { emittedOnce } = require('./events-helpers')
99
const chai = require('chai')
1010
const dirtyChai = require('dirty-chai')
1111

12-
const { ipcRenderer, remote } = require('electron')
12+
const { ipcRenderer, remote, clipboard } = require('electron')
1313
const { BrowserWindow, webContents, ipcMain, session } = remote
1414
const { expect } = chai
1515

@@ -255,6 +255,61 @@ describe('webContents module', () => {
255255
})
256256
})
257257

258+
describe('devtools window', () => {
259+
let testFn = it
260+
if (process.platform === 'darwin' && isCi) {
261+
testFn = it.skip
262+
}
263+
try {
264+
// We have other tests that check if native modules work, if we fail to require
265+
// robotjs let's skip this test to avoid false negatives
266+
require('robotjs')
267+
} catch (err) {
268+
testFn = it.skip
269+
}
270+
271+
testFn('can receive and handle menu events', async function () {
272+
this.timeout(5000)
273+
w.show()
274+
w.loadFile(path.join(fixtures, 'pages', 'key-events.html'))
275+
// Ensure the devtools are loaded
276+
w.webContents.closeDevTools()
277+
const opened = emittedOnce(w.webContents, 'devtools-opened')
278+
w.webContents.openDevTools()
279+
await opened
280+
await emittedOnce(w.webContents.devToolsWebContents, 'did-finish-load')
281+
w.webContents.devToolsWebContents.focus()
282+
283+
// Focus an input field
284+
await w.webContents.devToolsWebContents.executeJavaScript(
285+
`const input = document.createElement('input');
286+
document.body.innerHTML = '';
287+
document.body.appendChild(input)
288+
input.focus();`
289+
)
290+
291+
// Write something to the clipboard
292+
clipboard.writeText('test value')
293+
294+
// Fake a paste request using robotjs to emulate a REAL keyboard paste event
295+
require('robotjs').keyTap('v', process.platform === 'darwin' ? ['command'] : ['control'])
296+
297+
const start = Date.now()
298+
let val
299+
300+
// Check every now and again for the pasted value (paste is async)
301+
while (val !== 'test value' && Date.now() - start <= 1000) {
302+
val = await w.webContents.devToolsWebContents.executeJavaScript(
303+
`document.querySelector('input').value`
304+
)
305+
await new Promise(resolve => setTimeout(resolve, 10))
306+
}
307+
308+
// Once we're done expect the paste to have been successful
309+
expect(val).to.equal('test value', 'value should eventually become the pasted value')
310+
})
311+
})
312+
258313
describe('sendInputEvent(event)', () => {
259314
beforeEach((done) => {
260315
w.loadFile(path.join(fixtures, 'pages', 'key-events.html'))

0 commit comments

Comments
 (0)