        PAGE    60,132
NAME    Dvorak
        TITLE   Dvorak.com version 1.5

COMMENT û

Precis:

Dvorak.Com remaps your AT keyboard to the Dvorak layout.
It is a TSR that takes 288 bytes of RAM.  MASM source is
provided for you to create variants or so you can roll your own
TSRs to swap or rearrange selected keys in ways completely
unrelated to the Dvorak layout.

The code is well commented and serves as a teaching example on
keyboard TSRs.  Limitations: AT only, no XT.  Requires AT-style
INT 15 multiplex BIOS interrupt support.  No hot key
enable/disable.  No safety code to prevent loading twice.

Copyrighted, but may be freely copied for non-military use only.


This program may be freely copied and used for any purpose
except military.

Usage:

insert this command near the end of your autoexec.bat file:

Dvorak

It will translate your keyboard to Dvorak layout.  Note it only
works on AT computers.  XT computers require a more complex
method.

NOTE: There is no way to get rid of Dvorak except by rebooting.
There is no hot key to enable or disable it.  There are several
reasons for this:

1.  If you have modified your keyboard to DSK keycap layout, you
    could not type QWERTY on it anyway.  Thus there never any
    need to disable DVORAK.

2.  Leaving out Hot key support keeps the code very small -- under
    1K.

3.  If you really needed to disable it, you could use Mark/Release.

4.  I wanted this code to be a teaching example.  I did not want
    to have any more complications that necessary.


Please report bugs and problems to:

Roedy Green
Canadian Mind Products
#327 - 964 Heywood Avenue
Victoria, BC Canada V8V 2Y5
tel:(250) 361-9093
mailto:roedy@mindprod.com
http://mindprod.com

Version History
***************

Dvorak 1.0 was released to BIX on 1990 June 23

Dvorak 1.1 1990 June 27
- fix bug so that now the environment is released.  Missing INT 21h
- now close StdIn and StdOut so piping will not lose a handle.

Dvorak 1.2 1991 October 11
- just added comments about how the progam works

Dvorak 1.3 1993 June 8
- embed address and phone number
- more documentation on trouble shooting.

Version 1.4 1996 October 25
- embed POB 707 Quathiaski Cove address

version 1.5 1998 November 8
- embed Barker address

What Dvorak is for
******************

Dvorak lets you use a faster, saner keyboard layout. Also Dvorak
is a skeleton program to write your own compact keyboard
remapping routines.

The foreign language support routines that come with DOS take up
too much RAM.  There is no support for the Dvorak layout.

How Dvorak Works
****************

For the AT we leave a small TSR resident that intercepts the INT
15 4F keyboard remap interrupt that gets triggered by hardware
every time there is a keystroke event (down or up).

We translate the scan code to a different value.

The way XT BIOS is designed, there is no INT 15 4F, so this
program will not work.

A scan code comes through whenever a key is pressed, and again,
when it is released.  The scan code for release is the same as
the scan code for press, except it has the high bit on.


The Dvorak Layout
*****************

 Esc     F1  F2  F3  F4  F5  F6  F7  F8  F9  F10  F11  F12


~   !   @   #   $   %   ^   @   *   (   )   |   +   {  Bsp
`   1   2   3   4   5   6   7   8   9   0   \   =   [

  Tab  "   <   >   P   Y   F   G   C   R   L   ?   }
       '   ,   .   p   y   f   g   c   r   l   /   ]

CapsLock A   O   E   U   I   D   H   T   N   S  ___  Ent
         a   o   e   u   i   d   h   t   n   s   -

      Shf  :   Q   J   K   X   B   M   W   V   Z  Shf
           ;   q   j   k   x   b   m   w   v   z

Ctrl  Alt                  Space                     Alt   Ctrl


The original QWERTY Layout
**************************

 Esc     F1  F2  F3  F4  F5  F6  F7  F8  F9  F10  F11  F12


~   !   @   #   $   %   ^   @   *   (   )  ---  +   |  Bsp
`   1   2   3   4   5   6   7   8   9   0   -   =   \

  Tab  Q   W   E   R   T   Y   U   I   O   P   {   }
       q   w   e   r   t   y   u   i   o   p   [   ]

CapsLock A   S   D   F   G   H   J   K   L   :   "   Ent
         a   s   d   f   g   h   j   k   l   ;   '

      Shf  Z   X   C   V   B   N   M   <   >   ?  Shf
           z   x   c   v   b   n   m   ,   .   /

Ctrl  Alt                  Space                     Alt   Ctrl

Feel free to modify the translate table to better fit the
eccentricities of your keyboard.

How to Assemble
***************

to assemble with MASM 6.0 use:
ML.EXE /AT /c /Fl /Fm /Zf /Zm DVORAK.Asm
LINK.EXE /TINY /MAP DVORAK.Obj,DVORAK.com,DVORAK.map;

to assemble with OPTASM use:
Optasm   DVORAK.Asm,DVORAK.Obj,DVORAK.Lst/L/N/G/S
OLINK    DVORAK.Obj,DVORAK.COM,/MAP/TINY;

Extensions
**********

You can modify the translate tables to create arbitrary
keyswapping programs.  They may be as simple as swapping
CapsLock and Ctrl, or as complex as a left-handed Dvorak layout.

To do that all you need do is remove the list of CHANGE macros
defining a Dvorak layout and replace them with these two:

        CHANGE  _CapsLk,_Ctrl
        CHANGE  _Ctrl,_CapsLk

Dvorak is simple.  It cannot map a key differently in Ctrl or
Shift mode.  It cannot generate keystrokes not on the keyboard
such as accents.  If you want to do that see ESPAN which is more
complex version of Dvorak that lets you map the lower and upper
function of each key separately, create accents, dead keys,
ignored keys etc.

However you might not need the full power of ESPAN, so you might
just monitor E0 in the FIELD routines, to for example swap LEFT
ctrl with Capslock but leave RIGHT ctrl unmolested.  You would
have to dynamically modify the the translate table to map the
presses and releases.


end of comment û

CODE    SEGMENT PARA

        ASSUME  CS:CODE,DS:CODE
        ORG     100H

;==============================================================

; Configuration EQUATES


;==============================================================

;       Register Conventions
;
;       All subroutines are permitted to trash whatever registers
;       they like.  It is the caller's responsibility to save
;       and restore registers.  For speed, callers cheat and only
;       save registers they know the called program changes.
;       In a few cases, subroutines do save/restore some registers.

;==============================================================

SAY     MACRO   Msg
;;      display message on screen
        LEA     DX,&Msg         ;; use LEA rather than
                                ;; MOV Offset for more generality
        MOV     AH,09h          ;; some assemblers will optimise this.
        INT     21h
        ENDM

;==============================================================

CHANGE  MACRO   old,new
;;      build two bytes of the translate table
        ORG     TRT+(&old and 07Fh)     ;; translate downstroke
        DB      (&new AND 07Fh)         ;; high bit off
        ORG     TRT+(&old OR 080h)      ;; translate the release
        DB      (&new OR 080h)          ;; high bit on
        ENDM

;==============================================================

; MAINLINE PROGRAM

Dvorak   PROC    FAR
START:
        JMP     Init
                                ; Mainline disposable Init routine
                                ; uses TRAP to set up vectors to
                                ; FIELD which later
                                ; does the real work.

;==============================================================

; VARIABLES


RealInt15Off    DW      0       ; offset of original INT15 BIOS code
                                ; More likely will be pointer to
                                ; entry point of some other TSR
                                ; already hooked onto INT 15.
RealInt15Seg    DW      0       ; Seg of original INT15 BIOS code


;==============================================================

FIELD   Proc    Far
;       Field (intercept and handle) INT 15 Interrupt

        PUSHF
        CMP     AH,04Fh         ; is this function 4F?
        JNE     NotStroke       ; 4F is the peek at keystroke interrupt


IsStroke:
;   We translate the keystroke in AL
        PUSH    BX
        XOR     BH,BH
        MOV     BL,AL
        MOV     AL,CS:TRT[BX]
        POP     BX
;       Fall through to let other INT 15 AF handlers have a crack.

NotStroke:
                                ; We simply want to jump to
                                ; the original INT 15,
        POPF                    ; or give any other INT 15 AF handlers a bash
                                ; at the character as well.
        JMP     CS: DWORD PTR [RealInt15Off]
FIELD   EndP

;==============================================================

;       E Q U A T E S   F O R   S C A N   C O D E S   B Y   N A M E
;
;       We use SYSTEM scan codes, not keyboard scan codes.
;       INT 15 will see codes after the keyboard controller has
;       translated them.
;       Upper and lower case A use the same scan code as do 1 and ! for example.
;       When a key is duplicated on the numeric keypad and on the arrow
;       keypad, both use the same code, but the arrow keypad gets an E0 prefix.
;       This is a very simple minded translate program.  It does not look for
;       E0 characters.  It does the same translation for both the prefixed and
;       plain characters.
;       The E0 characters themselves get passed through unmolested.
;       The press down codes shown have the high bit off.  The release
;       codes are the same with the high bit on.

_ESC    EQU     01h     ; Esc
_1      EQU     02h     ; 1 !
_2      EQU     03h     ; 2 @
_3      EQU     04h     ; 3 #
_4      EQU     05h     ; 4 $
_5      EQU     06h     ; 5 %
_6      EQU     07h     ; 6 ^
_7      EQU     08h     ; 7 &
_8      EQU     09h     ; 8 *
_9      EQU     0Ah     ; 9 (
_0      EQU     0Bh     ; 0 )
_Minus  EQU     0Ch     ; - _
_Eq     EQU     0Dh     ; = +
_BS     EQU     0Eh     ; backspace <-
_Tab    EQU     0Fh     ; Tab ->
_Q      EQU     10h     ; Q
_W      EQU     11h     ; W
_E      EQU     12h     ; E
_R      EQU     13h     ; R
_T      EQU     14h     ; T
_Y      EQU     15h     ; Y
_U      EQU     16h     ; U
_I      EQU     17h     ; I
_O      EQU     18h     ; O
_P      EQU     19h     ; P
_LSq    EQU     1Ah     ; [ {
_RSq    EQU     1Bh     ; ] }
_Enter  EQU     1Ch     ; Enter
_Ctrl   EQU     1Dh     ; Ctrl (left or right)
_A      EQU     1Eh     ; A
_S      EQU     1Fh     ; S
_D      EQU     20h     ; D
_F      EQU     21h     ; F
_G      EQU     22h     ; G
_H      EQU     23h     ; H
_J      EQU     24h     ; J
_K      EQU     25h     ; K
_L      EQU     26h     ; L
_Semi   EQU     27h     ; ; :
_Quote  EQU     28h     ; ' "
_Grave  EQU     29h     ; ` ~
_LShift EQU     2Ah     ; Left Shift
_BSlash EQU     2Bh     ; \ |
_Z      EQU     2Ch     ; Z
_X      EQU     2Dh     ; X
_C      EQU     2Eh     ; C
_V      EQU     2Fh     ; V
_B      EQU     30h     ; B
_N      EQU     31h     ; N
_M      EQU     32h     ; M
_Comma  EQU     33h     ; , <
_Period EQU     34h     ; . >
_Slash  EQU     35h     ; / ?
_RShift EQU     36h     ; Right Shift
_PrtSc  EQU     37h     ; PrintScreen
_Alt    EQU     38h     ; left Alt, Right alt uses same code with E0 prefix
_Space  EQU     39h     ; Space
_CapsLk EQU     3Ah     ; CapsLock
_F1     EQU     3Bh     ; function key F1
_F2     EQU     3Ch     ; function key F2
_F3     EQU     3Dh     ; function key F3
_F4     EQU     3Eh     ; function key F4
_F5     EQU     3Fh     ; function key F5
_F6     EQU     40h     ; function key F6
_F7     EQU     41h     ; function key F7
_F8     EQU     42h     ; function key F8
_F9     EQU     43h     ; function key F9
_F10    EQU     44h     ; function key F10
_NumLk  EQU     45h     ; NumLock
_ScLk   EQU     46h     ; ScrollLock
_Home   EQU     47h     ; Home 7
_UP     EQU     48h     ; ^ arrow 8
_PgUp   EQU     49h     ; PgUp 9
_PadMin EQU     4Ah     ; Keypad minus
_Left   EQU     4Bh     ; <- 4
_Pad5   EQU     4Ch     ; 5 on keypad
_Right  EQU     4Dh     ; -> 6
_PadPls EQU     4Eh     ; Keypad plus
_End    EQU     4Fh     ; End 1
_Down   EQU     50h     ; v arrow 2
_PgDn   EQU     51h     ; PgDn 3
_Ins    EQU     52h     ; Ins 0
_Del    EQU     53h     ; Del .
_Sys    EQU     54h     ; SysRequest
_Less   EQU     56h     ; < > 
_F11    EQU     57h     ; function key 11 (not always present)
_F12    EQU     58h     ; function key 12 (not always present)
; pause button simultates a Ctrl-Numlock.
;
; You can use the PC PowerTools utility, SCAN, to find out what codes your
; keyboard is generating.  To stop SCAN, hit the space bar.
; You may have to adjust the above table slightly.
;
;==============================================================

;       The translate table, to handle BOTH press and release codes.

TRT     Label   Byte    ; build default translate table 256 bytes long
                        ; 0,1,2,3,4,5,6,7,8,...,254,255
                        ; so each byte gets translated to itself
                        ; so for example hex E0 gets left alone
                        ; Each press code with high bit off gets translated
                        ; to same code with the high bit off, and each
                        ; release code with the high bit on gets
                        ; translated to that same code with the
                        ; high bit on.
        Count = 0
        REPT    256d
        db      Count
        Count = Count + 1
        ENDM

;==============================================================

;  Insert your translations here!
;  They will override the default null translations.
;
;       CHANGE  FROM,TO
;               usual code, new code when you press that key
;               We are using SYSTEM SCAN CODES, NOT the ASCII codes!
;
; e.g.  To Swap Caplock and Ctrl:
;       CHANGE  _CapsLk,_Ctrl
;       CHANGE  _Ctrl,_CapsLk
;
;       All keys not mentioned will be left as is.
;
;  QWERTY `1234567890-=\        most of top row is left unchanged
;  Dvorak `1234567890\=[
;  QWERTZ ^1234567890áï
;  TypeII ^1234567890+<
                              ;_Grave remains unchanged
        CHANGE _Minus,_RSq     ;á -> +
        CHANGE _Eq,_Less        ;ï -> < ?Code for <>?

;  QWERTY  QWERTYUIEP[]
;  Dvorak  ',.PYFGCRL/]
;  QWERTZ  QWERTZUIOP+
;  TypeII  š,.PYFGCTZ?/

        CHANGE _Q,_LSq          ; Q -> š
        CHANGE _W,_Comma
        CHANGE _E,_Period
        CHANGE _R,_P
        CHANGE _T,_Z            ;T -> Y
        CHANGE _Y,_F
        CHANGE _U,_G
        CHANGE _I,_C
        CHANGE _O,_T
        CHANGE _P,_Y            ;P -> Z
        CHANGE _LSq,_Minus      ;leider ß ? nicht ? ß , ESPAN is needed
        CHANGE _RSq,_RSq        ; unchanged need also ESPAN cause there is no  / \

;  QWERTY  ASDFGHJKL;'
;  Dvorak  AOEUIDHTNS-
;  QWERTZ  ASDFGHJKLÖÄ#
;  TypeII  AOEIUHDRNSL-

        CHANGE _A,_A            ; unchanged
        CHANGE _S,_O
        CHANGE _D,_E
        CHANGE _F,_I            ; I und U sind vertauscht
        CHANGE _G,_U
        CHANGE _H,_H            ; H und D sind vertauscht
        CHANGE _J,_D
        CHANGE _K,_R
        CHANGE _L,_N
        CHANGE _Semi,_S
        CHANGE _Quote,_L        ;Ä -> L
        CHANGE _BSlash,_Slash   ;#' -> -_ ( ;\ -> -_)

;  QWERTY   ZXCVBNM,./
;  Dvorak   ;QJKXBMWVZ
;  QWERTZ  <YXCVBNM,.-
;  TypeII  Ž™QJKXBMWV#

        CHANGE _Less,_Quote    ; < -> Ž 
        CHANGE _Z,_Semi         ; unchanged y -> ™
        CHANGE _X,_Q
        CHANGE _C,_J
        CHANGE _V,_K
        CHANGE _B,_X
        CHANGE _N,_B
        CHANGE _M,_M            ; unchanged
        CHANGE _Comma,_W
        CHANGE _Period,_V
        CHANGE _Slash,_BSlash   ;- -> #


;==============================================================

        ORG     TRT+256d        ; get to the end

;==============================================================
;==============================================================
;==============================================================
;==============================================================
; Everything below this line is disposable initialization code.
; It is thrown away and is not part of the resident code.
;==============================================================
;==============================================================
;==============================================================
;==============================================================
;==============================================================
DISPOSE:
;==============================================================
Init    Proc    Near
;       Intialize Dvorak then Terminate and Stay Resident
        Say     CopyRightMsg    ; CopyRight banner
        CALL    Trap            ; redirect INT15 vector
        CALL    TSR             ; exit to DOS
Init    EndP

;==============================================================

TRAP    Proc    Near
;                               ; redirect the INT 15 to FIELD
;       Save real Int 15 vector
        MOV     AX,3515h        ; get vector for multiplex int 15
        INT     21H             ; vector in ES:BX
        MOV     RealInt15Seg,ES ; save real vector
        MOV     RealInt15Off,BX
;       Set up our Int 15 vector
                                ; DS:DX is vector.  DS ok already.
        MOV     DX,Offset Field
        MOV     AX,2515h        ; set vector for mulitplex int 15
        INT     21H             ; set vector from DS:DX
        RET
TRAP    EndP

;==============================================================

TSR     Proc    Near
;       Terminate and Stay Resident

        mov     ES,DS:[2Ch]     ; pointer to environment
        mov     ah,49h          ; free ram allocated to the SET enviroment
        INT     21h

        MOV     AH,3Eh          ; Close StdIn
        MOV     BX,0            ; Avoid holding onto a handle if
        INT     21H             ; foolish user typed Dvorak <Myfile

        MOV     AH,3Eh          ; Close StdOut
        MOV     BX,1            ; Avoid holding onto a handle if
        INT     21H             ; user typed Dvorak >NUL:

        MOV     AX,3100H        ; Terminate and Stay Resident function
                                ; Exit to DOS
        MOV     DX,((Dispose-Start)+100h+15d)/16d
        INT     21h             ; paragraphs to keep resident
                                ; 100h accounts for PSP.
                                ; 15d rounds up to next para.
                                ; We can throw away all
                                ; initialization code.
TSR     EndP

;==============================================================

;       Disposable Variables

;==============================================================

; Messages are all disposable, needed only during initialization.

CopyRightMsg    LABEL BYTE
        DB      '°±²Û Dvorak 1.5 Û²±°',13,10
        DB      13,10
        DB      'Translate QWERTZ keyboard to German Dvorak layout',13,10
        DB      13,10
        DB      'copyright (c) 1991-2003 Roedy Green, Canadian Mind Products',13,10
        DB      'Cristian Conitzer  M„rz 2003'
        DB      '#327 - 964 Heywood Avenue, Victoria, BC Canada V8V 2Y5',13,10
        DB      'tel:(250) 361-9093   mailto:roedy@mindprod.com   http://mindprod.com',13,10
        DB      'This program may be freely copied and used for any purpose except military.',13,10,'$'

;==============================================================

Dvorak  ENDP
CODE    ENDS
        END     START
