Home > Net >  Change event before it propagates to next listener?
Change event before it propagates to next listener?

Time:12-05

Is there a way change an event and let it propagate further with the change?

For example how can I "force" press shift when any key is pressed?

window.focus();

window.addEventListener("keypress", e =>
{
  //force shift key doesn't work
  e.shiftKey = true;
})

window.addEventListener("keypress", e =>
{
  console.log("shift", e.shiftKey);
});
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

(this is just an example, I'm looking for a general solution that would work with any type of event)

CodePudding user response:

Use strict mode to see why your code isn't working:

'use strict';
window.focus();

window.addEventListener("keypress", e =>
{
  //force shift key doesn't work
  e.shiftKey = true;
})

window.addEventListener("keypress", e =>
{
  console.log("shift", e.shiftKey);
});
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

The event that the browser passes to addEventListener (regardless of propagation status) can't have certain intrinsic properties changed, including shiftKey. While you could assign to a different non-reserved property of the event, a better approach I think would be to use a WeakMap that maps the event to the new propert(ies) you want.

'use strict';
const customPropertiesByEvent = new WeakMap();
window.focus();

window.addEventListener("keypress", e =>
{
  customPropertiesByEvent.set(e, { shift: true });
})

window.addEventListener("keypress", e =>
{
  console.log("shift", customPropertiesByEvent.get(e).shift);
});
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

You can't "change" a KeyboardEvent. It's read-only.

It took a while, but apparently it IS the same object that gets passed to all the event listeners.. I messed with the get properties of Event and KeyboardEvent and the edited event passes smoothly :D

window.focus();

function control(event){
  if(typeof event=='function'){event=event.prototype}
  let properties=Object.getOwnPropertyDescriptors(event)
  Object.keys(properties)
  .filter(key=>
    !Object.keys(properties[key]).includes('value')
  )
  .forEach(key=>{
    const original=properties[key].get
    var value=null, valueSet=false
    function set(something){
      value=something; valueSet=true
    }
    function get(){
      return valueSet?value:original.call(this)
    }
    properties[key]={...properties[key],get,set}
  })
  Object.defineProperties(event,properties)
}
//for any event class given to it, this function makes its prototype functions malleable
control(KeyboardEvent); control(Event)
//not all but A LOT of the prototypes including shiftKey fall under these 2 classes

//eventListener that I assume you control and add first
window.addEventListener("keypress", e =>
{
  e.shiftKey=true //your edit to the event
})

//event listener that might be in the environment that you didn't make
window.addEventListener("keypress", e =>
{
  console.log("shift", e.shiftKey);
});

console.log("press an unshifted letter in this area")
<iframe name="sif4" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related