Hello there.
While testing a routine designed to check multiple key presses, i made an interesting discovery.
I didn't find anything about it anywhere, wikiti included, so the least i can do is to share it here.
Still can't believe i found that in 2019...
I decided to call the behaviour i'm about to describe "passive monitoring", as opposed to "active monitoring".
Active monitoring refers to the way most of you already know about, which is the regular sending to port $01, allowing you to specify which group(s) you want to monitor when reading the port afterwards.
Except for the need to use a variable delay between writings & readings, the port does what you expect it to do.
If you're new to that, you might want to check
my old relic.
Passive monitoring is basically an alternate way to monitor groups, but you don't control it by writing to the port at all, instead, it is triggered by pressing specific keys.
Fortunately for you, i believe i understood how it works in its entirety.
I'm gonna first summarise how it works with just 1 sentence :
"When monitoring the group of a pressed key, you are also monitoring all other groups that have a key of the same bit pressed."
I know that sounds ugly, but i'm afraid that's the easiest way to describe it.
EDIT : Such "connections" aren't limited to 2 groups only, so with the proper pressed keys, you can actually monitor the entire keyboard, while actively monitoring only 1 group.
A visual representation might help to understand :
To be clear, in both scenarios, only group 4 was asked to be actively monitored, by sending %11101111 to the port beforehand.
In scenario A, group 4 is monitored and group 3 is ignored, as expected, so you would read %11111010 from the port.
But as soon as you press 1 (scenario B), group 3 gets instantly added to the list of monitored groups, so you would actually read %11110000 from the port, this time.
In short, having both 1 & 2 pressed together creates a bridge that "spreads" the monitoring from group 4 to group 3, because those 2 keys share the same key bit (1).
Fortunately, using bit checking|masking instead of the CP instruction helps us to filter potential trash keys in passively monitored groups.
However, there are some situations where such tricks simply don't work, depending on what you look for, see below.
A concrete example that shows how nasty passive monitoring can be :
Let's say you want to code a loop that waits until DOWN, LEFT, ENTER, and +, are all pressed together.
Despite the fact that those keys aren't in the same group, that's actually impossible, even by reading groups sequentially, thanks to passive monitoring.
But let's pretend that you can do it, to understand why you can't.
The most obvious algorithm would be something like :
1) Send group 0.
2) Read group 0, check DOWN & LEFT, repeat if not both pressed.
3) Send group 1.
4) Read group 1, check ENTER & +, go to 1) if not both pressed.
In this case, the problem isn't that the loop will never exit, but that it will once 3 of those keys are pressed, instead of all 4.
And there's absolutely nothing you can do to prevent it, it will behave like that no matter how you code it, and no matter in which order you press the keys.
For the sake of simplicity, let's say you press them in this order, to understand what happens :
DOWN : Nothing unusual. Reading group 0 would return %11111110, and reading group 1 would return %11111111.
DOWN+LEFT : Still nothing unusual. Reading group 0 would return %11111100, and reading group 1 would (still) return %11111111.
DOWN+LEFT+ENTER : The fun begins. No matter which group you asked the port to monitor, you will read both of them.
The unfortunate consequence is that when reaching step 4), you'll read %11111100, despite + was never pressed, but LEFT, which shares the same key bit, is.
Testing passive monitoring in known projects :
Pick any game, that allows you to move a unit diagonally using the arrow keys.
Now, press & hold DOWN,0,1.
If i'm right about all this, there is a decent chance that the unit will move south-west.