superqd
superqd

Reputation: 343

Sending keyboard and mouse events from one browser tab to another

So, I have web page that opens another page (browser tab) as a child to the first. The parent tab holds the code that performs the bulk of the application's work. The child tab holds a component that is normally embedded in the parent tab, but sometimes the user may want to open it in its own tab. So they can.

The problem is, the component in the child tab supports about 20 different keyboard commands and a number of mouse related commands (as combos with keyboard commands). I was trying to avoid remapping each keyboard command in the child window to a call in the parent window. Right now, in the parent window, I use a plugin to map and handle keyboard commands that all get sent to the right component API call.

What I want to do, is to just pipe keyboard and mouse events from the child window back to the parent, so that the regular handling of those events can proceed as normal. I don't want to have to setup specific handlers for every command all over again in the child window. Piping the key/mouse events feels more elegant, and would, ideally, take less code.

The first thing I tried, is this:

// CHILD WINDOW
window.document.addEventListener("keydown",  Redispatch, false);
function Redispatch(event){  
        window.opener.myRedirector.dispatchChildEvent(event);
 }

And in the parent window, it had this:

myRedirector.dispatchChildEvent = function(event){
    var r = dispatchEvent(e);
    console.log('dispatched event from child window');
}

In this case, nothing happens. The console.log() function in the parent window never fires, and stepping through it, the console.log() line never gets hit. The dispatchEvent(e) call behaves as though an error occurs, but nothing is thrown (this is the latest Chrome).

So I tried instantiating a new event in the parent like this (seen from another StackOverflow post):

myRedirector.dispatchChildEvent = function(e){
    var event  = document.createEvent('KeyboardEvent');
    var method = typeof event.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent";

    event[method](
        /* type         */ e.type,
        /* bubbles      */ true,
        /* cancelable   */ false,
        /* view         */ window,
        /* keyIdentifier*/ e.keyIdentifier,
        /* keyLocation  */ e.location,
        /* ctrlKey      */ e.ctrlKey,
        /* altKey       */ e.altKey,
        /* shiftKey     */ e.shiftKey,
        /* metaKey      */ e.metaKey,
        /* altGraphKey  */ false
  );
}

The problem here is that this doesn't initialize all the properties of the event, like keyCode and which. The keyboard handler plugin I am using doesn't read keyIdentifier, it uses keyCode. I can't manually set keyCode cause it's readonly on the object. I thought of changing the plugin to read the keyIdentifier, but that value isn't an integer, it's a Unicode string like "U+005", etc, and I don't want to remap all the keyCodes to those values in the plugin (though this may be Chrome specific).

So I also tried instantiating a CustomEvent, and just adding properties to it, which almost worked. Except CustomEvent has a type property that is set to empty string, and can't be overridden, so the plugin doesn't catch it since it's not of type 'keydown', etc.

I keep feeling like I'm missing something that should make this possible. That's why I've avoided other solutions like remapping values, or setting up all new handlers in the child window, etc.

It feels like it should be possible to just pipe keyboard/mouse events to a parent window. So far, though, I can't seem to find a way.

Any suggestions, or solutions?

Upvotes: 2

Views: 777

Answers (1)

superqd
superqd

Reputation: 343

So, I was using document.createEvent() and that was producing an event object with too many properties already added (that were read-only). So when I did this:

var event = new Event(childEvent.type);

This created an event of the right type, but with no keyCode or keyIdentifier, or other such properties, and I could just add them dynamically from the childEvent. Then, dispatching them worked fine.

Upvotes: 2

Related Questions