Home Memoirs of a Gamer Movies I watched Guidebook Links

the Lobdegg's Comprehensive Guidebook to DOS Programming

Chapter 3 - Input

Section 4: Joystick Support

Updating Our Status

A Little Context

There's no 2 ways about it, the original PC Joystick protocol is a nightmare. It's computationally expensive, obtuse to implement, and obnoxious to read. It was the culmination of the IBM PC's root hardware design philosophy of "what's the cheapest way to implement this in hardware?" So how do we get analog axes from a joystick in a cheap fashion? Basically instead of a proper Analog to DC converter, it was decided to charge a set of capacitors (1 for each axis) and then signal the system to stop feeding said cap and loop through polling until the cap drained. Buttons were then fed directly through as binary inputs.

The Bare Minimum Update

Polling the Joystick Port
Assembly Borland Turbo C++ /
Open Watcom 16bit
Open Watcom 32bit
    xor ax, ax
    mov bx, 0x0F
    mov cx, 1
    mov dx, 0x201
    cli
    out dx, al
.startloop:
    in al, dx
    test al, 1
    jz .passed_axis1
    mov joy1_x, cx
    xor bx, 1
.passed_axis1:
    test al, 2
    jz .passed_axis2
    mov joy1_y, cx
    xor bx, 2
.passed_axis2:
    test al, 4
    jz .passed_axis3
    mov joy2_x, cx
    xor bx, 4
.passed_axis3:
    test al, 8
    jz .passed_axis4
    mov joy2_y, cx
    xor bx, 8
.passed_axis4:
    test bx, 0x0F
    jz .done
    inc cx
    cmp cx, 9999
    jl .startloop
.done:
    sti
    in al, dx
    shr al, 4
    mov joy1_b1, al
    and joy1_b1, 1
    shr al, 1
    mov joy1_b2, al
    and joy1_b2, 1
    shr al, 1
    mov joy2_b1, al
    and joy2_b1, 1
    shr al, 1
    mov joy2_b2, al
    and joy2_b2, 1
int i, j, mask=15;
disable();
outportb(0x201,0);
for (i=1; mask&&i<9999; i++) {
  j = inportb(0x201) ^ mask;
  if (j&1) { joy1.x = i; mask^=1; }
  if (j&2) { joy1.y = i; mask^=2; }
  if (j&4) { joy2.x = i; mask^=4; }
  if (j&8) { joy2.y = i; mask^=8; }
}
enable();
j = inportb(0x201) ^ 0xF0;
joy1.button1 = (j >> 4) & 1;
joy1.button2 = (j >> 5) & 1;
joy2.button1 = (j >> 6) & 1;
joy2.button2 = (j >> 7) & 1;
int i, j, mask=15;
_disable();
outp(0x201,0);
for (i=1; mask&&i<9999; i++) {
  j = inp(0x201) ^ mask;
  if (j&1) { joy1.x = i; mask^=1; }
  if (j&2) { joy1.y = i; mask^=2; }
  if (j&4) { joy2.x = i; mask^=4; }
  if (j&8) { joy2.y = i; mask^=8; }
}
_enable();
j = inportb(0x201) ^ 0xF0;
joy1.button1 = (j >> 4) & 1;
joy1.button2 = (j >> 5) & 1;
joy2.button1 = (j >> 6) & 1;
joy2.button2 = (j >> 7) & 1;

All of that to derive 4 unsigned shorts and 4 binary buttons. It's amazing anyone bothered at all.