mintz@hpindda.HP.COM (Ken Mintz) (07/27/88)
> Does anyone know of a Terminate and stay resident (TSR) program, or > device driver which could [swap the Control and Caps Lock keys]? I agree, and it's one of the first things I plan to do if/when I get my AT compatible. (It's been on order for a l-o-n-g time.) If anyone has s/w to do this, I'd appreciate a copy of the source. Email to the address below. But I would suggest a slightly different (re)mapping. Put Caps Lock up where Esc is ... or get rid of it altogether. Put Control where Caps Lock is. And put Esc where Control is. Pity to lose the right-hand Control key. But this is the best compromise I can come up with. Any other recommendations? Ken Mintz UUCP: hplabs!hpda!mintz ARPA: mintz%hpda@hplabs.hp.com
seeger@beach.cis.ufl.edu (Charles Seeger) (07/28/88)
I just got a Honeywell keyboard that remaps the cntrl and caps-lock via a dip-switch. Pretty nice for ~$75.00. They are *brand* new and may not be far along in distribution, yet. It's one of their "Silent-Tactile" line.
hedrick@athos.rutgers.edu (Charles Hedrick) (07/28/88)
I use the following program to make my AT keyboard work reasonably as a terminal. It turns caps lock into a control key. It puts caps lock where it belongs: on the back of the system unit. It also exchanges ESC and ~. You should find it easy to modify to do whatever other changes you want. It is for the Mark Williams assembler, which uses Unix syntax. I haven't yet figured out how to make the overblown Microsoft monster do what I want. I think some of the code is based on other PD stuff, which I should acknowledge but have lost the name of. / This program turns the caps lock key into a control key. It also / swaps the ` and ESC keys. It works / by patching the interrupt handler for interrupt 9 (keyboard) to / call hard_kybd_int in this program, and interrupt 16 (read char) / to call soft_kybd_int in this program. These routines call the real / interrupt routine, and hack on the results. / Presumably this program can be used at the same / time as other keyboard enhancers such as ProKey, but I wouldn't / want to bet very much on it. The cap lock hack seems to work all / the time. The ` ESC reversal doesn't work with micro-Gnu, though / it works with other Emacs. Presumably it fails only with software / that does hardware-level I/O. Fortunatley micro-Gnu has its own / way to redefine keys. (Probably other software that works at this / level does also.) / This program is written using "as" from Mark Williams C. This is / in effect a Unix assembler, rather than the usual Microsoft masm. / I apologize for this, but that happens to be the assembler I have... / The following labels refer to offsets in the interrupt area. / They must be used with a segment register that has 0 in it. kb_int=0x9*4 rd_int=0x16*4 / The following labels refer to offsets in the BIOS magic data area / starting at 0x400. They must be used with a segment register that / has 0x40 in it. equip_flag=0x10 kybd_flag=0x17 addr_6845=0x63 / The rest of the program is conventional. Note that we put our / local data into program segment. This is because we are using / ds to refer to the special areas defined above. .prvi / This assembler doesn't seem to have an END statement. The programs / always start at the beginning. So go to the place where we really / want to start. Note that the first part of the program is going / to be left around permanently to deal with interrupts. start: jmp initialize / Data needed for the permanent part. old_kyf: .byte 0x00 / This routine is our handler for interrupt 9. / This does the caps-lock to control mapping. hard_kybd_int: sti pushf / The following kludge is because this darned assembler can't assemble / call far except for a direct lable. / 9a is the op code for the inline form of call far. / I don't much like self-modifying code, but this was the safest form / to use under the circumstances. .byte 0x9a rom_key_int: .word 0,0 push ax / get some free registers push ds mov ax,$0x40 / we need 40 in ds to address the funny area mov ds,ax / There are two magic bytes involved here. Bit 40 in kybd_flag is the / flag used to control caps lock action. Bit 40 in kybd_flag+1 indicates / that the caps lock key is actually depressed. This can differ, because / some programs set caps lock for themselves by hacking on the bit in / kybdf_flag. Unfortunately, there is only one bit for the control keys. / So if somebody puts down both shift lock and control, we aren't going to / be able to keep track of exactly what is going on. movb al,kybd_flag+1 / 40 is caps lock down movb ah,al / save new val in ah, since xor will change it xorb al,cs:old_kyf / changes since last time testb al,$0x40 / has caps lock changed? jz nochange / no movb cs:old_kyf,ah / change - save new value movb al,kybd_flag / get status bits andb al,$0xbb / clear shift lock and control testb ah,$0x40 / but if caps lock went on jz wentoff orb al,$0x04 / then turn on control wentoff: movb kybd_flag,al / put in new flags nochange: pop ds pop ax iret / This routine is our handler for interrupt 16. / This does any other character mappings that may be desired. Note / however that software that works directly with interrupt 9, as / micro-Gnu seems to, will not see these mappings. Fortunately, / micro-Gnu has its own way to redefine keys, and I suspect other / software that works at that level will as well. soft_kybd_int: sti / The user program passes a request code. We only trap 0, which is / read char and 1, which is lookahead. orb ah,ah jz dochange cmpb ah,$1 je dochangex / This is a jump far to the original handler, for all codes that we / don't want to handle. .byte 0xea rom_rd_int2: .word 0,0 / Here for codes 0, read request dochange: pushf / Call the original read routine .byte 0x9a rom_rd_int: .word 0,0 / Now exchange ESC and ` mapit: cmpb al,$0140 je backqt cmpb al,$033 je esc doret: iret / The test above checks the character code that is about to be / returned. We also check ah, which contains the low-level hardware / code for the key that was pressed. This is done so that we map / the ESC key but not ^[ (which is also ESC). Note that we / supply new values for both al and ah, just in case any software / happens to be looking at the key rather than the character. backqt: cmpb ah,$0x29 jne doret movb al,$033 movb ah,$0x1 iret esc: cmpb ah,$0x1 jne doret movb al,$0140 movb ah,$0x29 iret / Here for code 1, lookahead dochangex: push bp mov bp,sp / Call original read routine pushf .byte 0x9a rom_rd_int3: .word 0,0 / This code returns the zero flag to say whether there is a char or not jz iszer / Have to pass the flag back to the caller. The caller's flags are / on the stack. push ax mov ax,6(bp) and ax,$0xffbf mov 6(bp),ax pop ax pop bp jmp mapit / Nothing there - pass zero flag up to the caller iszer: push ax mov ax,6(bp) or ax,$0x0040 mov 6(bp),ax pop ax pop bp iret / The following is the main program. It saves the old value of / the int 9 and int 16 handlers, and puts ours in instead. initialize: / hardware kb int movb ah,$53 / get interrupt vector movb al,$0x9 / for hardware int int 33 / call DOS mov cs:rom_key_int,bx / save old address:seg mov cs:rom_key_int+2,es mov dx,$hard_kybd_int / to our handler mov ax,cs / in our segment mov ds,ax movb ah,$37 / set interrupt vector movb al,$0x9 / for hardware int int 33 / software read ch int movb ah,$53 / get interrupt vector movb al,$0x16 / for hardware int int 33 / call DOS mov cs:rom_rd_int,bx / save old address:seg mov cs:rom_rd_int2,bx / need it 3 places mov cs:rom_rd_int3,bx mov cs:rom_rd_int+2,es mov cs:rom_rd_int2+2,es mov cs:rom_rd_int3+2,es mov dx,$soft_kybd_int / to our handler mov ax,cs / in our segment mov ds,ax movb ah,$37 / set interrupt vector movb al,$0x16 / for hardware int int 33 / Now we exit, telling the system to leave the code needed to do the / interrupt handling around. mov dx,$initialize int 0x27