Alex Russell's Game Programming Tutorial using DX

Introduction . Chapter 1 . Chapter 2 . Chapter 3 . Chapter 4 . Chapter 5 . Chapter 6 . Chapter 7

Chapter 5

I/O

DX provides two types of I/O: polled and buffered. If you use polled i/o you ask DX what the current state of the i/o device is (for example is a certain key down) and it tells you, but it does not track the state of the i/o device between calls. So if a user quickly presses and releases a key 3 times, but your program is polling the program may only detect the last down key-press. Using buferred i/o all i/o 'events' are saved in a buffer and all current events are returned. In general polled is easier to program but can miss i/o events, while buffered i/o is slightly more difficult to use but no i/o events ever get missed.

DXSmith uses buffered i/o, and it takes the i/o from all devices and puts them in one 'event queue'. The general steps for using any i/o device are:

  • Create the device (mouse, keyboard, joystick)
  • Set the data format
  • Set the buffere size if using buffered i/o
  • Set the cooperation level
  • Acquire the device

DX does handles multiple joysticks, each gets its own index number. You can also ask for the devices 'capabilities', eg how many buttons does the mouse have, does the joystick have a throttle, etc... See the class CgsdxIO's i/o functions for detailed examples of setting up i/o for use.

Keyboard

DXSmith returns both keypresses and key releases. The raw scan code and the ascii value are both return for all key presses. ALT, CTRL, and other special keys/combinations can be detected. Note that most keyboard hardware only supports about 5 simultaneous keys being down.

Mouse

All buttons, the scroll wheel, etc... are supported. Note that DX returns raw mouse movements. Many mouse drivers accelerate the mouse pointer if it moves quickly, but DX does not return acceleration or other features - only the raw mouse movements. DXSmith converts these raw mouse moves to absolute screen cooridinates.

JoyStick

DX provides very complete joystick support. A large number of axis and buttons are supported. DXSmith support x,y,x, rudders, pov hats, and multiple buttons for joystickes. DXSmith also supports more than one joystick. DXSmith returns both the current state of the joystick, plus joy-events like 'joy stick moved to left', 'joy stick return to center'. These joy-events are useful for games that what to use the joystick as a digital device instead of an analog device.

Event Queue

DXSmith takes ALL i/o events (and GUI events if you use the GUI tools in GUILib) into one event queue that lists all user i/o to be processes since the last time the event queue was checked.

typedef union
    {
    gsdxKeyEvent_t key;
    gsdxMouseEvent_t mouse;
    gsdxJoystickEvent_t joy;
    gsdxGuiEvent_t gui;
    }
gsdxEvent_u;

// for the event queue
typedef struct gsdxEvent
    {
    UINT type;
    int x, y, z;

    gsdxEvent_u event;
    struct gsdxEvent *prev, *next;
    }
gsdxEvent_t;

Events are stored in a list of gsdxEvent_t structures. type tells the program if it is a mouse, keyboard, joystick or other event, x, y, z hold the most popular data, and event holds detailed information for the event.

The advantage of placing all events in one list is that you only need to code one event loop for all event types. If you need to add new event types you will find it quite simple using this setup.

