boppreh / keyboard

Hook and simulate global keyboard events on Windows and Linux.
MIT License
3.76k stars 433 forks source link

Scancodes returned by key_to_scan_codes are not unique #560

Closed Aran-Fey closed 2 years ago

Aran-Fey commented 2 years ago

According to key_to_scan_codes, some scan codes are apparently mapped to multiple different keys. Here are some examples I discovered on my Windows PC:

>>> keyboard.key_to_scan_codes('e')  # includes 18
(18, 37)
>>> keyboard.key_to_scan_codes('f')  # also includes 18?!
(33, 18)

>>> keyboard.key_to_scan_codes('num 5')
(6, 76)
>>> keyboard.key_to_scan_codes('%')
(6,)

Maybe I'm misunderstanding what scan codes are, but shouldn't each scan code belong to exactly one key?

boppreh commented 2 years ago

The reason is that the names don't map 1:1 to keys on the keyboard. The key labeled 5 is also labeled % and on my keyboard, and all three names, if passed to key_to_scan_codes, will return a list that contains the same scan code.

num 5 should probably not overlap with %, but this is a bug in the way the current version handles the numpad. I'm hoping to fix it in the next release.

Aran-Fey commented 2 years ago

I'll be honest, I realized I have no clue how scan codes work and I'm now more confused than before. I'll let you decide what to do with this issue, but I'd like to ask a question.

What I'm trying to do is figure out the scan code that will be produced when I press a certain key. For example, if I register a hook with keyboard.hook and then press E on my keyboard, what will be the value of event.scan_code? 18? 37? How can I figure that out ahead of time?

boppreh commented 2 years ago

Scan codes are supposed to map to each physical key on your keyboard. There are some weird exceptions, like numpad keys, and some special function keys, but for the main keys you have one scan code per physical key.

The key_to_scan_codes returns a sorted list, with the most important scan codes first. So if keyboard.key_to_scan_codes('e') returns (18, 37), then the scan code you'll get by pressing the e key is probably 18.

If you are doing it for just a few keys, you can also run python -m keyboard or import keyboard; keyboard.hook(print); keyboard.wait() and it'll print every key that you press. This will give you the scan code, with 100% accuracy.

Aran-Fey commented 2 years ago

Got it, thanks.

boppreh commented 2 years ago

I'm closing this issue, but feel free to open a new one if you still have questions.