Commit 31a6f70b authored by lukasza's avatar lukasza Committed by Commit bot

Handling PNaCl KeyboardInputEvent(s) in the key tester app.

BUG=407778

Review URL: https://codereview.chromium.org/884703006

Cr-Commit-Position: refs/heads/master@{#314424}
parent 67610e1e
......@@ -59,6 +59,7 @@
'remoting_client.gypi',
'remoting_host.gypi',
'remoting_host_srcs.gypi',
'remoting_key_tester.gypi',
'remoting_locales.gypi',
'remoting_srcs.gypi',
'remoting_test.gypi',
......
# Copyright 2015 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.
{
'includes': [
'../build/common_untrusted.gypi',
],
'variables': {
'remoting_key_tester_js_files': [
'tools/javascript_key_tester/background.js',
'tools/javascript_key_tester/chord_tracker.js',
'tools/javascript_key_tester/keyboard_map.js',
'tools/javascript_key_tester/main.js',
],
},
'conditions': [
['disable_nacl==0 and disable_nacl_untrusted==0', {
'targets': [
{
'target_name': 'remoting_key_tester',
'type': 'none',
'dependencies': [
'remoting_key_tester_pexe',
'remoting_key_tester_jscompile',
],
'copies': [
{
'destination': '<(PRODUCT_DIR)/remoting/key_tester',
'files': [
'<@(remoting_key_tester_js_files)',
'tools/javascript_key_tester/main.css',
'tools/javascript_key_tester/main.html',
'tools/javascript_key_tester/manifest.json',
'tools/javascript_key_tester/pnacl/remoting_key_tester.nmf',
'<(PRODUCT_DIR)/remoting_key_tester_newlib.pexe',
],
}
],
}, # end of target 'remoting_key_tester'
{
'target_name': 'remoting_key_tester_jscompile',
'type': 'none',
'conditions': [
# TODO(lukasza): Enable when remoting_key_tester_jscompile is clean.
# ['run_jscompile != 0', {
['0 != 0', {
'variables': {
'success_stamp': '<(PRODUCT_DIR)/<(_target_name).stamp',
},
'actions': [
{
'action_name': 'jscompile remoting_key_tester',
'inputs': [
'<@(remoting_key_tester_js_files)',
],
'outputs': [
'<(success_stamp)',
],
'action': [
'python', '../third_party/closure_compiler/checker.py',
'--strict',
'--no-single-file',
'--success-stamp', '<(success_stamp)',
'<@(remoting_key_tester_js_files)',
],
},
], # actions
}],
],
}, # end of target 'remoting_key_tester_jscompile'
{
'target_name': 'remoting_key_tester_pexe',
'type': 'none',
'sources': [
'tools/javascript_key_tester/pnacl/remoting_key_tester.cc',
],
'variables': {
'nexe_target': 'remoting_key_tester',
'build_glibc': 0,
'build_newlib': 0,
'build_pnacl_newlib': 1,
'extra_deps_pnacl_newlib': [
'>(tc_lib_dir_pnacl_newlib)/libppapi.a',
'>(tc_lib_dir_pnacl_newlib)/libppapi_cpp.a',
],
},
'link_flags': [
'-lppapi_stub',
'-lppapi_cpp',
],
}, # end of target 'remoting_key_tester_pexe'
],
}]
],
}
......@@ -4,7 +4,7 @@
{
'includes': [
'../native_client/build/untrusted.gypi',
'../build/common_untrusted.gypi',
'remoting_srcs.gypi',
],
......
The key tester is a Chrome app that dumps:
- PNaCl KeyboardInputEvent events
- JavaScript keydown/keyup events
To use the key tester:
1. Build: ninja -C out/Debug remoting_key_tester
2. In Chrome navigate to: chrome://extensions
3. Use "Load unpacked extension" to load the key tester
......@@ -14,26 +14,42 @@ var ChordTracker = function(parentDiv) {
};
/**
* @param {Event} event The keyup or keydown event.
* @param {number} keyCode
* @param {string} title
* @return {void}
*/
ChordTracker.prototype.addKeyEvent = function(event) {
this.begin_();
var span = document.createElement('span');
span.title = this.makeTitle_(event);
if (event.type == 'keydown') {
span.classList.add('key-down');
this.pressedKeys_[event.keyCode] = span;
} else {
span.classList.add('key-up');
delete this.pressedKeys_[event.keyCode];
}
span.innerText = this.keyName_(event.keyCode);
this.currentDiv_.appendChild(span);
ChordTracker.prototype.addKeyUpEvent = function(keyCode, title) {
var text = this.keyName_(keyCode);
var span = this.addSpanElement_('key-up', text, title);
delete this.pressedKeys_[keyCode];
if (!this.keysPressed_()) {
this.end_();
}
};
/**
* @param {number} keyCode
* @param {string} title
* @return {void}
*/
ChordTracker.prototype.addKeyDownEvent = function(keyCode, title) {
var text = this.keyName_(keyCode);
var span = this.addSpanElement_('key-down', text, title);
this.pressedKeys_[keyCode] = span;
};
/**
* @param {string} characterText
* @param {string} title
* @return {void}
*/
ChordTracker.prototype.addCharEvent = function(characterText, title) {
this.addSpanElement_('char-event', characterText, title);
};
/**
* @return {void}
*/
ChordTracker.prototype.releaseAllKeys = function() {
this.end_();
for (var i in this.pressedKeys_) {
......@@ -42,6 +58,22 @@ ChordTracker.prototype.releaseAllKeys = function() {
this.pressedKeys_ = {};
}
/**
* @private
* @param {string} className
* @param {string} text
* @param {string} title
*/
ChordTracker.prototype.addSpanElement_ = function(className, text, title) {
this.begin_();
var span = document.createElement('span');
span.classList.add(className);
span.innerText = text;
span.title = title;
this.currentDiv_.appendChild(span);
return span;
}
/**
* @private
*/
......@@ -93,18 +125,3 @@ ChordTracker.prototype.keyName_ = function(keyCode) {
return result;
};
/**
* @param {Event} event The keyup or keydown event.
* @private
*/
ChordTracker.prototype.makeTitle_ = function(event) {
return 'type: ' + event.type + '\n' +
'alt: ' + event.altKey + '\n' +
'shift: ' + event.shiftKey + '\n' +
'control: ' + event.controlKey + '\n' +
'meta: ' + event.metaKey + '\n' +
'charCode: ' + event.charCode + '\n' +
'keyCode: ' + event.keyCode + '\n' +
'keyIdentifier: ' + event.keyIdentifier + '\n' +
'repeat: ' + event.repeat + '\n';
};
......@@ -3,6 +3,7 @@
* found in the LICENSE file.
*/
/** @type {Array.<string>} */
var keyboardMap = [
'',
'',
......
......@@ -12,6 +12,30 @@ html {
height: 100%;
}
#pnacl-plugin {
background-color: gray;
border: 1px solid
}
#pnacl-plugin:focus {
background-color: yellow;
}
.summary-log-container {
width: 50%;
height: 50vh;
overflow-y: auto;
float: left;
}
.text-log-container {
width: 100%;
max-height: 25vh;
overflow-y: auto;
float: left;
}
.char-event,
.key-down,
.key-up {
border-radius: 4px;
......@@ -20,6 +44,14 @@ html {
margin-right: 2px;
}
.char-event {
background-color: yellow;
}
.char-event::before {
content: "char:";
}
.key-up {
background-color: #DFD;
}
......
......@@ -15,8 +15,30 @@ found in the LICENSE file.
</head>
<body>
<h2>Chrome AppsV2 Key Event Tester</h2>
<button id="clear-log">Clear log</button>
<div id="key-log">
<div id="pnacl-listener">
PNaCl focus box:
<embed id="pnacl-plugin" width=100 height=12
src="remoting_key_tester.nmf" type="application/x-pnacl" />
(click inside to get focus, yellow background means it has focus).
</div>
<button id="clear-log">Clear logs</button>
<hr/>
<div class="logs">
<div class="summary-log-container">
Summary of JavaScript logs:
<div id="javascript-log">
</div>
</div>
<div class="summary-log-container">
Summary of PNaCl logs:
<div id="pnacl-log">
</div>
</div>
<div class="text-log-container">
Text log of JSON-ified events:
<div id="text-log">
</div>
</div>
</div>
</body>
</html>
......@@ -3,17 +3,142 @@
* found in the LICENSE file.
*/
/**
* @param {string} eventName
* @param {number=} opt_space
* @return {string}
*/
function jsonifyJavascriptKeyEvent(event, eventName, opt_space) {
return "JavaScript '" + eventName + "' event = " + JSON.stringify(
event,
['type', 'alt', 'shift', 'control', 'meta', 'charCode', 'keyCode',
'keyIdentifier', 'repeat'],
opt_space);
};
/**
* @param {ChordTracker} jsChordTracker
* @param {Event} event
* @return {void}
*/
function handleJavascriptKeyDownEvent(jsChordTracker, event) {
appendToTextLog(jsonifyJavascriptKeyEvent(event, 'keydown', undefined));
jsChordTracker.addKeyDownEvent(
event.keyCode, jsonifyJavascriptKeyEvent(event, 'keydown', 2));
}
/**
* @param {ChordTracker} jsChordTracker
* @param {Event} event
* @return {void}
*/
function handleJavascriptKeyUpEvent(jsChordTracker, event) {
appendToTextLog(jsonifyJavascriptKeyEvent(event, 'keyup', undefined));
jsChordTracker.addKeyUpEvent(
event.keyCode, jsonifyJavascriptKeyEvent(event, 'keyup', 2));
}
/** @constructor */
var PNaClEvent = function() {
/** @type {string} */
this.type = "";
/** @type {number} */
this.modifiers = 0;
/** @type {number} */
this.keyCode = 0;
/** @type {string|undefined} */
this.characterText = undefined;
/** @type {string} */
this.code = "";
};
/**
* @param {PNaClEvent} event
* @param {number|undefined} space
* @return {string}
*/
function jsonifyPnaclKeyboardInputEvent(event, space) {
return "PNaCl KeyboardInputEvent = " + JSON.stringify(
event,
['type', 'modifiers', 'keyCode', 'characterText', 'code'],
space);
};
/**
* @param {ChordTracker} pnaclChordTracker
* @param {Event} event
* @return {void}
*/
function handlePNaclMessage(pnaclChordTracker, event) {
var pnaclEvent = /** @type {PNaClEvent} */ (event.data);
appendToTextLog(jsonifyPnaclKeyboardInputEvent(pnaclEvent, undefined));
var title = jsonifyPnaclKeyboardInputEvent(pnaclEvent, 2);
if (pnaclEvent.type == "KEYDOWN") {
pnaclChordTracker.addKeyDownEvent(pnaclEvent.keyCode, title);
}
if (pnaclEvent.type == "KEYUP") {
pnaclChordTracker.addKeyUpEvent(pnaclEvent.keyCode, title);
}
if (pnaclEvent.type == "CHAR") {
pnaclChordTracker.addCharEvent(pnaclEvent.characterText, title);
}
}
/**
* @param {string} str
* @return {void}
*/
function appendToTextLog(str) {
var textLog = document.getElementById('text-log');
var div = document.createElement('div');
div.innerText = str;
textLog.appendChild(div);
}
function onLoad() {
var parentDiv = document.getElementById('key-log');
var chordTracker = new ChordTracker(parentDiv);
// Start listening to Javascript keyup/keydown events.
var jsLog = document.getElementById('javascript-log');
var jsChordTracker = new ChordTracker(jsLog);
document.body.addEventListener(
'keydown', chordTracker.addKeyEvent.bind(chordTracker), false);
'keydown',
function (event) {
handleJavascriptKeyDownEvent(jsChordTracker, event);
},
false);
document.body.addEventListener(
'keyup', chordTracker.addKeyEvent.bind(chordTracker), false);
'keyup',
function (event) {
handleJavascriptKeyUpEvent(jsChordTracker, event);
},
false);
// Start listening to PNaCl keyboard input events.
var pnaclLog = document.getElementById('pnacl-log');
var pnaclChordTracker = new ChordTracker(pnaclLog);
document.getElementById('pnacl-listener').addEventListener(
'message',
function (message) {
handlePNaclMessage(pnaclChordTracker, message);
},
true);
// Start listening to generic, source-agnostic events.
window.addEventListener(
'blur', chordTracker.releaseAllKeys.bind(chordTracker), false);
'blur',
function () {
jsChordTracker.releaseAllKeys();
pnaclChordTracker.releaseAllKeys();
},
false);
document.getElementById('clear-log').addEventListener(
'click', function() { parentDiv.innerText = ''; }, false);
'click',
function() {
jsLog.innerText = '';
pnaclLog.innerText = '';
document.getElementById('text-log').innerText = '';
},
false);
}
window.addEventListener('load', onLoad, false);
// Copyright (c) 2015 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 <sstream>
#include "ppapi/cpp/input_event.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h"
#include "ppapi/cpp/var_dictionary.h"
namespace remoting {
class KeyTesterInstance : public pp::Instance {
public:
explicit KeyTesterInstance(PP_Instance instance) : pp::Instance(instance) {
RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
}
virtual ~KeyTesterInstance() {}
virtual bool HandleInputEvent(const pp::InputEvent& event) {
switch (event.GetType()) {
case PP_INPUTEVENT_TYPE_KEYDOWN:
case PP_INPUTEVENT_TYPE_KEYUP:
case PP_INPUTEVENT_TYPE_CHAR: {
HandleKeyboardEvent(pp::KeyboardInputEvent(event));
break;
}
default:
break;
}
return true;
}
private:
void HandleKeyboardEvent(const pp::KeyboardInputEvent& event) {
pp::VarDictionary out;
out.Set("type", EventTypeToString(event.GetType()));
out.Set("modifiers", (double)event.GetModifiers());
out.Set("keyCode", (double)event.GetKeyCode());
out.Set("characterText", event.GetCharacterText());
out.Set("code", event.GetCode());
PostMessage(out);
}
std::string EventTypeToString(PP_InputEvent_Type t) {
switch (t) {
case PP_INPUTEVENT_TYPE_UNDEFINED:
return "UNDEFINED";
case PP_INPUTEVENT_TYPE_MOUSEDOWN:
return "MOUSEDOWN";
case PP_INPUTEVENT_TYPE_MOUSEUP:
return "MOUSEUP";
case PP_INPUTEVENT_TYPE_MOUSEMOVE:
return "MOUSEMOVE";
case PP_INPUTEVENT_TYPE_MOUSEENTER:
return "MOUSEENTER";
case PP_INPUTEVENT_TYPE_MOUSELEAVE:
return "MOUSELEAVE";
case PP_INPUTEVENT_TYPE_WHEEL:
return "WHEEL";
case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
return "RAWKEYDOWN";
case PP_INPUTEVENT_TYPE_KEYDOWN:
return "KEYDOWN";
case PP_INPUTEVENT_TYPE_KEYUP:
return "KEYUP";
case PP_INPUTEVENT_TYPE_CHAR:
return "CHAR";
case PP_INPUTEVENT_TYPE_CONTEXTMENU:
return "CONTEXTMENU";
case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START:
return "IME_COMPOSITION_START";
case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE:
return "IME_COMPOSITION_UPDATE";
case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END:
return "IME_COMPOSITION_END";
case PP_INPUTEVENT_TYPE_IME_TEXT:
return "IME_TEXT";
case PP_INPUTEVENT_TYPE_TOUCHSTART:
return "TOUCHSTART";
case PP_INPUTEVENT_TYPE_TOUCHMOVE:
return "TOUCHMOVE";
case PP_INPUTEVENT_TYPE_TOUCHEND:
return "TOUCHEND";
case PP_INPUTEVENT_TYPE_TOUCHCANCEL:
return "TOUCHCANCEL";
default:
return "[UNRECOGNIZED]";
}
}
};
class KeyTesterModule : public pp::Module {
public:
KeyTesterModule() : pp::Module() {}
virtual ~KeyTesterModule() {}
virtual pp::Instance* CreateInstance(PP_Instance instance) {
return new KeyTesterInstance(instance);
}
};
} // namespace remoting
namespace pp {
Module* CreateModule() {
return new remoting::KeyTesterModule();
}
} // namespace pp
{
"program": {
"portable": {
"pnacl-translate": {
"url": "remoting_key_tester_newlib.pexe"
}
}
}
}
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