tomzx / gkm

⚠ Unsupported/Unmaintained ⚠️️ Global Keyboard and Mouse listener for node.js.
MIT License
52 stars 16 forks source link

`key.released` event doesn't always seem to fire when a key is released #21

Open Wizek opened 4 years ago

Wizek commented 4 years ago

This makes it look like certain keys are stuck and are always pressed.

This is especially bad if I want to respond to a key-combination like Alt+F1.

I can likely create a small repro case if this is not a known issue and is doubted, just let me know.

I also realized just now that maybe I can also create some kind of an abstraction to hide this issue, because genuine stuck/pressed keys repeatedly fire new key.pressed events, so if for about a second I don't get any of those, I can safely assume that its due to this bug and the key is in fact not pressed.

This can work, though of course it would be preferable that this is fixed somewhere upstream because this would introduce a noticeable lag on occasion when responding to a user releasing a key.


Somewhat off-topic, but I am also baffled by the lack of available and reliable global keyboard hooks for node.js. For a while I was using iohook, until I realised that it doesn't at all work when two apps require it at once. It makes Windows OS freeze. That's a pretty big deal-breaker.

Now, gkm, this package, seems to work much better, but like I say above, it's not fully reliable. And it also seems to not be actively maintained? And yeah, maybe I can smooth out these rough edges and live with this, but I am perplexed as to what people actually use if/when they want to respond in Node to a global keyboard shortcut. Do people just never want to do that? Do they use something I am not aware of?

Wizek commented 4 years ago

Attempting to work around the issue with this:

let pressMap = {}
let onKey = fn => {
  gkm.events.on('key.*', async function([key]) {
    if (this.event == "key.typed") return
    if (this.event == "key.pressed") {
      clearTimeout(pressMap[key])
      pressMap[key] = setTimeout(_ => {
        pressMap[key] = null
        // this.event = "key.released"
        // fn.call(this, [key])
        fn.call({event: "key.released"}, [key])
      }, 1000)
    }
    if (this.event == "key.released") {
      clearTimeout(pressMap[key])
    }
    fn.call(this, [key])
  })
}

And noticed a weird behavior: When I keep pressing alt, the alt event repeatedly fires; but when I then also start long pressing control, the repeated alt firing stops and repeated ctrl firing takes its place, even though alt is still pressed. This can be a problem if the user hesitates for a long time while pressing stuff.

As in, the above code works around the initial issue, but fails in the edge-case when the user is slower than 1s in a long key combination.

Though I might have an idea on how to overcome this issue too by treating repeated firings as a key group being pressed. Though that might also run a different risk of consecutive long-held combinations appearing as if being held together.

However, I also noticed a much more worrying problem: If multiple events coincide, some of them seem to be fully dropped! Even key.pressed events! In my logs I see stuff like:

pressed    alt
released   alt        
released   control

Note how according to gkm, control was never pressed, it's just released out of nowhere.