Translating keyboard input into the best form to send on.
Posted: Fri Jan 07, 2011 7:28 pm
There are a lot of things in my OS that are a bit of a mess (even though they work reliably) - in particular, the way I deal with keyboard input could be better designed, but it's possible that I might just be about to create a new mess which I'll only end up having to tidy up again later, so I thought I should describe what I'm thinking of doing and see if anyone has any suggestions to make.
The first stage is fine - the interrupt routine simply reads the 8042's data port and sticks whatever it finds into a buffer.
The next stage is done whenever the OS is asked to read the keyboard by whichever user interface is active at the time: it transfers what it finds in the buffer into a 12-byte array which can store information on up to six keys being held down at a time, three of those being shifts (shift/ctrl/alt), and the other three being any other keys. I designed this part of the system to make it easy to treat any key as a shift key so that whole words can potentially be entered by holding down any char key and then pressing another (which must be released first if it's to count, a reasonable delay between them being pressed determining that the second key was not pressed by accident). If the second char key is held down after the first is released, it counts as a separate char being input. This part of the system is efficient and works fine, so it will probably stay as it is.
The next part is the bit that needs to be tidied up. At the moment it translates everything into a form to send to apps (or for the OS itself to use), putting a code in al, either ASKII for a char key or a non-ASKII value for other kinds of key. Some values indicate that ah should be looked at as well because there aren't enough values to go round. The reason I'm not happy with this system is that every app has to filter out all the ASKII values every time by comparing with various values, and it's tiresome having to do this filtering every time. (I do have alternative routines for collecting input where the OS does the filtering in advance and only passes values of a certain type, but normally an app wants the whole lot.) I now plan to divide the codes being passed to the app into different groups with the code value held in ah rather than al so that al is kept free to indicate which group the code belongs to. The result of this is that an ASKII char can be filtered out with a single compare instead of having to do multiple comparisons with different values. A single compare would also be able to isolate the numbers, the letters or the other symbols, so the value in al might be 0 for numbers, 1 for letters and 2 for other kinds of symbol. The various cursor keys and other positioning keys could all be identified by a 4 in al, and the F1 to F12 keys by a 5 (the ah values in the latter case being the same as on those keys, plus 12 if shifted, plus 24 if ctrl, etc.). The value 6 in al could indicate a char shifted by a char (for whole word entry), the chars involved being in ah and the next free byte in eax. The value 7 could be used to pass information about shift keys being pressed, just in case an app cares. The values 3 and 13 would probably be used for Esc and Return, without any need to put them in ah. Unmakes can also be sent if 128 is added to the byte in al, even if no app bothers to do anything with them, but it makes sense to supply all the information that any app might want even if most aren't interest in half of it - they can respond to the ones they're interested in while ignoring the rest and without the process ever being messy.
So, what I'd like to know is, does this sound like a good way to do things or am I missing a trick or two? I'd like to know how other people have gone about this if they've done something different, particularly if some aspect of my design might make some kind of functionality which I haven't thought of harder. Ideally what I'd like to do is create or tie in with something that might become a common standard that many OSes could support (perhaps in addition to their existing way of doing things - it should be possible to switch the translation code to suit individual apps when their user interface is active so that they get input in the form they expect, after the OS has filtered out anything that might be intended for it directly, so a common standard needn't limit any OS that wants to use the keyboard in some exotic way which cannot be made compatible with that standard and which would itself limit the keyboard's potential functionality in some other way).
The first stage is fine - the interrupt routine simply reads the 8042's data port and sticks whatever it finds into a buffer.
The next stage is done whenever the OS is asked to read the keyboard by whichever user interface is active at the time: it transfers what it finds in the buffer into a 12-byte array which can store information on up to six keys being held down at a time, three of those being shifts (shift/ctrl/alt), and the other three being any other keys. I designed this part of the system to make it easy to treat any key as a shift key so that whole words can potentially be entered by holding down any char key and then pressing another (which must be released first if it's to count, a reasonable delay between them being pressed determining that the second key was not pressed by accident). If the second char key is held down after the first is released, it counts as a separate char being input. This part of the system is efficient and works fine, so it will probably stay as it is.
The next part is the bit that needs to be tidied up. At the moment it translates everything into a form to send to apps (or for the OS itself to use), putting a code in al, either ASKII for a char key or a non-ASKII value for other kinds of key. Some values indicate that ah should be looked at as well because there aren't enough values to go round. The reason I'm not happy with this system is that every app has to filter out all the ASKII values every time by comparing with various values, and it's tiresome having to do this filtering every time. (I do have alternative routines for collecting input where the OS does the filtering in advance and only passes values of a certain type, but normally an app wants the whole lot.) I now plan to divide the codes being passed to the app into different groups with the code value held in ah rather than al so that al is kept free to indicate which group the code belongs to. The result of this is that an ASKII char can be filtered out with a single compare instead of having to do multiple comparisons with different values. A single compare would also be able to isolate the numbers, the letters or the other symbols, so the value in al might be 0 for numbers, 1 for letters and 2 for other kinds of symbol. The various cursor keys and other positioning keys could all be identified by a 4 in al, and the F1 to F12 keys by a 5 (the ah values in the latter case being the same as on those keys, plus 12 if shifted, plus 24 if ctrl, etc.). The value 6 in al could indicate a char shifted by a char (for whole word entry), the chars involved being in ah and the next free byte in eax. The value 7 could be used to pass information about shift keys being pressed, just in case an app cares. The values 3 and 13 would probably be used for Esc and Return, without any need to put them in ah. Unmakes can also be sent if 128 is added to the byte in al, even if no app bothers to do anything with them, but it makes sense to supply all the information that any app might want even if most aren't interest in half of it - they can respond to the ones they're interested in while ignoring the rest and without the process ever being messy.
So, what I'd like to know is, does this sound like a good way to do things or am I missing a trick or two? I'd like to know how other people have gone about this if they've done something different, particularly if some aspect of my design might make some kind of functionality which I haven't thought of harder. Ideally what I'd like to do is create or tie in with something that might become a common standard that many OSes could support (perhaps in addition to their existing way of doing things - it should be possible to switch the translation code to suit individual apps when their user interface is active so that they get input in the form they expect, after the OS has filtered out anything that might be intended for it directly, so a common standard needn't limit any OS that wants to use the keyboard in some exotic way which cannot be made compatible with that standard and which would itself limit the keyboard's potential functionality in some other way).