2022-03-11 15:47:48 +01:00
|
|
|
const comboConfig = require('../config.json').combos;
|
|
|
|
const commandConfig = require('../config.json').commands;
|
2022-03-10 14:05:08 +01:00
|
|
|
|
2022-03-03 03:35:34 +01:00
|
|
|
const LINE_START = 'Event: time';
|
2022-02-15 04:33:19 +01:00
|
|
|
|
|
|
|
const ACTION_KEYUP = { id: 0, action: 'keyup' };
|
|
|
|
const ACTION_KEYDOWN = { id: 1, action: 'keydown' };
|
|
|
|
const ACTION_KEYHOLD = { id: 2, action: 'keyhold' };
|
|
|
|
|
|
|
|
class Keyfilter {
|
2022-03-11 15:47:48 +01:00
|
|
|
constructor(config) {
|
|
|
|
if (config === undefined || config.length === 0) {
|
2022-02-15 04:33:19 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.actions = new Map();
|
2022-03-11 15:47:48 +01:00
|
|
|
for (let index = 0; index < config.length; index++) {
|
|
|
|
this.setAction(config[index]);
|
2022-02-15 04:33:19 +01:00
|
|
|
}
|
2022-03-03 03:35:34 +01:00
|
|
|
this.currentCombo = undefined;
|
2022-02-15 04:33:19 +01:00
|
|
|
}
|
2022-03-11 15:47:48 +01:00
|
|
|
getCommand(command) {
|
|
|
|
if (command === undefined || commandConfig === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const result = commandConfig[command];
|
|
|
|
if (result === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
result.name = command;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
getActionType(type) {
|
|
|
|
let result = ACTION_KEYDOWN;
|
|
|
|
if (isNaN(type)) {
|
|
|
|
switch (type.toLowerCase()) {
|
|
|
|
case ACTION_KEYUP.action:
|
|
|
|
result = ACTION_KEYUP;
|
|
|
|
break;
|
|
|
|
case ACTION_KEYHOLD.action:
|
|
|
|
result = ACTION_KEYHOLD;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (type) {
|
|
|
|
case ACTION_KEYUP.id:
|
|
|
|
result = ACTION_KEYUP;
|
|
|
|
break;
|
|
|
|
case ACTION_KEYHOLD.id:
|
|
|
|
result = ACTION_KEYHOLD;
|
|
|
|
break;
|
|
|
|
}
|
2022-02-15 04:33:19 +01:00
|
|
|
}
|
2022-03-11 15:47:48 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
setAction(config) {
|
2022-03-10 17:06:44 +01:00
|
|
|
let key = config.key.toUpperCase();
|
|
|
|
if (config.combo !== undefined && config.combo.length > 0) {
|
|
|
|
const tmp = JSON.parse(JSON.stringify(config.combo));
|
|
|
|
tmp.unshift(config.key);
|
|
|
|
key = tmp.toString().toUpperCase();
|
|
|
|
}
|
|
|
|
this.actions.set(key,
|
2022-03-03 03:35:34 +01:00
|
|
|
{
|
2022-03-11 15:47:48 +01:00
|
|
|
type: this.getActionType(config.type),
|
2022-03-03 03:35:34 +01:00
|
|
|
event: config.event,
|
2022-03-11 15:47:48 +01:00
|
|
|
command: this.getCommand(config.command),
|
2022-03-03 03:35:34 +01:00
|
|
|
combo: config.combo,
|
|
|
|
delay: function () {
|
|
|
|
if (config.combo === undefined) {
|
|
|
|
return config.delay;
|
|
|
|
}
|
|
|
|
return config.delay || 1000;
|
|
|
|
}(),
|
|
|
|
}
|
|
|
|
);
|
2022-02-15 04:33:19 +01:00
|
|
|
}
|
|
|
|
filter(input) {
|
2022-03-03 03:35:34 +01:00
|
|
|
if (input === undefined || input.length === 0) {
|
2022-02-15 04:33:19 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
input = input.toString();
|
2022-03-10 12:29:41 +01:00
|
|
|
let lines = input.split("\n");
|
|
|
|
for (let index = 0; index < lines.length; index++) {
|
|
|
|
let line = lines[index];
|
2022-03-03 03:35:34 +01:00
|
|
|
if (line.length === 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!line.startsWith(LINE_START)) {
|
2022-02-15 04:33:19 +01:00
|
|
|
continue;
|
|
|
|
}
|
2022-03-03 03:35:34 +01:00
|
|
|
const parsedEvent = this.parseLine(line);
|
|
|
|
if (parsedEvent === undefined) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-03-10 12:29:41 +01:00
|
|
|
for (let [key, event] of this.actions) {
|
2022-03-03 03:35:34 +01:00
|
|
|
if (this.currentCombo === undefined && !this.isParsedEventValid(key, event, parsedEvent)) {
|
2022-02-15 04:33:19 +01:00
|
|
|
continue;
|
|
|
|
}
|
2022-03-11 15:47:48 +01:00
|
|
|
if (this.isStartOfCombo(parsedEvent)) {
|
|
|
|
return this.setComboResult(this.getFilterResult(parsedEvent.key, parsedEvent.type.action));
|
2022-03-03 03:35:34 +01:00
|
|
|
}
|
|
|
|
if (this.isPartOfCombo(parsedEvent)) {
|
|
|
|
if (parsedEvent.ignore) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-03-11 15:47:48 +01:00
|
|
|
return this.setComboResult(this.getFilterResult(parsedEvent.key, parsedEvent.type.action));
|
2022-03-03 03:35:34 +01:00
|
|
|
}
|
|
|
|
if (!this.isParsedEventValid(key, event, parsedEvent)) {
|
2022-02-15 04:33:19 +01:00
|
|
|
continue;
|
|
|
|
}
|
2022-03-03 03:35:34 +01:00
|
|
|
if (this.shouldBeDelayed(event)) {
|
2022-03-11 15:47:48 +01:00
|
|
|
const result = this.getFilterResult(parsedEvent.key, event.type.action, event.command);
|
|
|
|
result.delayed = true;
|
|
|
|
return result;
|
2022-02-15 04:33:19 +01:00
|
|
|
}
|
2022-03-03 03:35:34 +01:00
|
|
|
event.captured = new Date().getTime();
|
2022-03-11 15:47:48 +01:00
|
|
|
return this.getFilterResult(parsedEvent.key, event.type.action, event.command);
|
2022-02-15 04:33:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-03-03 03:35:34 +01:00
|
|
|
isParsedEventValid(key, value, parsed) {
|
2022-03-10 17:06:44 +01:00
|
|
|
let keyCheck = key === parsed.key;
|
|
|
|
if (value.combo !== undefined && value.combo.length > 0) {
|
|
|
|
keyCheck = key.includes(parsed.key);
|
|
|
|
}
|
2022-03-11 15:47:48 +01:00
|
|
|
return keyCheck && (value.event === undefined || value.event === parsed.event) && value.type.id === parsed.type.id;
|
2022-03-03 03:35:34 +01:00
|
|
|
}
|
2022-03-11 15:47:48 +01:00
|
|
|
setComboResult(result) {
|
|
|
|
if (result === undefined || this.currentCombo === undefined) {
|
2022-03-03 03:35:34 +01:00
|
|
|
return;
|
|
|
|
}
|
2022-03-11 15:47:48 +01:00
|
|
|
if (!this.currentCombo.finished) {
|
|
|
|
result.combo = { possibilities: this.currentCombo.possibilities.length };
|
|
|
|
} else {
|
|
|
|
result.combo = {
|
|
|
|
finished: true,
|
|
|
|
done: this.currentCombo.done
|
|
|
|
};
|
|
|
|
result.command = this.currentCombo.command;
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
getFilterResult(key, type, command) {
|
|
|
|
if (key === undefined || type === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
return {
|
2022-03-10 17:06:44 +01:00
|
|
|
key: key,
|
2022-03-11 15:47:48 +01:00
|
|
|
type: type,
|
|
|
|
command: command
|
2022-03-10 17:06:44 +01:00
|
|
|
};
|
2022-03-03 03:35:34 +01:00
|
|
|
}
|
|
|
|
parseLine(line) {
|
|
|
|
try {
|
|
|
|
const parts = line.split(',');
|
|
|
|
const event = parts[1].substring(parts[1].indexOf('(') + 1, parts[1].lastIndexOf(')'));
|
|
|
|
const key = parts[2].substring(parts[2].indexOf('(') + 1, parts[2].indexOf(')'));
|
2022-03-11 15:47:48 +01:00
|
|
|
const type = this.getActionType(parseInt(parts[3].split(' ').pop()));
|
2022-03-03 03:35:34 +01:00
|
|
|
return { event: event, key: key, type: type };
|
|
|
|
} catch (err) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
shouldBeDelayed(event) {
|
|
|
|
if (event.delay === undefined || event.delay === 0 || event.captured === undefined) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return new Date().getTime() - event.captured < event.delay;
|
|
|
|
}
|
2022-03-11 15:47:48 +01:00
|
|
|
isStartOfCombo(parsedEvent) {
|
|
|
|
if (this.currentCombo !== undefined) {
|
2022-03-03 03:35:34 +01:00
|
|
|
return false;
|
|
|
|
}
|
2022-03-10 17:06:44 +01:00
|
|
|
let possibilities = [];
|
|
|
|
for (let [actionKey, actionEvent] of this.actions) {
|
|
|
|
if (actionEvent.combo === undefined || actionEvent.combo.length === 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!actionKey.toUpperCase().startsWith(parsedEvent.key)) {
|
2022-03-11 15:47:48 +01:00
|
|
|
continue;
|
2022-03-10 17:06:44 +01:00
|
|
|
}
|
2022-03-11 15:47:48 +01:00
|
|
|
possibilities.push(JSON.parse(JSON.stringify(actionEvent)));
|
|
|
|
}
|
|
|
|
if (possibilities.length === 0) {
|
|
|
|
return false;
|
2022-03-10 17:06:44 +01:00
|
|
|
}
|
2022-03-03 03:35:34 +01:00
|
|
|
this.currentCombo = {
|
2022-03-11 15:47:48 +01:00
|
|
|
key: parsedEvent.key.toUpperCase(),
|
2022-03-03 03:52:34 +01:00
|
|
|
timestamp: new Date().getTime(),
|
2022-03-11 15:47:48 +01:00
|
|
|
type: parsedEvent.type,
|
|
|
|
event: parsedEvent.event,
|
2022-03-10 17:06:44 +01:00
|
|
|
done: [parsedEvent.key],
|
2022-03-11 15:47:48 +01:00
|
|
|
possibilities: possibilities
|
2022-03-03 03:35:34 +01:00
|
|
|
};
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
isPartOfCombo(parsedEvent) {
|
|
|
|
if (this.hasComboTimedOut()) {
|
|
|
|
this.resetCurrentCombo();
|
|
|
|
}
|
2022-03-11 15:47:48 +01:00
|
|
|
if (this.currentCombo === undefined || this.currentCombo.type.id !== parsedEvent.type.id || this.currentCombo.event !== parsedEvent.event) {
|
2022-03-03 03:35:34 +01:00
|
|
|
return false;
|
|
|
|
}
|
2022-03-11 15:47:48 +01:00
|
|
|
// if (this.currentCombo.done.includes(parsedEvent.key)) {
|
|
|
|
// parsedEvent.ignore = true;
|
|
|
|
// return true;
|
|
|
|
// }
|
|
|
|
let possibilities = [];
|
2022-03-10 17:06:44 +01:00
|
|
|
for (let index = 0; index < this.currentCombo.possibilities.length; index++) {
|
|
|
|
const possibility = this.currentCombo.possibilities[index];
|
2022-03-11 15:47:48 +01:00
|
|
|
if (possibility.combo.length === 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (possibility.combo[0].toUpperCase() !== parsedEvent.key) {
|
2022-03-10 17:06:44 +01:00
|
|
|
continue;
|
|
|
|
}
|
2022-03-11 15:47:48 +01:00
|
|
|
possibility.combo.shift();
|
|
|
|
possibilities.push(possibility);
|
2022-03-10 17:06:44 +01:00
|
|
|
}
|
2022-03-11 15:47:48 +01:00
|
|
|
if (possibilities.length === 0) {
|
2022-03-03 03:35:34 +01:00
|
|
|
return false;
|
|
|
|
}
|
2022-03-03 03:52:34 +01:00
|
|
|
this.currentCombo.timestamp = new Date().getTime();
|
2022-03-03 03:35:34 +01:00
|
|
|
this.currentCombo.done.push(parsedEvent.key);
|
2022-03-11 15:47:48 +01:00
|
|
|
this.currentCombo.possibilities = possibilities;
|
|
|
|
this.currentCombo.finished = false;
|
|
|
|
if (this.currentCombo.possibilities.length === 1 && this.currentCombo.possibilities[0].combo.length === 0) {
|
|
|
|
const tmp = this.currentCombo.possibilities[0];
|
|
|
|
delete tmp.combo;
|
|
|
|
tmp.finished = true;
|
|
|
|
tmp.timestamp = this.currentCombo.timestamp;
|
|
|
|
tmp.done = this.currentCombo.done;
|
|
|
|
this.currentCombo = tmp;
|
2022-03-10 17:06:44 +01:00
|
|
|
}
|
2022-03-03 03:35:34 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
hasComboTimedOut() {
|
2022-03-10 17:06:44 +01:00
|
|
|
return false;
|
2022-03-11 15:47:48 +01:00
|
|
|
return comboConfig !== undefined &&
|
|
|
|
comboConfig.delay !== undefined &&
|
|
|
|
this.currentCombo !== undefined &&
|
2022-03-03 03:52:34 +01:00
|
|
|
this.currentCombo.timestamp !== undefined &&
|
2022-03-11 15:47:48 +01:00
|
|
|
new Date().getTime() - this.currentCombo.timestamp > comboConfig.delay;
|
2022-03-03 03:35:34 +01:00
|
|
|
}
|
|
|
|
resetCurrentCombo() {
|
|
|
|
this.currentCombo = undefined;
|
2022-02-15 04:33:19 +01:00
|
|
|
}
|
2022-02-16 02:08:21 +01:00
|
|
|
isValid() {
|
|
|
|
return this.actions != undefined && this.actions.size > 0;
|
|
|
|
}
|
2022-03-10 14:05:08 +01:00
|
|
|
|
2022-02-15 04:33:19 +01:00
|
|
|
}
|
|
|
|
|
2022-03-11 15:47:48 +01:00
|
|
|
|
2022-03-03 03:35:34 +01:00
|
|
|
|
|
|
|
|
2022-02-15 04:33:19 +01:00
|
|
|
module.exports = Keyfilter;
|