Just a quick update here. No hardware changes since last time, but I finally got around to putting in rudimentary ghost key rejection. What I tried was laughably simple: if there are more than two new keys being detected in a single scanning pass, ignore them both and send no updates, until the next change occurs. It doesn’t even check to see if they are in positions to cause ghosting — it just relies on the fact that ghost keypresses will always appear instantaneously with the last key, and for normal keypresses that’s very unlikely. Since making that change, it’s just perfect. No ghost keypresses, and no lost keys from what I’ve noticed.
One unfortunate effect from the current decoder/diode arrangement is that I can’t really set things up for this to go to sleep and be awaked by an interrupt when any key gets pressed. So I don’t have a great way for this to go into a very low-power mode, but I can at least try to optimize the regular power usage a little. Throughout all of the previous iterations, I had a 1ms delay following each scanning pass, but the passes were now happening much faster without the IO expanders. I tried doubling the loop delay to 2ms, and noticed no change in responsiveness, but greatly increased battery life. At some point I’ll probably put something in to increase that a lot (like 25ms or so) if there haven’t been any keys pressed in an hour or so, and that’ll presumably make another huge difference. But for right now everything’s great.
Oh, I should also put in some kind of support for volume/media control. That would be useful.