Date: Wed, 14 Jan 1998 18:01:21 +0200 (IST) From: Eli Zaretskii To: Anthony DOT Appleyard AT umist DOT ac DOT uk cc: djgpp-workers AT delorie DOT com Subject: Re: MCLSSAA2 AT fs2 DOT mt DOT umist DOT ac DOT uk: Hooking interrupt 9 In-Reply-To: <27011525706@fs2.mt.umist.ac.uk> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Precedence: bulk On Wed, 14 Jan 1998, Anthony.Appleyard wrote: > + enum{ /* numbers of the keys */ > + k_esc = 1, > + k_1, Why are these needed on a system-wide header? As far as I could see, they aren't used anywhere in the code, right? already has definitions for all the PC keys, but they are the codes returned by the BIOS, not the scan codes. If you think these scan codes should be available system-wide, I suggest to add your definitions there, not to . > + cli /* disable interrupts */ I think this is both slow and unnecessary. Charles Sandmann agrees with that, so I think this line should go away. > + movw __go32_info_block+26,%ax > + movw %ax,%fs /* FS = _dos_ds */ > + .byte 0x64 /* use segment reg FS */ > + movw 0417,%ax /* [0x417] [0x418] are shift status */ I already asked why do you need to do this when the original handler code already loads the _dos_ds selector into DS, two lines after you call the callback code. Moving that line higher is all you need to do, no? > ================================================================== > Herewith a .TXH file for it, say call it djgppkbh.txh :- > ------------------------------------------------------------------ This needs more work in the markup. Below is a somewhat changed version which shows what you missed. Some noteworthy comments: 1) Function names, variable names, keywords and similar tokens should be written as @code{foo}. This produces `foo' in Info and is typeset in a typewriter face. 2) Parts that should not be reindented and refilled should be surrounded by @display DOT DOT DOT AT end display. Otherwise, the spacing of the words will be changed to fill text, which is not what you want. 3) Names of keys should use the @key{} markup. Names of parameters (such as the `keycode' parameter of this function) should use @var{}. File names should use @file{}. 4) If you want to make an ordered list, use @table or @itemize, see below. 5) Don't use double quotes; use `` and '' instead. These will be converted into double quotes in Info, but in the printed version they will produce the `` and '' glyphs as God intended. 6) You need to use @{ and @} in the examples where you need { and }, respectively, since the braces are special. 7) Make a good-faith effort to verify that your example works. This means, at the very least, to compile it with -Wall and see that it doesn't generate any warnings or errors. It is best to make sure that it actually works and doesn't crash. In this case, you haven't locked the code and the data, and it would surely crash, since it is called from within an interrupt handler. (Neither did you mention this in the description.) In my version below, I added some locking code, but I didn't test it. One thing which is definitely not right is that GCC assumes SS == DS, which is incorrect in the interrupt handler, so the callback code should take care of that also. I think that the example needs to be written in assembly, for all these reasons, lest people decide that it is all too easy to write it in C and end up scrogging their hard disks. I would also mention thesse considerations in the docs. Note that I have taken liberty to change some of your wording, especially where it made an impression that it is specific to ``my PC'' (who is ``me'', anyway?) ------------------------------------------------------------------- @node _djgpp_kbd_callback, misc @subheading Syntax @example #include extern int (*_djgpp_kbd_callback)(int keycode); @end example @subheading Description If @code{_djgpp_kbd_callback} is not zero, it is a pointer to a user-definable function which is automatically called whenever a keyboard event occurs such as a key being pressed or released. This is useful to let the program see the raw keyboard events. Note that the code and data of the callback needs to be locked, as it is called from within an interrupt handler. This function is called with a single parameter @var{keycode} which is constructed as follows: @table @code{} @item X & 255 the keyboard scan code. @item (X >> 8) & 255 keyboard shift status as if from function AH=2 of interrupt 16h. @item (X >> 16) & 255 keyboard extended shift status as if from function AH=12h of interrupt 16h. @end table If @code{_djgpp_kbd_callback} returns nonzero, that keyboard event is not passed on to DOS. This would let the user e.g. recognize and intercept @key{PrtScr} and use it for some purpose of his own instead of DOS handling it. @display bits of shift status bits of extended shift status 7 @key{Insert} active 7 @key{SysReq} key pressed 6 @key{CapsLock} active 6 @key{CapsLock} pressed 5 @key{NumLock} active 5 @key{NumLock} pressed 4 @key{ScrollLock} active 4 @key{ScrollLock} pressed 3 @key{Alt} key pressed 3 right @key{Alt} key pressed 2 @key{Ctrl} key pressed 2 right @key{Ctrl} key pressed 1 left @key{Shift} key pressed 1 left @key{Alt} key pressed 0 right @key{Shift} key pressed 0 left @key{Ctrl} key pressed @end display The current values of these two bytes are kept in conventional memory at linear addresses 0x417 and 0x418 respectively. Pressing a keyboard key generates a scan code between 0 and 127. The scan code for pressing a key is as listed in the header file @file{keys.h}; the code for releasing that key is 0x80 = 128 higher. The keys introduced with the extended 101-key keyboard, when pressed or released, produce two keyboard events, of which the first is 0xe0, and the second is the key's scan code (plus 128, 0x100, on release). @key{Numshift} is an imaginary key whose press and release codes are manufactured by the BIOS when the ``grey key'' are pressed. This allows to differentiate between the grey @key{Home} key and the @key{Home/7} key on the numeric pad. If @key{Numshift} is treated as an extra shift key, the effect is that those ``grey keys'' are shifted by the current @key{Numlock} state and not by the two real shift keys. Two keys are special in that they produce more than two-byte sequence when pressed or released: @itemize @bullet{} @item Pressing the @key{Pause/Break} key produces the sequence @code{e1 1d 45}, and releasing it produces @code{e1 9d c5}; i.e. @code{e1} followed by the codes for left @key{Ctrl} and @key{Numlock}, in that order. In the sequence, the @code{e1 1d} is the functioning part that causes the pausing or the break. @item Pressing @key{PrtScr/SysReq} key produces @code{e0 2a e0 37}; releasing it produces @code{e0 b7 e0 aa}. Due to wide differences between national keyboard layouts, the non-alphanumeric printing keys are called neutrally, e.g. @code{k_2rof0} means ``the key two to the right of 0'' (@key{=/+} on UK and USA keyboards). This refers to the layout on a desktop keyboard. Laptop keys tend to be somewhat differently arranged. @subheading Return Value This function is a callback, so it is up to the user what it returns. The return value should be 0 if you want the keyboard event to be processed as usual after you have processed it, otherwise 1. @subheading Example @example #include #include #include char print_wanted = 0; unsigned trap_prscr_size = ...; /* the size of the code in trap_prscr */ int trap_prscr(int X) @{ if((X&0xff) == 0x2a) /* if it is left shift or Prt Scr */ if(!((X>>8)&15)) /* not if shift or ctrl or alt */ if(_farpeekb(_dos_ds,0x496)&2) /* if it is next after 0xe0 event */ @{ /* then it is a Prt Scr */ print_wanted = 1; /* leave note to call my own printout routine */ return 1; /* no, I DON'T want DOS's method right now */ @} return 0; /* else default */ @} ...... int main() @{ __dpmi_meminfo lockmem; lockmem.address = __djgpp_base_address + (unsigned) &trap_prscr; lockmem.size = trap_prscr_size; __dpmi_lock_linear_region(&lockmem); lockmem.address = __djgpp_base_address + (unsigned) &print_wanted; lockmem.size = sizeof(print_wanted); __dpmi_lock_linear_region(&lockmem); _djgpp_kbd_callback = trap_prscr; ...... @} @end example