Hi Forum,
I wrote a whole post. I'm going to go ahead and share it, as a kind of tribute. Because I had my target audience in mind (you guys) while writing it I took some trouble to rewrite it a few times, and go back and double check what I was saying. While doing that, I looked at what I wrote about the key repeat sequence ($75, $75, $75) and thought "boy, things sure would be easier if it resent the '$E0' code every time instead of just at the beginning and the end. Then I thought "wait, does it actually do that? You just *wrote* that, you didn't actually check for sure." So I went to check it for sure. And Lo! It sends $E0 with every key-repeat! Hot dog. My cursor keys are now working with one extra flag bit and a few extra instructions in the "key release" routine. Plus, it's extensible if I want to add some other $E0 keys in the future (like CTRL and ALT) that I'm not currently using.
So... thanks for being you guys! Just being present in my imagination helped me clear up a problem without actually having to pester you.
At Ed's suggestion, here's what an extended key repeat sequence really sends:
Code:
$E0, $75,<$E0, $75, $E0, $75, $E0, $75...>,$E0, $F0, $75
^ ^ ^ ^ ^ ^
| | | | | |
| | | | | +-- scan code
| | | | +------- break code
| | | +------------ extended code
| | +--------------------------------------------- key repeat
| +-------------------------------------------------- scan code (make code)
+------------------------------------------------------- extended code
=-=-=-=-= ORIGINAL POST BELOW =-=-=-=-=
Ben Eater's keyboard driver isn't very good. Let's let him off the hook... his code is suppose to be a starting point to get people thinking and making their own better versions. I did that. For example, Ben's version does a lot of processing in the ISR; I didn't want that, so my ISR just grabs the scan-code from the keyboard and saves it in a buffer for later dispatching. I bet most other people also made this change - it's kind of low hanging fruit.
Another thing about Ben's version is the way it handles the SHIFT keys. It has a SHIFT flag. The handler routine for SHIFT sets the flag on make and clears it on break. At least, that's what you would think. Actually what it does is that it *flips* (eor) the flag on make *or* break. This would work fine if there was only one SHIFT key, but since there are two the make/break sequences can overlap and you can get weird effects. In my version there's a separate flag for each SHIFT so overlapping sequences don't interpret <RSHIFT DOWN>,<LSHIFT DOWN> as <SHIFT DOWN, SHIFT UP>.
I just got to the point in my code review that I want to add cursor / arrow key functionality. Here's how this works:
When you push a key, let's say numpad key scan-code $75, the PS2 keyboard sends a make code (that scan-code). If you hold the key down it will send it again (key repeat) until you let go the key. Then it will send a break code ($F0) followed by the scan code again. So a typical key-press is 3 bytes: $75, $F0, $75.
For some keys - the cursor keys in particular - the keyboard re-uses certain scan-codes and prepends them with a special "extended" code: $E0. The cursor keys are just the numpad key scancodes for '2,' '4,' '6,' and '8' sent following the E code. The thing is, on key release the keyboard sends the modifier code before it sends the break code. This seems backwards to me; the break code means "release what comes next," so shouldn't it be $F0 (release) $E0 (the extended) $75 (numpad key)? Anyway.
Code:
$E0, $75,<$75, $75, $75...>,$E0, $F0, $75
^ ^ ^ ^ ^ ^
| | | | | |
| | | | | +-- scan-code
| | | | +------- break
| | | +------------ extended
| | +------------------------------ key repeat
| +----------------------------------- scan-code
+---------------------------------------- modifier
You can probably see the difficulty. If you are pushing a lot of arrow keys, say, quickly navigating around a text screen (or playing a game... ha!) it's likely that key-presses will overlap with key-releases. So you will get, e.g.:
Code:
$E0, $75, $E0, $72, $E0, $F0, $75, $E0, $F0 $72
^ ^ ^ ^
| | | |
| | | +-- E OFF
| | +----------------- E ON
| +--------------------------- E OFF
+------------------------------------- E ON
For any particular $E0, there's no way to tell on the spot if it means "interpret the next scan code as extended" or "release the previously extended scancode."
I could set flag on the first $E0, then ignore all subsequent $E0s, until $E0 is cleared. Then have a separate "key-down" flag for each key that sends $E0, just like I do with SHIFTs. The key-release routine would check ALL of those flags, and only clear the $E0 flag once every extended key has been released. Of course, then there's a new problem to solve... what happens when a keypress that should never be extended [*] (say, numpad 8) but that shares a scancode with one that is extended overlaps with some extended keypress (say, cursor right)? You will get "right, up" instead of "right, 8." It's the opposite problem.
Another try that almost works is to clear the E flag every time you test it. That handles both kinds of overlapping key-presses, but it breaks key-repeat.
Thinking about the amount of code involved in handling just these 4 keys makes my morale sink. I can't help but wonder if there's a more elegant way to do this.
[*] Actually, numpad keys can be modified by num-lock, but let's save that for later!