zephyrfalcon / LeafMachine5900

1 stars 1 forks source link

Proper keyboard handling #4

Open zephyrfalcon opened 3 years ago

zephyrfalcon commented 3 years ago

See: https://community.monogame.net/t/one-shot-key-press/11669/9 http://rbwhitaker.wikidot.com/basic-keyboard-input https://gamefromscratch.com/monogame-tutorial-handling-keyboard-mouse-and-gamepad-input/

zephyrfalcon commented 3 years ago

MonoGame's keyboard handling is atrocious. I suppose it works well from a purely hardware point of view, where keys are considered, well, keys, and so you can check which physical keys have been pressed, where things like Ctrl and Shift are treated the same as letters or Enter or any other keys.

Problem 1: Keyboard.GetState().IsKeyDown() has a ridiculous repeat rate, which probably stems from the fact that (when used in Update()) it's checked 60x per second, and so when you "just" press a key like usual, it will show up multiple times. This would make typing very hard, as letters etc will be repeated multiple times. One of the M4 demos uses the cursor keys, which works, but even if you don't hold the cursor keys, just pressing them will be treated as multiple keypresses, sending the cursor across the screen way faster than intended.

Problem 2: The links above "fix" this problem by keeping a "current state" and a "previous state" to detect repetition. This works for regular keys, but sometimes you want a key to repeat when you hold it, like in the case of the cursor keys mentioned above... and it's not handling that at all.

In a different (throw-away) repo, I am experimenting with my own keyboard handler, which allows for repetition. It uses three variables: when you press and hold a key, a wait time has to pass before it starts repeating (avoiding spurious repetitions for just a single key press); once it starts repeating, the repeat rate determines how soon the next key will appear; and when repetition is going on but you wait the cooldown time before pressing the same key again, it is no longer considered to be repeating, but instead it's treated like a "new" keypress.

Using this, I wrote a method HasKeyBeenPressed() (or something like that). This works... when you want to check if a particular key has been pressed, taking into account repetition etc.

Problem 3: But it does not work yet when you want to check if "any key" has been pressed and go from there.

Problem 4: Because MonoGame thinks Shift, Ctrl etc are keys like any other, they will be handled separately by IsKeyDown() and therefore HasKeyBeenPressed(). In other words, we have no way to check if, for example, Ctrl-A was pressed, or really anything that requires modifier keys, like the exclamation mark (Shift-1).

Problem 5: When we type, usually a certain character is produced. Which character, depends on the keyboard, international settings etc. But... MonoGame doesn't take that into account, at all. Which means that on a German keyboard, for example, I have no way to reliably produce "ä". In general, there is no way to reliably "translate" the keys that were pressed, to a character.

There might be more problems that I have no discovered yet. Wouldn't surprise me.

zephyrfalcon commented 3 years ago

Idea: Find a way to represent a key combination, consisting of a "real" key and any number of modifier keys. So maybe something like a struct with the actual key, then booleans indicating whether Shift is pressed, Ctrl, etc. (Maybe distinguishing between left and right versions of modifier keys.)

We would need to create such structs from... whatever the method is called that shows all keys being pressed at a given time. (Some sanitizing would be necessary here, since it allows, for example, for Q and W being pressed at the same time. We should really only accept one non-modifier key.)

We can then use such key structs in HasKeyBeenPressed() and whatever we use to determine whether "any" key has been pressed.

I'm not sure how well this would work, nor how we would represent such key combinations in Aphid. As lists of symbols? [ :#left-shift :#1 ]

zephyrfalcon commented 3 years ago

Another idea: Since the home computers of the 80s didn't have Unicode anyway, maybe neither should the Leaf be expected to. Which means we can provide a default "translation" for certain key combinations (Shift+1 => "!" etc). (We could, in theory, allow ways to have users set their own key combinations and translations. Might be useful even when not dealing with typing regular text.)

zephyrfalcon commented 3 years ago

Note: We should also remember to look at this "top-down", i.e. think of what we would want to check for, and how to write it in Aphid, and work from there.

key-pressed? { ... } when

Handling many different keys could maybe be handled by a dictionary. (We don't have those yet, that's another can of worms... but they would be useful in many situations.)

[ :#cursor-left { ... }
  :#cursor-right { ... }
  ...
] key-input-case

...or something like that...