blob: 17833eb7ea3784c42aab540508d396cacd315ef8 [file] [log] [blame]
import cobaltService from "./cobaltService.js";
// The unique ID needed for almost every webdriver command.
let sessionId = null;
// A container holding all the screens sending requests for frames.
let screenList = [];
// The number of screens requesting frames from Cobalt.
// This must be greater than 1, but can be optimized for performance.
// On flakey networks, more may be necessary.
// 3-4 are recommended for stable behavior on a reliable, fast network.
let numScreens = 4;
// The screen that is currently displayed to the user.
let visibleScreen = null;
// The current position of the mouse relative to the screens.
let mousePosition = {xPos: 0, yPos:0};
// The ID of cobalt's body element.
// Used to send mouse positioning instructions.
let bodyElementId = null;
// A cancelable event that sends mouse position to Cobalt.
let mouseInterval = null;
// The div that contains all the image frames.
let parentContainer = null;
window.onload = async function(){
await cobaltService.initialize();
// Create image tags with the appropriate css.
parentContainer = document.getElementById("screenContainer");
if (numScreens < 1) return;
for (let i = 0; i < numScreens; i++){
// Create an image and append it to DOM.
let newScreen = document.createElement("img");
newScreen.id = "screen" + i;
newScreen.classList.add("screen");
parentContainer.appendChild(newScreen);
screenList.push(newScreen);
}
// Grab a current session.
let sessions = await cobaltService.getSessions();
if(sessions.length > 0){
sessionId = sessions[0];
}
else{
// Create a new session if none are already created.
sessionId = await cobaltService.makeSession();
}
// Get Webdriver body element for mouse positioning.
bodyElementId = await cobaltService.getElement(sessionId);
cobaltService.startScreencast(sessionId).then((response) => {
cobaltService.setScreencastPort(response);
subscribeToMouseEvents();
window.addEventListener("keydown", sendKeyPress);
window.addEventListener("beforeunload", function(e){
cobaltService.stopScreencast(sessionId);
cobaltService.deleteSession(sessionId);
}, false);
// Start requesting screenshots.
for (let i = 0; i < screenList.length; i++) {
assignScreenshotURLAndId(screenList[i]);
// No screenshots are currently displayed.
screenList[i].currentImageId = -1;
visibleScreen = screenList[0];
}
});
// Assign image behavior.
for (let i = 0; i < screenList.length; i++) {
screenList[i].onload = () => { imageLoaded(screenList[i]) };
// Reload on error.
// TODO - differentiate between types of errors.
screenList[i].onerror = () => { assignScreenshotURLAndId(screenList[i]) };
}
}
function assignScreenshotURLAndId(screen){
let nextImageId = cobaltService.createNextScreenshotId();
screen.nextImageId = nextImageId;
screen.src = cobaltService.getScreenshotURL() + nextImageId;
}
function imageLoaded(screen){
// The image will only become visible if it's more recent than the last image.
if(screen.nextImageId > visibleScreen.currentImageId){
visibleScreen.classList.remove("visibleScreen");
screen.classList.add("visibleScreen");
visibleScreen = screen;
}
screen.currentImageId = screen.nextImageId;
assignScreenshotURLAndId(screen);
}
function sendClick(event){
let data = {
button: event.button
};
cobaltService.sendClick(sessionId, data);
}
function sendScroll(event){
// Prevent default browser action like scrolling on mouseKey.
event.preventDefault();
}
function saveMousePos(event){
mousePosition = {
xPos: event.clientX,
yPos: event.clientY
};
}
// Requests that get stalled send outdated mouse positions,
// so only send one at a time. This will help ensure no mouse
// movements are delayed.
var mouseLock = false;
function sendMousePos(){
if (mouseLock) return;
let viewportOffset = parentContainer.getBoundingClientRect();
let data = {
element: bodyElementId,
xoffset: mousePosition.xPos - viewportOffset.left,
yoffset: mousePosition.yPos - viewportOffset.top
};
mouseLock = true;
cobaltService.sendMouseMove(sessionId, data)
.then((response) => {
mouseLock = false;
});
}
function subscribeToMouseEvents(){
window.addEventListener('mousemove', saveMousePos);
window.addEventListener('click', sendClick);
window.addEventListener('scroll', sendScroll);
mouseInterval = setInterval(sendMousePos, 200);
}
if (typeof KeyEvent === 'undefined') {
var KeyEvent = {
DOM_VK_CANCEL: 3,
DOM_VK_HELP: 6,
DOM_VK_BACK_SPACE: 8,
DOM_VK_TAB: 9,
DOM_VK_CLEAR: 12,
DOM_VK_RETURN: 13,
DOM_VK_ENTER: 14,
DOM_VK_SHIFT: 16,
DOM_VK_CONTROL: 17,
DOM_VK_ALT: 18,
DOM_VK_PAUSE: 19,
DOM_VK_CAPS_LOCK: 20,
DOM_VK_ESCAPE: 27,
DOM_VK_SPACE: 32,
DOM_VK_PAGE_UP: 33,
DOM_VK_PAGE_DOWN: 34,
DOM_VK_END: 35,
DOM_VK_HOME: 36,
DOM_VK_LEFT: 37,
DOM_VK_UP: 38,
DOM_VK_RIGHT: 39,
DOM_VK_DOWN: 40,
DOM_VK_PRINTSCREEN: 44,
DOM_VK_INSERT: 45,
DOM_VK_DELETE: 46,
DOM_VK_0: 48,
DOM_VK_1: 49,
DOM_VK_2: 50,
DOM_VK_3: 51,
DOM_VK_4: 52,
DOM_VK_5: 53,
DOM_VK_6: 54,
DOM_VK_7: 55,
DOM_VK_8: 56,
DOM_VK_9: 57,
DOM_VK_SEMICOLON: 59,
DOM_VK_EQUALS: 61,
DOM_VK_A: 65,
DOM_VK_B: 66,
DOM_VK_C: 67,
DOM_VK_D: 68,
DOM_VK_E: 69,
DOM_VK_F: 70,
DOM_VK_G: 71,
DOM_VK_H: 72,
DOM_VK_I: 73,
DOM_VK_J: 74,
DOM_VK_K: 75,
DOM_VK_L: 76,
DOM_VK_M: 77,
DOM_VK_N: 78,
DOM_VK_O: 79,
DOM_VK_P: 80,
DOM_VK_Q: 81,
DOM_VK_R: 82,
DOM_VK_S: 83,
DOM_VK_T: 84,
DOM_VK_U: 85,
DOM_VK_V: 86,
DOM_VK_W: 87,
DOM_VK_X: 88,
DOM_VK_Y: 89,
DOM_VK_Z: 90,
DOM_VK_CONTEXT_MENU: 93,
DOM_VK_NUMPAD0: 96,
DOM_VK_NUMPAD1: 97,
DOM_VK_NUMPAD2: 98,
DOM_VK_NUMPAD3: 99,
DOM_VK_NUMPAD4: 100,
DOM_VK_NUMPAD5: 101,
DOM_VK_NUMPAD6: 102,
DOM_VK_NUMPAD7: 103,
DOM_VK_NUMPAD8: 104,
DOM_VK_NUMPAD9: 105,
DOM_VK_MULTIPLY: 106,
DOM_VK_ADD: 107,
DOM_VK_SEPARATOR: 108,
DOM_VK_SUBTRACT: 109,
DOM_VK_DECIMAL: 110,
DOM_VK_DIVIDE: 111,
DOM_VK_F1: 112,
DOM_VK_F2: 113,
DOM_VK_F3: 114,
DOM_VK_F4: 115,
DOM_VK_F5: 116,
DOM_VK_F6: 117,
DOM_VK_F7: 118,
DOM_VK_F8: 119,
DOM_VK_F9: 120,
DOM_VK_F10: 121,
DOM_VK_F11: 122,
DOM_VK_F12: 123,
DOM_VK_F13: 124,
DOM_VK_F14: 125,
DOM_VK_F15: 126,
DOM_VK_F16: 127,
DOM_VK_F17: 128,
DOM_VK_F18: 129,
DOM_VK_F19: 130,
DOM_VK_F20: 131,
DOM_VK_F21: 132,
DOM_VK_F22: 133,
DOM_VK_F23: 134,
DOM_VK_F24: 135,
DOM_VK_NUM_LOCK: 144,
DOM_VK_SCROLL_LOCK: 145,
DOM_VK_COMMA: 188,
DOM_VK_PERIOD: 190,
DOM_VK_SLASH: 191,
DOM_VK_BACK_QUOTE: 192,
DOM_VK_OPEN_BRACKET: 219,
DOM_VK_BACK_SLASH: 220,
DOM_VK_CLOSE_BRACKET: 221,
DOM_VK_QUOTE: 222,
DOM_VK_META: 224
};
}
function mapKeyCode(code){
// We want to optimize this for all printable characters ideally.
switch(code){
case KeyEvent.DOM_VK_UP:
return '\ue013';
case KeyEvent.DOM_VK_DOWN:
return '\ue015';
case KeyEvent.DOM_VK_LEFT:
return '\ue012';
case KeyEvent.DOM_VK_RIGHT:
return '\ue014';
case KeyEvent.DOM_VK_ENTER:
return '\ue007';
case KeyEvent.DOM_VK_RETURN:
return '\ue006';
case KeyEvent.DOM_VK_ESCAPE:
return '\ue00c';
case KeyEvent.DOM_VK_BACK_SPACE:
return '\ue003';
case KeyEvent.DOM_VK_SPACE:
return '\ue00d';
case KeyEvent.DOM_VK_SHIFT:
return '\ue008';
default:
return null;
}
}
function sendKeyPress(event){
// Prevent default browser action like scrolling on mouseKey.
event.preventDefault();
let uKeyCode = mapKeyCode(event.keyCode);
if(uKeyCode === null) uKeyCode = event.key;
cobaltService.sendKeystrokes(sessionId, [uKeyCode]);
}