Commit c790e5d1 authored by Joe Downing's avatar Joe Downing Committed by Commit Bot

Move KeyboardLock API methods to a 'keyboard' object

This change moves the KeyboardLock API methods to a 'keyboard'
namespace on the Navigator object.  We are doing this work now as
there has been a request for additional keyboard functionality that
would also be placed on the new keyboard object and we wanted to
move the KeyboardLock methods there for consistency before we launch.

KeyboardLock API Spec is here:
https://w3c.github.io/keyboard-lock/#API

Old calling pattern:
Navigator.keyboardLock();
Navigator.keyboardUnlock();

New calling pattern:
Navigator.keyboard.lock();
Navigator.keyboard.unlock();

Note: The main logic in the KeyboardLock.cpp class and tests is the
same as it was, however the file changed enough that git does not
recognize it as a file move.

BUG=680809

Change-Id: I234b2ab12d5ecd44c894ed5103863fd96fd548d4
Reviewed-on: https://chromium-review.googlesource.com/969656Reviewed-by: default avatarPhilip Jägenstedt <foolip@chromium.org>
Reviewed-by: default avatarGary Kacmarcik <garykac@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#544996}
parent 6eaf64fc
partial interface Navigator {
[SecureContext, SameObject] readonly attribute Keyboard keyboard;
};
[SecureContext, Exposed=Window] interface Keyboard {
Promise<void> lock(optional sequence<DOMString> keyCodes = []);
void unlock();
};
This is a testharness.js-based test.
FAIL Navigator interface: operation keyboardLock(sequence) assert_throws: calling operation with this = null didn't throw TypeError function "function() {
fn.apply(obj, args);
}" did not throw
PASS Unscopable handled correctly for keyboardLock(sequence) on Navigator
PASS Navigator interface: operation keyboardUnlock()
PASS Unscopable handled correctly for keyboardUnlock() on Navigator
PASS Navigator interface: navigator must inherit property "keyboardLock(sequence)" with the proper type
PASS Navigator interface: calling keyboardLock(sequence) on navigator with too few arguments must throw TypeError
PASS Navigator interface: navigator must inherit property "keyboardUnlock()" with the proper type
Harness: the test ran to completion.
<!doctype html>
<html>
<head>
<title>Keyboard Lock IDL tests</title>
<link rel="help" href="https://github.com/w3c/keyboard-lock"/>
<title>Keyboard IDL tests</title>
<link rel="help" href="https://w3c.github.io/keyboard-lock/"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/WebIDLParser.js"></script>
<script src="/resources/idlharness.js"></script>
</head>
<body>
<pre id="untested_idl" style="display: none">
interface Navigator {
};
</pre>
<!--
The reason of the failure of keyboardLock test looks like a code defect in
idlharness.js. media-capabilities/idlharness.html is also impacted by this
issue. See https://codereview.chromium.org/2805763004/#ps620001, which
includes a potential fix.
TODO(joedow): Submit the fix.
-->
<pre id="idl" style="display: none">
partial interface Navigator {
[SecureContext] Promise<void> keyboardLock(optional sequence<DOMString> keyCodes = []);
[SecureContext] void keyboardUnlock();
};
</pre>
<script>
var idl_array = new IdlArray();
idl_array.add_untested_idls(
document.getElementById("untested_idl").textContent);
idl_array.add_idls(document.getElementById("idl").textContent);
idl_array.add_objects({
Navigator: ["navigator"]
});
idl_array.test();
'use strict';
function doTest(idls) {
var idl_array = new IdlArray();
idl_array.add_untested_idls('interface Navigator {};');
for (let idl of idls) {
idl_array.add_idls(idl);
}
idl_array.add_objects({
Navigator: ['navigator'],
Keyboard: ['navigator.keyboard'],
});
idl_array.test();
};
function fetchText(url) {
return fetch(url).then((response) => response.text());
}
promise_test(() => {
return Promise.all(["/interfaces/keyboard-lock.idl"].map(fetchText))
.then(doTest);
}, "Test driver");
</script>
<div id="log"></div>
</body>
</html>
This is a testharness.js-based test.
FAIL [Keyboard Lock] keyboard.lock twice in parallel assert_throws: keyboard.lock() should only be executed if another request has finished. function "function() { throw e }" threw "Last lock() call has not finished yet." with type "string", not an object
Harness: the test ran to completion.
......@@ -5,11 +5,11 @@
'use strict';
promise_test((t) => {
const p1 = navigator.keyboardLock(['a', 'b']);
const p2 = navigator.keyboardLock(['c', 'd']);
const p1 = navigator.keyboard.lock(['a', 'b']);
const p2 = navigator.keyboard.lock(['c', 'd']);
return promise_rejects(t, null, p2,
'keyboardLock() should only be ' +
'keyboard.lock() should only be ' +
'executed if another request has finished.');
}, 'Keyboard Lock keyboardLock twice in parallel');
}, '[Keyboard Lock] keyboard.lock twice in parallel');
</script>
......@@ -5,10 +5,10 @@
'use strict';
promise_test(() => {
return navigator.keyboardLock(['a', 'b'])
return navigator.keyboard.lock(['a', 'b'])
.then(() => {
return navigator.keyboardLock(['c', 'd']);
return navigator.keyboard.lock(['c', 'd']);
});
}, 'Keyboard Lock keyboardLock twice sequentially');
}, '[Keyboard Lock] keyboard.lock called twice sequentially');
</script>
......@@ -5,9 +5,9 @@
'use strict';
promise_test(() => {
const p = navigator.keyboardLock(['a', 'b']);
const p = navigator.keyboard.lock(['a', 'b']);
assert_true(p instanceof Promise);
return p;
}, 'Keyboard Lock keyboardLock');
}, '[Keyboard Lock] keyboard.lock');
</script>
......@@ -5,8 +5,8 @@
'use strict';
test(() => {
assert_equals(navigator.keyboardUnlock(),
assert_equals(navigator.keyboard.unlock(),
undefined);
}, 'Keyboard Lock keyboardUnlock');
}, '[Keyboard Lock] keyboard.unlock');
</script>
This is a testharness.js-based test.
FAIL Keyboard Lock keyboardLock twice in parallel assert_throws: keyboardLock() should only be executed if another request has finished. function "function() { throw e }" threw "Last keyboardLock() has not finished yet." with type "string", not an object
Harness: the test ran to completion.
......@@ -4009,6 +4009,11 @@ interface IntersectionObserverEntry
getter target
getter time
method constructor
interface Keyboard
attribute @@toStringTag
method constructor
method lock
method unlock
interface KeyboardEvent : UIEvent
attribute @@toStringTag
attribute DOM_KEY_LOCATION_LEFT
......@@ -4559,6 +4564,7 @@ interface Navigator
getter doNotTrack
getter geolocation
getter hardwareConcurrency
getter keyboard
getter language
getter languages
getter locks
......@@ -4591,8 +4597,6 @@ interface Navigator
method getUserMedia
method getVRDisplays
method javaEnabled
method keyboardLock
method keyboardUnlock
method registerProtocolHandler
method requestMIDIAccess
method requestMediaKeySystemAccess
......
......@@ -119,7 +119,7 @@ target("jumbo_" + modules_target_type, "modules") {
"//third_party/WebKit/Source/modules/indexeddb",
"//third_party/WebKit/Source/modules/installation",
"//third_party/WebKit/Source/modules/installedapp",
"//third_party/WebKit/Source/modules/keyboard_lock",
"//third_party/WebKit/Source/modules/keyboard",
"//third_party/WebKit/Source/modules/locks",
"//third_party/WebKit/Source/modules/media_capabilities",
"//third_party/WebKit/Source/modules/media_controls",
......
# Copyright 2017 The Chromium Authors. All rights reserved.
# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//third_party/WebKit/Source/modules/modules.gni")
blink_modules_sources("keyboard_lock") {
blink_modules_sources("keyboard") {
sources = [
"NavigatorKeyboardLock.cpp",
"NavigatorKeyboardLock.h",
"Keyboard.cpp",
"Keyboard.h",
"KeyboardLock.cpp",
"KeyboardLock.h",
"NavigatorKeyboard.cpp",
"NavigatorKeyboard.h",
]
}
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/keyboard/Keyboard.h"
#include "core/dom/ExecutionContext.h"
#include "modules/keyboard/KeyboardLock.h"
#include "platform/bindings/ScriptState.h"
namespace blink {
Keyboard::Keyboard(ExecutionContext* context)
: keyboard_lock_(new KeyboardLock(context)) {}
Keyboard::~Keyboard() = default;
ScriptPromise Keyboard::lock(ScriptState* state,
const Vector<String>& keycodes) {
return keyboard_lock_->lock(state, keycodes);
}
void Keyboard::unlock() {
keyboard_lock_->unlock();
}
void Keyboard::Trace(blink::Visitor* visitor) {
visitor->Trace(keyboard_lock_);
ScriptWrappable::Trace(visitor);
}
} // namespace blink
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef Keyboard_h
#define Keyboard_h
#include "bindings/core/v8/ScriptPromise.h"
#include "platform/bindings/ScriptWrappable.h"
namespace blink {
class ExecutionContext;
class KeyboardLock;
class ScriptState;
class Keyboard final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
WTF_MAKE_NONCOPYABLE(Keyboard);
public:
explicit Keyboard(ExecutionContext*);
~Keyboard() override;
// KeyboardLock API: https://w3c.github.io/keyboard-lock/
ScriptPromise lock(ScriptState*, const Vector<String>&);
void unlock();
// ScriptWrappable override.
void Trace(blink::Visitor*) override;
private:
Member<KeyboardLock> keyboard_lock_;
};
} // namespace blink
#endif // Keyboard_h
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[
Exposed=Window,
RuntimeEnabled=KeyboardLock,
SecureContext
] interface Keyboard {
[CallWith=ScriptState] Promise<void> lock(optional sequence<DOMString> keyCodes = []);
void unlock();
};
// Copyright 2017 The Chromium Authors. All rights reserved.
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/keyboard_lock/NavigatorKeyboardLock.h"
#include "modules/keyboard/KeyboardLock.h"
#include "bindings/core/v8/ScriptPromise.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
......@@ -15,52 +15,35 @@
namespace blink {
NavigatorKeyboardLock::NavigatorKeyboardLock(Navigator& navigator)
: Supplement<Navigator>(navigator) {}
KeyboardLock::KeyboardLock(ExecutionContext* context)
: ContextLifecycleObserver(context) {}
NavigatorKeyboardLock& NavigatorKeyboardLock::From(Navigator& navigator) {
NavigatorKeyboardLock* supplement =
Supplement<Navigator>::From<NavigatorKeyboardLock>(navigator);
if (!supplement) {
supplement = new NavigatorKeyboardLock(navigator);
ProvideTo(navigator, supplement);
}
return *supplement;
}
// static
ScriptPromise NavigatorKeyboardLock::keyboardLock(
ScriptState* state,
Navigator& navigator,
const Vector<String>& keycodes) {
return NavigatorKeyboardLock::From(navigator).keyboardLock(state, keycodes);
}
KeyboardLock::~KeyboardLock() = default;
ScriptPromise NavigatorKeyboardLock::keyboardLock(
ScriptState* state,
const Vector<String>& keycodes) {
ScriptPromise KeyboardLock::lock(ScriptState* state,
const Vector<String>& keycodes) {
DCHECK(state);
if (request_keylock_resolver_) {
// TODO(joedow): Reject with a DOMException once it has been defined in the
// spec. See https://github.com/w3c/keyboard-lock/issues/18.
return ScriptPromise::Reject(
state, V8String(state->GetIsolate(),
"Last keyboardLock() has not finished yet."));
"Last lock() call has not finished yet."));
}
if (!EnsureServiceConnected()) {
return ScriptPromise::Reject(
state, V8String(state->GetIsolate(), "Current frame is detached."));
return ScriptPromise::Reject(
state, V8String(state->GetIsolate(), "Current frame is detached."));
}
request_keylock_resolver_ = ScriptPromiseResolver::Create(state);
service_->RequestKeyboardLock(
keycodes, WTF::Bind(&NavigatorKeyboardLock::LockRequestFinished,
WrapPersistent(this)));
keycodes,
WTF::Bind(&KeyboardLock::LockRequestFinished, WrapPersistent(this)));
return request_keylock_resolver_->Promise();
}
void NavigatorKeyboardLock::keyboardUnlock() {
void KeyboardLock::unlock() {
if (!EnsureServiceConnected()) {
// Current frame is detached.
return;
......@@ -69,14 +52,9 @@ void NavigatorKeyboardLock::keyboardUnlock() {
service_->CancelKeyboardLock();
}
// static
void NavigatorKeyboardLock::keyboardUnlock(Navigator& navigator) {
NavigatorKeyboardLock::From(navigator).keyboardUnlock();
}
bool NavigatorKeyboardLock::EnsureServiceConnected() {
bool KeyboardLock::EnsureServiceConnected() {
if (!service_) {
LocalFrame* frame = GetSupplementable()->GetFrame();
LocalFrame* frame = GetFrame();
if (!frame) {
return false;
}
......@@ -87,7 +65,7 @@ bool NavigatorKeyboardLock::EnsureServiceConnected() {
return true;
}
void NavigatorKeyboardLock::LockRequestFinished(
void KeyboardLock::LockRequestFinished(
mojom::KeyboardLockRequestResult result) {
DCHECK(request_keylock_resolver_);
// TODO(joedow): Reject with a DOMException once it has been defined in the
......@@ -100,12 +78,9 @@ void NavigatorKeyboardLock::LockRequestFinished(
request_keylock_resolver_ = nullptr;
}
// static
const char NavigatorKeyboardLock::kSupplementName[] = "NavigatorKeyboardLock";
void NavigatorKeyboardLock::Trace(blink::Visitor* visitor) {
void KeyboardLock::Trace(blink::Visitor* visitor) {
visitor->Trace(request_keylock_resolver_);
Supplement<Navigator>::Trace(visitor);
ContextLifecycleObserver::Trace(visitor);
}
} // namespace blink
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef KeyboardLock_h
#define KeyboardLock_h
#include "bindings/core/v8/ScriptPromise.h"
#include "core/CoreExport.h"
#include "core/dom/ContextLifecycleObserver.h"
#include "platform/heap/Member.h"
#include "public/platform/modules/keyboard_lock/keyboard_lock.mojom-blink.h"
namespace blink {
class ScriptPromiseResolver;
class KeyboardLock final : public GarbageCollectedFinalized<KeyboardLock>,
public ContextLifecycleObserver {
USING_GARBAGE_COLLECTED_MIXIN(KeyboardLock);
WTF_MAKE_NONCOPYABLE(KeyboardLock);
public:
explicit KeyboardLock(ExecutionContext*);
~KeyboardLock();
ScriptPromise lock(ScriptState*, const Vector<String>&);
void unlock();
// ContextLifecycleObserver override.
void Trace(blink::Visitor*) override;
private:
// Returns true if |service_| is initialized and ready to be called.
bool EnsureServiceConnected();
void LockRequestFinished(mojom::KeyboardLockRequestResult);
mojom::blink::KeyboardLockServicePtr service_;
Member<ScriptPromiseResolver> request_keylock_resolver_;
};
} // namespace blink
#endif // KeyboardLock_h
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/keyboard/NavigatorKeyboard.h"
#include "core/dom/Document.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/Navigator.h"
#include "modules/keyboard/Keyboard.h"
namespace blink {
// static
const char NavigatorKeyboard::kSupplementName[] = "NavigatorKeyboard";
NavigatorKeyboard::NavigatorKeyboard(Navigator& navigator)
: Supplement<Navigator>(navigator),
keyboard_(
new Keyboard(GetSupplementable()->GetFrame()
? GetSupplementable()->GetFrame()->GetDocument()
: nullptr)) {}
// static
Keyboard* NavigatorKeyboard::keyboard(Navigator& navigator) {
NavigatorKeyboard* supplement =
Supplement<Navigator>::From<NavigatorKeyboard>(navigator);
if (!supplement) {
supplement = new NavigatorKeyboard(navigator);
ProvideTo(navigator, supplement);
}
return supplement->keyboard_;
}
void NavigatorKeyboard::Trace(blink::Visitor* visitor) {
visitor->Trace(keyboard_);
Supplement<Navigator>::Trace(visitor);
}
} // namespace blink
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NavigatorKeyboard_h
#define NavigatorKeyboard_h
#include "core/CoreExport.h"
#include "core/frame/Navigator.h"
#include "platform/Supplementable.h"
#include "platform/heap/Handle.h"
namespace blink {
class Keyboard;
// Navigator supplement which exposes keyboard related functionality.
class NavigatorKeyboard final : public GarbageCollected<NavigatorKeyboard>,
public Supplement<Navigator> {
USING_GARBAGE_COLLECTED_MIXIN(NavigatorKeyboard);
WTF_MAKE_NONCOPYABLE(NavigatorKeyboard);
public:
static const char kSupplementName[];
static Keyboard* keyboard(Navigator&);
void Trace(blink::Visitor*);
private:
explicit NavigatorKeyboard(Navigator&);
Member<Keyboard> keyboard_;
};
} // namespace blink
#endif // NavigatorKeyboard_h
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[
ImplementedAs=NavigatorKeyboard,
RuntimeEnabled=KeyboardLock
] partial interface Navigator {
[SameObject, SecureContext] readonly attribute Keyboard keyboard;
};
garykac@chromium.org
joedow@chromium.org
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NavigatorKeyboardLock_h
#define NavigatorKeyboardLock_h
#include "bindings/core/v8/ScriptPromise.h"
#include "core/frame/Navigator.h"
#include "platform/Supplementable.h"
#include "platform/heap/Handle.h"
#include "platform/heap/Member.h"
#include "platform/wtf/Forward.h"
#include "public/platform/modules/keyboard_lock/keyboard_lock.mojom-blink.h"
namespace blink {
class ScriptPromiseResolver;
// The supplement of Navigator to process navigator.keyboardLock() and
// navigator.keyboardUnlock() web APIs. This class forwards both requests
// directly to the browser process through mojo.
class NavigatorKeyboardLock final
: public GarbageCollectedFinalized<NavigatorKeyboardLock>,
public Supplement<Navigator> {
USING_GARBAGE_COLLECTED_MIXIN(NavigatorKeyboardLock);
public:
static const char kSupplementName[];
// Requests to receive a set of key codes
// (https://w3c.github.io/uievents/#dom-keyboardevent-code) in string format.
// The Promise will be rejected if the user or browser does not allow the web
// page to use this API. Otherwise, the web page should expect to receive the
// key presses once the Promise has been resolved. This API does best effort
// to deliver the key codes: due to the platform restrictions, some keys or
// key combinations cannot be received or intercepted by the user agent.
// - TODO(joedow): Update concurrent promise behavior to match spec.
// - Making two requests concurrently without waiting for one Promise to
// finish is disallowed, the second Promise will be rejected immediately.
// - Making a second request after the Promise of the first one has finished
// is allowed; the second request will overwrite the key codes reserved.
// - Passing in an empty keyCodes array will reserve all keys.
static ScriptPromise keyboardLock(ScriptState*,
Navigator&,
const Vector<String>&);
// Removes all reserved keys. This function is asynchronous so the web page
// may still receive reserved keys after this function has returned. Once
// the web page is closed, the user agent implicitly executes this API.
static void keyboardUnlock(Navigator&);
void Trace(blink::Visitor*);
private:
explicit NavigatorKeyboardLock(Navigator&);
static NavigatorKeyboardLock& From(Navigator&);
ScriptPromise keyboardLock(ScriptState*, const Vector<String>&);
void keyboardUnlock();
// Returns true if |service_| is initialized and ready to be called.
bool EnsureServiceConnected();
void LockRequestFinished(mojom::KeyboardLockRequestResult);
mojom::blink::KeyboardLockServicePtr service_;
Member<ScriptPromiseResolver> request_keylock_resolver_;
};
} // namespace blink
#endif // NavigatorKeyboardLock_h
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// https://rawgit.com/w3c/keyboard-lock/gh-pages/index.html.
// TODO(joedow, garykac): Update the spec to match the implementation.
// 1. "System" should be removed from both the function names: these functions
// are not for system keys or key combinations only.
// See https://github.com/w3c/keyboard-lock/issues/6
// 2. Returns Promise<void> from keyboardLock() function: user agents can
// decline the request, and web page can get a notification once the
// requested keys should be received.
// See https://github.com/w3c/keyboard-lock/issues/7
// 3. The parameter of keyboardLock() should be
// optional sequence<DOMString> keyCodes = []
// See https://github.com/w3c/keyboard-lock/issues/21
// 4. keyboardUnlock() function is implicitly called whenever the unloading
// document cleanup steps run with a document.
// See https://github.com/w3c/keyboard-lock/issues/22
[
ImplementedAs=NavigatorKeyboardLock
] partial interface Navigator {
[SecureContext, RuntimeEnabled=KeyboardLock, CallWith=ScriptState] Promise<void> keyboardLock(optional sequence<DOMString> keyCodes = []);
[SecureContext, RuntimeEnabled=KeyboardLock] void keyboardUnlock();
};
......@@ -170,6 +170,7 @@ modules_idl_files =
"indexeddb/IDBTransaction.idl",
"indexeddb/IDBVersionChangeEvent.idl",
"installedapp/RelatedApplication.idl",
"keyboard/Keyboard.idl",
"locks/Lock.idl",
"locks/LockManager.idl",
"media_capabilities/MediaCapabilities.idl",
......@@ -694,7 +695,7 @@ modules_dependency_idl_files =
"indexeddb/WindowIndexedDatabase.idl",
"indexeddb/WorkerGlobalScopeIndexedDatabase.idl",
"installedapp/NavigatorInstalledApp.idl",
"keyboard_lock/NavigatorKeyboardLock.idl",
"keyboard/NavigatorKeyboard.idl",
"locks/NavigatorLocks.idl",
"locks/WorkerNavigatorLocks.idl",
"media_capabilities/NavigatorMediaCapabilities.idl",
......
......@@ -8,8 +8,8 @@ enum KeyboardLockRequestResult {
SUCCESS = 0,
};
// The browser side service to process navigator.requestKeyboardLock() and
// navigator.cancelKeyboardLock() web APIs. See http://crbug.com/680809.
// The browser side service to process navigator.keyboard.lock() and
// navigator.keyboard.unlock() web APIs. See http://crbug.com/680809.
interface KeyboardLockService {
// Registers a set of string-formatted key codes
// (https://www.w3.org/TR/uievents/#interface-keyboardevent) to the platform
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment