KEY SUBstitute

Installs a TSR to make keys on your keyboard send a different code,
effectively becoming a different key.

use:  KEYSUB  with no arguments for command syntax.

Unlike most other key remapping tools, KEYSUB replaces the entire keycode
returned by INT 16h AH=0 with the code for the substituted key. This means
you can substitute keys with a different Shift/Ctrl/Alt state than the one
it is becomming.

Many other keymap tools remap only the scancode, which means Shift/Ctrl/Alt
has to be the same for the new key as the one it becomes, and it will remap
ALL of these states for a given key scancode.

I mainly created KEYSUB to handle running DosBox on android phones/tablets.
I've tried:  Turbo-DosBox, FreeBox, I-DosBox and Magic-DosBox(*)
all work quite well...  EXCEPT...

Working in DosBox on a phone/tablet can be painful.   The on-screen keyboard
either covers nearly 1/2 the DOS display, or you make the display so small it
gets difficult to read.  And rapid typeing on a touch screen is never great.
I prefer using a little physical Bluetooth keyboard which uses NO screen real
estate and has tactile feedback... but...

Phones/Tablets were never PC's, and most of the little Bluetooth keyboards
for them are missing MANY of the PC keyboard keys.  Things like Function keys,
PgUp/PgDn, Home/End, Ins/Del are in many cases not there at all.

Fortunatly several of my Bluetooth keyboards have suitable alternate key
functions. Eg: on a few, Alt-1 through Alt-0 are unique codes which would
make a good alternative to F1-F10.  And there are lots of CTRL or ALT keys
you could use for other missing keys as they do not often need to be typed.

DosBox has a built in keymap function, but do to it working only on SCANCODES,
you can only remap a non-Shift/Ctrl/Alt key to another non-Shift/Ctrl-Alt key..
there just aren't enough unused "normal" keys to get all the ones you want.

I CAN for example make Alt1 send the F1 scancode, but since I have to hold Alt
to enter it, DOS sees:  Alt-F1 - a valid DOS key and NOT the same as F1.

You might be able to define different/additional modifier keys, but that uses
more keys and I've not been able to make it work.

So... I created KEYSUB, this translates the complete keycode (scan+key codes)
return by BIOS which is independant of the state of Shift/Ctrl/Alt.  It's not
perfect as there are other ways to get scancodes.  But any program which gets
its console keys via INT 16h AH=0 (the most common and straightforward way)
should see the modified keys.

As this is how my Micro-C library keyboard related functions work, this works
well with all of my tools and utilities.

The .KEY files are simple text. Blank lines and those beginning with ';' are
ignored, remaining lines contain 2 4-character hex values. The first is the
keycode that is generated by a key, and the second is the new keycode to be
returned for that key.

Note1: This should work for any DOS program reading the keyboard via INT 16h
but DosBox itself reads the keyboard directly on the host, without activating
any TSR installed on the emulated INT 16h - this means your substituted
keycodes won't work on the DosBox command line.  As special keys are rarely
used here, this isn't much of a problem, and you can always bring up the on-
screen keyboard if you need to access a special DosBox function key  (which
may not even be supported in a tablet setup).

