From 095ffc9a2572d731cd5262ad9c543f7eaaa45afb Mon Sep 17 00:00:00 2001 From: Pedro Pontes Date: Thu, 13 Dec 2018 01:25:15 +0100 Subject: [PATCH 1/2] fix: do not allow the window to grab focus when tabbing / shift+tabbing --- atom/browser/common_web_contents_delegate.cc | 13 +++++++++++++ atom/browser/common_web_contents_delegate.h | 1 + 2 files changed, 14 insertions(+) diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc index 591013af8b274..01f8c8b735f02 100644 --- a/atom/browser/common_web_contents_delegate.cc +++ b/atom/browser/common_web_contents_delegate.cc @@ -346,6 +346,19 @@ blink::WebSecurityStyle CommonWebContentsDelegate::GetSecurityStyle( security_style_explanations); } +bool CommonWebContentsDelegate::TakeFocus(content::WebContents* source, + bool reverse) { + if (source && source->GetOutermostWebContents() == source) { + // If this is the outermost web contents and the user has tabbed or + // shift + tabbed through all the elements, reset the focus back to + // the first or last element so that it doesn't stay in the body. + source->FocusThroughTabTraversal(reverse); + return true; + } + + return false; +} + void CommonWebContentsDelegate::DevToolsSaveToFile(const std::string& url, const std::string& content, bool save_as) { diff --git a/atom/browser/common_web_contents_delegate.h b/atom/browser/common_web_contents_delegate.h index 96cbee75c225f..d4729808ee8d4 100644 --- a/atom/browser/common_web_contents_delegate.h +++ b/atom/browser/common_web_contents_delegate.h @@ -98,6 +98,7 @@ class CommonWebContentsDelegate : public content::WebContentsDelegate, blink::WebSecurityStyle GetSecurityStyle( content::WebContents* web_contents, content::SecurityStyleExplanations* explanations) override; + bool TakeFocus(content::WebContents* source, bool reverse) override; void HandleKeyboardEvent( content::WebContents* source, const content::NativeWebKeyboardEvent& event) override; From d11e553d7a2d0bfd94738d9ef5858a0f2f316e4c Mon Sep 17 00:00:00 2001 From: Pedro Pontes Date: Fri, 14 Dec 2018 21:09:20 +0100 Subject: [PATCH 2/2] test: add tests. --- spec/chromium-spec.js | 105 ++++++++++++++++++ .../pages/tab-focus-loop-elements-wv.html | 25 +++++ .../pages/tab-focus-loop-elements.html | 27 +++++ 3 files changed, 157 insertions(+) create mode 100644 spec/fixtures/pages/tab-focus-loop-elements-wv.html create mode 100644 spec/fixtures/pages/tab-focus-loop-elements.html diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index 9aeed38225f36..a66b095615a3b 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -1411,6 +1411,111 @@ describe('chromium feature', () => { await new Promise((resolve) => { utter.onend = resolve }) }) }) + + describe('focus handling', () => { + let webviewContents = null + + beforeEach(async () => { + w = new BrowserWindow({ + show: true + }) + + const webviewReady = emittedOnce(w.webContents, 'did-attach-webview') + await w.loadFile(path.join(fixtures, 'pages', 'tab-focus-loop-elements.html')) + const [, wvContents] = await webviewReady + webviewContents = wvContents + await emittedOnce(webviewContents, 'did-finish-load') + w.focus() + }) + + afterEach(() => { + webviewContents = null + }) + + const expectFocusChange = async () => { + const [, focusedElementId] = await emittedOnce(ipcMain, 'focus-changed') + return focusedElementId + } + + describe('a TAB press', () => { + const tabPressEvent = { + type: 'keyDown', + keyCode: 'Tab' + } + + it('moves focus to the next focusable item', async () => { + let focusChange = expectFocusChange() + w.webContents.sendInputEvent(tabPressEvent) + let focusedElementId = await focusChange + assert.strictEqual(focusedElementId, 'BUTTON-element-1', `should start focused in element-1, it's instead in ${focusedElementId}`) + + focusChange = expectFocusChange() + w.webContents.sendInputEvent(tabPressEvent) + focusedElementId = await focusChange + assert.strictEqual(focusedElementId, 'BUTTON-element-2', `focus should've moved to element-2, it's instead in ${focusedElementId}`) + + focusChange = expectFocusChange() + w.webContents.sendInputEvent(tabPressEvent) + focusedElementId = await focusChange + assert.strictEqual(focusedElementId, 'BUTTON-wv-element-1', `focus should've moved to the webview's element-1, it's instead in ${focusedElementId}`) + + focusChange = expectFocusChange() + webviewContents.sendInputEvent(tabPressEvent) + focusedElementId = await focusChange + assert.strictEqual(focusedElementId, 'BUTTON-wv-element-2', `focus should've moved to the webview's element-2, it's instead in ${focusedElementId}`) + + focusChange = expectFocusChange() + webviewContents.sendInputEvent(tabPressEvent) + focusedElementId = await focusChange + assert.strictEqual(focusedElementId, 'BUTTON-element-3', `focus should've moved to element-3, it's instead in ${focusedElementId}`) + + focusChange = expectFocusChange() + w.webContents.sendInputEvent(tabPressEvent) + focusedElementId = await focusChange + assert.strictEqual(focusedElementId, 'BUTTON-element-1', `focus should've looped back to element-1, it's instead in ${focusedElementId}`) + }) + }) + + describe('a SHIFT + TAB press', () => { + const shiftTabPressEvent = { + type: 'keyDown', + modifiers: ['Shift'], + keyCode: 'Tab' + } + + it('moves focus to the previous focusable item', async () => { + let focusChange = expectFocusChange() + w.webContents.sendInputEvent(shiftTabPressEvent) + let focusedElementId = await focusChange + assert.strictEqual(focusedElementId, 'BUTTON-element-3', `should start focused in element-3, it's instead in ${focusedElementId}`) + + focusChange = expectFocusChange() + w.webContents.sendInputEvent(shiftTabPressEvent) + focusedElementId = await focusChange + assert.strictEqual(focusedElementId, 'BUTTON-wv-element-2', `focus should've moved to the webview's element-2, it's instead in ${focusedElementId}`) + + focusChange = expectFocusChange() + webviewContents.sendInputEvent(shiftTabPressEvent) + focusedElementId = await focusChange + assert.strictEqual(focusedElementId, 'BUTTON-wv-element-1', `focus should've moved to the webview's element-1, it's instead in ${focusedElementId}`) + + focusChange = expectFocusChange() + webviewContents.sendInputEvent(shiftTabPressEvent) + focusedElementId = await focusChange + assert.strictEqual(focusedElementId, 'BUTTON-element-2', `focus should've moved to element-2, it's instead in ${focusedElementId}`) + + focusChange = expectFocusChange() + w.webContents.sendInputEvent(shiftTabPressEvent) + focusedElementId = await focusChange + assert.strictEqual(focusedElementId, 'BUTTON-element-1', `focus should've moved to element-1, it's instead in ${focusedElementId}`) + + focusChange = expectFocusChange() + w.webContents.sendInputEvent(shiftTabPressEvent) + focusedElementId = await focusChange + assert.strictEqual(focusedElementId, 'BUTTON-element-3', `focus should've looped back to element-3, it's instead in ${focusedElementId}`) + }) + }) + }) }) describe('font fallback', () => { diff --git a/spec/fixtures/pages/tab-focus-loop-elements-wv.html b/spec/fixtures/pages/tab-focus-loop-elements-wv.html new file mode 100644 index 0000000000000..b2daec0fc17e2 --- /dev/null +++ b/spec/fixtures/pages/tab-focus-loop-elements-wv.html @@ -0,0 +1,25 @@ + + + + + + +
+ + +
+ + + diff --git a/spec/fixtures/pages/tab-focus-loop-elements.html b/spec/fixtures/pages/tab-focus-loop-elements.html new file mode 100644 index 0000000000000..b10b6cba80796 --- /dev/null +++ b/spec/fixtures/pages/tab-focus-loop-elements.html @@ -0,0 +1,27 @@ + + + + + + + +
+ + + + +
+ +