This code demo's reading DXSmith events:

        if ( dx.InitIO() )
            {
            TRACE("initIO failed\n");
            dx.DrawText(font, 50, 230, RGB(255, 255,255), 0, "InitIO failed");
            dx.Flip();
            getch();
            }
        else
            {
            gsdxEvent_t event;
            gsdxJoystickState_t joyState;

            TRACE("init IO OK\n");
            dx.DrawText(font, 50, 230, RGB(255, 255,255), 0, "InitIO OK, press a key to test");
            dx.GetTextSize(font, "a", &size);
            sprintf(temp, "24 is font creation height, cy = %d", size.cy);
            dx.DrawText(font, 50, 255, RGB(255, 255,255), 0, temp);
            dx.Flip();
            getch();

            done=0;
            while ( !done )
                {
                dx.RectFill(NULL, 0);
                if ( dx.IsKeyDown(DIK_ESCAPE) ) // quit if ESC pressed
                    done=1;
                if ( dx.GetEvent(&event) ) // get the next event if one is ready
                    {
                    if ( event.type == GSDX_IO_TYPE_KEY ) // keyboard
                        {
                        sprintf(temp, "scan %d ascii %d %c %s CAP %s NUM %s SCROLL %s",
                            event.event.key.scanCode,
                            event.event.key.ascii,
                            event.event.key.ascii,
                            event.event.key.isDown ? "DOWN" : "UP",
                            dx.GetCapState() ? "ON" : "OFF",
                            dx.GetNumState() ? "ON" : "OFF",
                            dx.GetScrollState() ? "ON" : "OFF");
                        dx.DrawText(font, 50, 230, RGB(255, 255,255), 0, temp);
                        if ( event.event.key.scanCode == DIK_ESCAPE )
                            done=1;
                        }
                    else
                        {
                        if ( event.type == GSDX_IO_TYPE_MOUSE )
                            {
                            sprintf(temp, "mouse %04d:%04d wheel %04d",
                                event.x,
                                event.y,
                                event.z);
                            if ( event.event.mouse.sub_type == GSDX_IO_SUBTYPE_BUTTON_DOWN )
                                {
                                sprintf(temp2, " button down num %d\n", event.event.mouse.index);
                                strcat(temp, temp2);
                                }
                            else
                                {
                                if ( event.event.mouse.sub_type == GSDX_IO_SUBTYPE_BUTTON_UP )
                                    {
                                    sprintf(temp2, " button up num %d\n", event.event.mouse.index);
                                    strcat(temp, temp2);
                                    }
                                else
                                    strcat(temp, " mouse move");
                                }
                            dx.DrawText(font, 50, 250, RGB(255, 255,255), 0, temp);
                            }
                        else
                            {
                            if ( event.type == GSDX_IO_TYPE_JOYSTICK )
                                {
                                sprintf(temp, "JOY %05d %05d ", 
                                    event.x,
                                    event.y);
                                switch ( event.event.joy.sub_type )
                                    {
                                    case GSDX_IO_SUBTYPE_JOYSTICK_X:
                                        strcat(temp, "X ");
                                        break;
                                    case GSDX_IO_SUBTYPE_JOYSTICK_Y:
                                        strcat(temp, "Y ");
                                        break;
                                    case GSDX_IO_SUBTYPE_JOYSTICK_Z:
                                        strcat(temp, "Z ");
                                        break;
                                    case GSDX_IO_SUBTYPE_JOYSTICK_R:
                                        strcat(temp, "R ");
                                        break;
                                    case GSDX_IO_SUBTYPE_BUTTON_UP:
                                        strcat(temp, "B UP ");
                                        sprintf(temp2, "%02d ", event.event.joy.index);
                                        strcat(temp, temp2);
                                        break;
                                    case GSDX_IO_SUBTYPE_BUTTON_DOWN:
                                        strcat(temp, "B DN ");
                                        sprintf(temp2, "%02d ", event.event.joy.index);
                                        strcat(temp, temp2);
                                        break;
                                    case GSDX_IO_SUBTYPE_JOYSTICK_POV:
                                        strcat(temp, "POV ");
                                        break;
                                    }

                                switch ( event.event.joy.sub_sub_type )
                                    {
                                    case GSDX_IO_SUBTYPE_JOYSTICK_CENTRE:
                                        strcat(temp, "TO CENTRE      ");
                                        break;
                                    case GSDX_IO_SUBTYPE_JOYSTICK_LEFT:
                                        strcat(temp, "TO LEFT        ");
                                        break;
                                    case GSDX_IO_SUBTYPE_JOYSTICK_RIGHT:
                                        strcat(temp, "TO RIGHT       ");
                                        break;
                                    case GSDX_IO_SUBTYPE_JOYSTICK_UP:
                                        strcat(temp, "TO UP          ");
                                        break;
                                    case GSDX_IO_SUBTYPE_JOYSTICK_DOWN:
                                        strcat(temp, "TO DOWN        ");
                                        break;
                                    case GSDX_IO_SUBTYPE_JOYSTICK_DOWN_LEFT:
                                        strcat(temp, "TO DOWN  LEFT      ");
                                        break;
                                    case GSDX_IO_SUBTYPE_JOYSTICK_DOWN_RIGHT:
                                        strcat(temp, "TO DOWN  RIGHT      ");
                                        break;
                                    case GSDX_IO_SUBTYPE_JOYSTICK_UP_LEFT:
                                        strcat(temp, "TO UP  LEFT      ");
                                        break;
                                    case GSDX_IO_SUBTYPE_JOYSTICK_UP_RIGHT:
                                        strcat(temp, "TO UP  RIGHT      ");
                                        break;
                                    default:
                                        strcat(temp, "               ");
                                        break;
                                    }
                                dx.DrawText(font, 50, 250, RGB(255, 255,255), 0, temp);
                                }
                            else
                                dx.DrawText(font, 50, 230, RGB(255, 255,255), 0, "not KEY type >>>>");
                            }
                        }

                    }

                dx.GetJoystickState(&joyState);
                sprintf(temp, "x %05d y %05d z %05d pov %d %d %d %d Rudders x %05d y %05d z %05d",
                    joyState.x,
                    joyState.y,
                    joyState.z,
                    joyState.pov[0],
                    joyState.pov[1],
                    joyState.pov[2],
                    joyState.pov[3],
                    joyState.rx,
                    joyState.ry,
                    joyState.rz);
                t1=temp2;
                *t1='>';
                t1++;
                for ( mask=1,i=0; i < 10; i++, mask<<=1 )
                    {
                    TRACE("mask %d mask & button %d\n", mask, mask & joyState.buttons);
                    if ( (mask & joyState.buttons) )
                        *t1='*';
                    else
                        *t1=' ';
                    t1++;
                    }
                *t1='<';
                t1++;
                *t1=0;
                dx.DrawText(font, 50, 270, RGB(255, 255,255), 0, temp);
                dx.DrawText(font, 50, 290, RGB(255, 255,255), 0, temp2);

                if ( event.type == GSDX_IO_TYPE_JOYSTICK )
                    Sleep(1000);
                dx.Flip();
                }


            } // initIO ok


Introduction . Chapter 1 . Chapter 2 . Chapter 3 . Chapter 4 . Chapter 5 . Chapter 6 . Chapter 7

Copyright 2004 (c), Alex Russell, All rights reserved