Note2: The TSR installed by KEYSUB is TINY - only 51 bytes of code + 4 bytes
for each key substituted. The size of the EXE header is also added to this,
nornally 256 bytes, but the smallest I have found to work (at least in MSDOS5
and DosBox is 64 bytes (this removes the argument buffer and a few "reserved"
bytes).

If KEYSUB doesn't work under your OS version, contact me and I can give you a
slightly bigger one with the full EXE header.

(*) To get a command prompt on Magic-DosBox, create a game definiton which
    points to: Z:\COMMAND.COM

To keep the TSR portion tiny, and also because it is normally "permanently"
installed, KEYSUB does not eat up any keys or contain code to "remove" itself.
The only reliable way to remove KEYSUB is to reboot and not install it.
See the -S and -W options if you plan to automatically install in AUTOEXEC.

Disable installed keysub with -D option. This DOES NOT remove it from memory!
Use -E to reEnable it.  Note: if you use keysub to edit the .KEY file, -E will
not switch to new definitions - to do this you must reload!

If you edit the key definitions while the TSR is installed and enabled, this
may affect the keys you enter. KEYSUB will warn you with "!TSR!" in the lower
left corner ... use: KEYSUB -D
to disable it first and don't forget to reload to get the updated keys.

Dave Dunfield   -   https://dunfield.themindfactory.com

Use of -Q and ERRORLEVEL in .BAT files:
---------------------------------------
You can use the -Quiet option, and knowing that KEYSUB sets ERRORLEVEL
if run with no .KEY file specified to indicate status, to enable KEYSUB
only during programs run from that .BAT file:
	@echo OFF
	keysub -q
	if errorlevel 12 goto ok
	if errorlevel 11 goto en
	keysub keys -tq
	goto ok
	:en
	keysub -eq
	:ok
	YourProg %1 %2 %3 %4 %5 ...
	...
	keysub -dq


Technical details:
------------------
The following information is provided in case you need to debug the keyboard
interface with KEYSUB, and is not normally needed.


When the PC was designed, it was given a "PC keyboard" which had standard
"letter" keys ('A-Z', '0-9' and symbols) which were defined in ASCII (American
Standard Code for Information Interchange) as well as a number of non-letter
keys which were unique to the PC (F1-F10, PgUp/PgDn, Home/End etc).

All these keys were handled by assigning each one a "Scancode".
This basically the position (row and column) of the key on early keyboards.

The PC had a bit of software in ROM called BIOS (Basic Input/Output System)
which knows how to deal with most of the standard PC hardware including
the keyboard. This was done using a hardware interrupt which would activate
BIOS every time a key was pressed... this would read the scancode and store it
in an internal buffer. This insured that no keys were "lost" if the system was
busy doing something else as keys were pressed.

The BIOS provided an interface for software via "software interrupt", an 8086
CPU feature which allowed one bit of sofware to call another without having to
know where it was located in memory.

There are two main ways to access the keyboard with BIOS:


INT 16h, AH=0 - Read a key

This waits until there is at least one entry in the PC's keyboard buffer, then
removes and returns the first scancode located there in AH. To make things
simpler the BIOS also translated scancodes for letter keys to ASCII which it
would return in AL.


INT 16h, AH=1 - Test for a key

This behaves like AH=0 except that if no entries are in the keyboard buffer
it returns a special code meaning no keys are available. It also DOES NOT
remove entries from the keyboard buffer.


When you call INT 16h, AH=1 to see if there is a key you do get the code for
any key which has been typed, however you then need to call INT 16h, AH=0 to
remove the scancode from the buffer.  Otherwise you would keep getting the
same key for subsequent tests.

In the interst of minimizing it's TSR size, KEYSUB only intercepts the
AH=0 function. It always has to be called anyway.

The simplest, most straightforward way to test for a key:

 INT 16h, AH=1		- Test for key pressed
 if no key was reported, return "NO KEY"
 INT 16h, AH=0		- Read and remove the key
 return with the keycode returned by AH=0

This is the way my compiler libraries to access the keyboard work when
testing for a key. It works with KEYSUB because the code returned is the
one read by INT 16h, AH=0

But... you could also test the keyboard in a less straigtforward way with a
bit more work... (and no doubt some programmers have done this):

 INT 16h, AH=1		- Test for key, read if pressed
 if no key was reported, return "NO KEY"
 Save the keycode returned by AH=1 in a temporary location
 INT 16h, AH=0		- Remove the key from keyboard buffer
 Retreive the previously saved AH=1 keycode
 return with the AH=1 keycode previousy saved.

KEYSUB does NOT work in this case, because it only activates on AH=0 and that
code gets "tossed away" by the above.


Other factors:
--------------
Back in the days of DOS, DOS itself used the BIOS INT 16h to read the keyboard.

But actual DOS is rarelly used these days. Modern systems provide DOS
capability by emulating DOS and BIOS. This includes 32-bit versions of
Windows as well as things like DOSBOX (Win64, Android, Mac etc).

Programs running under such emulation use INT 16h to access the keyboard and
KEYSUB works with those programs, however the DOS emulation itself tends to
read keys directly on the host, ignoring the emulated BIOS. This means that
KEYSUB does not work on DOS command line in various emulation packages.
