Skip to content

Instantly share code, notes, and snippets.

@AlienKevin
Created April 9, 2019 21:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AlienKevin/78ce3fcda0f8e530a111e229802978a2 to your computer and use it in GitHub Desktop.
Save AlienKevin/78ce3fcda0f8e530a111e229802978a2 to your computer and use it in GitHub Desktop.
Add same event listener to multiple simultaneous events that are fired at about the same time.
function addSimultaneousEventListeners(eventNames, callback, options) {
const defaultOptions = {
inOrder: true, // the events should be fired in the order specified in eventNames array or not
tolerance: 500, // the tolerance time between the first and the last event in milliseconds,
// you can rarely fire two events at the exact moment
}
// merge default options with user options
const mergedOptions = {
...defaultOptions,
...options
};
const inOrder = mergedOptions.inOrder;
const tolerance = mergedOptions.tolerance;
eventNames = Object.freeze(eventNames); // make array immutable
let eventList = [];
eventNames.forEach((eventName) => {
document.addEventListener(eventName, listener);
})
function listener(e) {
eventList.push(e);
// trim eventList size
if (eventList.length > eventNames.length) {
eventList = eventList.slice(eventList.length - eventNames.length);
}
// console.log("eventList: " + eventList.reduce((string, event) => {
// return string + event.type + "@" + Math.round(event.timeStamp) + ", ";
// }, ""));
const eventStack = eventNames.slice(); // copy array
if (eventList.length === eventNames.length) {
const firstEvent = eventList[0];
for (let i = 0; i < eventList.length; i++) {
const currentEvent = eventList[i];
let currentEventName;
if (inOrder) {
currentEventName = eventNames[i];
} else {
const eventIndex = eventStack.indexOf(currentEvent.type);
if (eventIndex >= 0) {
currentEventName = currentEvent.type;
eventStack.splice(eventIndex, 1);
} else {
return; // not the right events fired
}
}
if (currentEvent.type !== currentEventName || !approximatelyEqual(firstEvent.timeStamp, currentEvent.timeStamp)) {
return; // not the right event type or both events are NOT fired at the same time
}
}
// eventList will be in order when inOrder is true
// otherwise it will be the order the user fired them
// you should always test for event types
callback(eventList);
}
}
// test if a and b are equal within the tolerance range
function approximatelyEqual(a, b) {
return (Math.abs(a - b) <= tolerance);
}
}
// Demo: detect keydown, click, and contextmenu fire at about the same time in that order
addSimultaneousEventListeners(["keydown", "click", "contextmenu"], // events registered
(eventList) => { // listener
console.log("you pressed a key, left clicked, and right clicked the document!");
console.log("eventList: ", eventList);
},
{ // options
inOrder: true
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment