Merge pull request #8143 from poiru/webcontents-before-input-event
Add before-input-event event for webContents (fixes #7586)
This commit is contained in:
commit
25feb9232d
8 changed files with 161 additions and 2 deletions
|
@ -488,6 +488,17 @@ void WebContents::HandleKeyboardEvent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WebContents::PreHandleKeyboardEvent(
|
||||||
|
content::WebContents* source,
|
||||||
|
const content::NativeWebKeyboardEvent& event,
|
||||||
|
bool* is_keyboard_shortcut) {
|
||||||
|
if (event.type == blink::WebInputEvent::Type::RawKeyDown
|
||||||
|
|| event.type == blink::WebInputEvent::Type::KeyUp)
|
||||||
|
return Emit("before-input-event", event);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void WebContents::EnterFullscreenModeForTab(content::WebContents* source,
|
void WebContents::EnterFullscreenModeForTab(content::WebContents* source,
|
||||||
const GURL& origin) {
|
const GURL& origin) {
|
||||||
auto permission_helper =
|
auto permission_helper =
|
||||||
|
|
|
@ -244,6 +244,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
void HandleKeyboardEvent(
|
void HandleKeyboardEvent(
|
||||||
content::WebContents* source,
|
content::WebContents* source,
|
||||||
const content::NativeWebKeyboardEvent& event) override;
|
const content::NativeWebKeyboardEvent& event) override;
|
||||||
|
bool PreHandleKeyboardEvent(content::WebContents* source,
|
||||||
|
const content::NativeWebKeyboardEvent& event,
|
||||||
|
bool* is_keyboard_shortcut) override;
|
||||||
void EnterFullscreenModeForTab(content::WebContents* source,
|
void EnterFullscreenModeForTab(content::WebContents* source,
|
||||||
const GURL& origin) override;
|
const GURL& origin) override;
|
||||||
void ExitFullscreenModeForTab(content::WebContents* source) override;
|
void ExitFullscreenModeForTab(content::WebContents* source) override;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "third_party/WebKit/public/web/WebFindOptions.h"
|
#include "third_party/WebKit/public/web/WebFindOptions.h"
|
||||||
#include "third_party/WebKit/public/web/WebInputEvent.h"
|
#include "third_party/WebKit/public/web/WebInputEvent.h"
|
||||||
#include "ui/base/clipboard/clipboard.h"
|
#include "ui/base/clipboard/clipboard.h"
|
||||||
|
#include "ui/events/keycodes/dom/keycode_converter.h"
|
||||||
#include "ui/events/keycodes/keyboard_code_conversion.h"
|
#include "ui/events/keycodes/keyboard_code_conversion.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -215,6 +216,26 @@ bool Converter<content::NativeWebKeyboardEvent>::FromV8(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> Converter<content::NativeWebKeyboardEvent>::ToV8(
|
||||||
|
v8::Isolate* isolate, const content::NativeWebKeyboardEvent& in) {
|
||||||
|
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||||
|
|
||||||
|
if (in.type == blink::WebInputEvent::Type::RawKeyDown)
|
||||||
|
dict.Set("type", "keyDown");
|
||||||
|
else if (in.type == blink::WebInputEvent::Type::KeyUp)
|
||||||
|
dict.Set("type", "keyUp");
|
||||||
|
dict.Set("key", ui::KeycodeConverter::DomKeyToKeyString(in.domKey));
|
||||||
|
|
||||||
|
using Modifiers = blink::WebInputEvent::Modifiers;
|
||||||
|
dict.Set("isAutoRepeat", (in.modifiers & Modifiers::IsAutoRepeat) != 0);
|
||||||
|
dict.Set("shift", (in.modifiers & Modifiers::ShiftKey) != 0);
|
||||||
|
dict.Set("control", (in.modifiers & Modifiers::ControlKey) != 0);
|
||||||
|
dict.Set("alt", (in.modifiers & Modifiers::AltKey) != 0);
|
||||||
|
dict.Set("meta", (in.modifiers & Modifiers::MetaKey) != 0);
|
||||||
|
|
||||||
|
return dict.GetHandle();
|
||||||
|
}
|
||||||
|
|
||||||
bool Converter<blink::WebMouseEvent>::FromV8(
|
bool Converter<blink::WebMouseEvent>::FromV8(
|
||||||
v8::Isolate* isolate, v8::Local<v8::Value> val, blink::WebMouseEvent* out) {
|
v8::Isolate* isolate, v8::Local<v8::Value> val, blink::WebMouseEvent* out) {
|
||||||
mate::Dictionary dict;
|
mate::Dictionary dict;
|
||||||
|
|
|
@ -45,6 +45,8 @@ template<>
|
||||||
struct Converter<content::NativeWebKeyboardEvent> {
|
struct Converter<content::NativeWebKeyboardEvent> {
|
||||||
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
|
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
|
||||||
content::NativeWebKeyboardEvent* out);
|
content::NativeWebKeyboardEvent* out);
|
||||||
|
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||||
|
const content::NativeWebKeyboardEvent& in);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
|
@ -232,6 +232,24 @@ Emitted when a plugin process has crashed.
|
||||||
|
|
||||||
Emitted when `webContents` is destroyed.
|
Emitted when `webContents` is destroyed.
|
||||||
|
|
||||||
|
#### Event: 'before-input-event'
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
* `event` Event
|
||||||
|
* `input` Object - Input properties
|
||||||
|
* `type` String - Either `keyUp` or `keyDown`
|
||||||
|
* `key` String - Equivalent to [KeyboardEvent.key](keyboardevent)
|
||||||
|
* `isAutoRepeat` Boolean - Equivalent to [KeyboardEvent.repeat](keyboardevent)
|
||||||
|
* `shift` Boolean - Equivalent to [KeyboardEvent.shiftKey](keyboardevent)
|
||||||
|
* `control` Boolean - Equivalent to [KeyboardEvent.controlKey](keyboardevent)
|
||||||
|
* `alt` Boolean - Equivalent to [KeyboardEvent.altKey](keyboardevent)
|
||||||
|
* `meta` Boolean - Equivalent to [KeyboardEvent.metaKey](keyboardevent)
|
||||||
|
|
||||||
|
Emitted before dispatching the `keydown` and `keyup` events in the page.
|
||||||
|
Calling `event.preventDefault` will prevent the page `keydown`/`keyup` events
|
||||||
|
from being dispatched.
|
||||||
|
|
||||||
#### Event: 'devtools-opened'
|
#### Event: 'devtools-opened'
|
||||||
|
|
||||||
Emitted when DevTools is opened.
|
Emitted when DevTools is opened.
|
||||||
|
@ -1217,3 +1235,5 @@ when the DevTools has been closed.
|
||||||
#### `contents.debugger`
|
#### `contents.debugger`
|
||||||
|
|
||||||
A [Debugger](debugger.md) instance for this webContents.
|
A [Debugger](debugger.md) instance for this webContents.
|
||||||
|
|
||||||
|
[keyboardevent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
|
||||||
|
|
|
@ -4,7 +4,7 @@ const assert = require('assert')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const {closeWindow} = require('./window-helpers')
|
const {closeWindow} = require('./window-helpers')
|
||||||
|
|
||||||
const {remote} = require('electron')
|
const {ipcRenderer, remote} = require('electron')
|
||||||
const {BrowserWindow, webContents, ipcMain} = remote
|
const {BrowserWindow, webContents, ipcMain} = remote
|
||||||
|
|
||||||
const isCi = remote.getGlobal('isCi')
|
const isCi = remote.getGlobal('isCi')
|
||||||
|
@ -98,6 +98,101 @@ describe('webContents module', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('before-input-event event', () => {
|
||||||
|
it('can prevent document keyboard events', (done) => {
|
||||||
|
w.loadURL('file://' + path.join(__dirname, 'fixtures', 'pages', 'key-events.html'))
|
||||||
|
w.webContents.once('did-finish-load', () => {
|
||||||
|
ipcMain.once('keydown', (event, key) => {
|
||||||
|
assert.equal(key, 'b')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcRenderer.send('prevent-next-input-event', 'a', w.webContents.id)
|
||||||
|
w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'a'})
|
||||||
|
w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'b'})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the correct properties', (done) => {
|
||||||
|
w.loadURL('file://' + path.join(__dirname, 'fixtures', 'pages', 'base-page.html'))
|
||||||
|
w.webContents.once('did-finish-load', () => {
|
||||||
|
const testBeforeInput = (opts) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
w.webContents.once('before-input-event', (event, input) => {
|
||||||
|
assert.equal(input.type, opts.type)
|
||||||
|
assert.equal(input.key, opts.key)
|
||||||
|
assert.equal(input.isAutoRepeat, opts.isAutoRepeat)
|
||||||
|
assert.equal(input.shift, opts.shift)
|
||||||
|
assert.equal(input.control, opts.control)
|
||||||
|
assert.equal(input.alt, opts.alt)
|
||||||
|
assert.equal(input.meta, opts.meta)
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
|
||||||
|
const modifiers = []
|
||||||
|
if (opts.shift) modifiers.push('shift')
|
||||||
|
if (opts.control) modifiers.push('control')
|
||||||
|
if (opts.alt) modifiers.push('alt')
|
||||||
|
if (opts.meta) modifiers.push('meta')
|
||||||
|
if (opts.isAutoRepeat) modifiers.push('isAutoRepeat')
|
||||||
|
|
||||||
|
w.webContents.sendInputEvent({
|
||||||
|
type: opts.type,
|
||||||
|
keyCode: opts.keyCode,
|
||||||
|
modifiers: modifiers
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise.resolve().then(() => {
|
||||||
|
return testBeforeInput({
|
||||||
|
type: 'keyDown',
|
||||||
|
key: 'A',
|
||||||
|
keyCode: 'a',
|
||||||
|
shift: true,
|
||||||
|
control: true,
|
||||||
|
alt: true,
|
||||||
|
meta: true,
|
||||||
|
isAutoRepeat: true
|
||||||
|
})
|
||||||
|
}).then(() => {
|
||||||
|
return testBeforeInput({
|
||||||
|
type: 'keyUp',
|
||||||
|
key: '.',
|
||||||
|
keyCode: '.',
|
||||||
|
shift: false,
|
||||||
|
control: true,
|
||||||
|
alt: true,
|
||||||
|
meta: false,
|
||||||
|
isAutoRepeat: false
|
||||||
|
})
|
||||||
|
}).then(() => {
|
||||||
|
return testBeforeInput({
|
||||||
|
type: 'keyUp',
|
||||||
|
key: '!',
|
||||||
|
keyCode: '1',
|
||||||
|
shift: true,
|
||||||
|
control: false,
|
||||||
|
alt: false,
|
||||||
|
meta: true,
|
||||||
|
isAutoRepeat: false
|
||||||
|
})
|
||||||
|
}).then(() => {
|
||||||
|
return testBeforeInput({
|
||||||
|
type: 'keyUp',
|
||||||
|
key: 'Tab',
|
||||||
|
keyCode: 'Tab',
|
||||||
|
shift: false,
|
||||||
|
control: true,
|
||||||
|
alt: false,
|
||||||
|
meta: false,
|
||||||
|
isAutoRepeat: true
|
||||||
|
})
|
||||||
|
}).then(done).catch(done)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('sendInputEvent(event)', function () {
|
describe('sendInputEvent(event)', function () {
|
||||||
beforeEach(function (done) {
|
beforeEach(function (done) {
|
||||||
w.loadURL('file://' + path.join(__dirname, 'fixtures', 'pages', 'key-events.html'))
|
w.loadURL('file://' + path.join(__dirname, 'fixtures', 'pages', 'key-events.html'))
|
||||||
|
|
|
@ -8,6 +8,7 @@ const ipcMain = electron.ipcMain
|
||||||
const dialog = electron.dialog
|
const dialog = electron.dialog
|
||||||
const BrowserWindow = electron.BrowserWindow
|
const BrowserWindow = electron.BrowserWindow
|
||||||
const protocol = electron.protocol
|
const protocol = electron.protocol
|
||||||
|
const webContents = electron.webContents
|
||||||
const v8 = require('v8')
|
const v8 = require('v8')
|
||||||
|
|
||||||
const Coverage = require('electabul').Coverage
|
const Coverage = require('electabul').Coverage
|
||||||
|
@ -184,6 +185,12 @@ app.on('ready', function () {
|
||||||
event.returnValue = 'done'
|
event.returnValue = 'done'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ipcMain.on('prevent-next-input-event', (event, key, id) => {
|
||||||
|
webContents.fromId(id).once('before-input-event', (event, input) => {
|
||||||
|
if (key === input.key) event.preventDefault()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
ipcMain.on('executeJavaScript', function (event, code, hasCallback) {
|
ipcMain.on('executeJavaScript', function (event, code, hasCallback) {
|
||||||
if (hasCallback) {
|
if (hasCallback) {
|
||||||
window.webContents.executeJavaScript(code, (result) => {
|
window.webContents.executeJavaScript(code, (result) => {
|
||||||
|
|
2
vendor/brightray
vendored
2
vendor/brightray
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit b8c8a31e9253406ef410f0d253bf1507448c222d
|
Subproject commit 365eacb67d86581670519d09c3ce266f5c47313e
|
Loading…
Add table
Add a link
Reference in a new issue