Skip to content

hla_controller.inc

IanM-Matrix1 edited this page Aug 29, 2020 · 2 revisions

Purpose: To provide a higher-level access to the keyboard and both joystick ports.

Note that if you #import this file, it will automatically #import the hla.inc file too.

Table of Contents

Statements provided by this library

The parameters shown for each command are either labels to structures in memory, or they are parameters used for lookup of internal data.

The structure names used are:

  • keyMatrix
  • keyState
  • keyStateList
  • keyStateData
  • joyState
The lookup parameters provided are:
  • keyName
Details of both the structures and the lookup parameters are provided later in this document.

General controller macros

create_keyMatrix()

Creates a keyMatrix structure that can be updated by the update_keyboard_matrix macro, and used by the update_keystate_list_from_matrix and update_keystate_from_matrix macros.

It provides an area for the current state of the keyboard to be stored.

update_keyboard_matrix(keyMatrix)

Update the keyMatrix area with a snapshot of the keyboard state.

initialize_keystate_list(keyStateData)

Set all values in a keyStateData structure to the state of unpressed keys.

initialize_keystate(keyState)

Set a single keyState to the state of unpressed.

update_keystate(keyState, keyName)

Reads the state of a single key directly from the keyboard into the keyState. Useful for a single-key lookup against the keyboard (such as 'Press SPACE to continue').

update_keystate_from_matrix(keyState, keyName, keyMatrix)

Reads the state of a single key from the keyMatrix into the keyState. Useful for optional single-key lookups against the keyboard snapshot (eg, maybe for a key that is only active if another key is already pressed, such as shift & F1).

update_keystate_list_from_matrix(keyStateList, keyStateData, keyMatrix)

Reads the state of a set of keys in the keyStateList from the keyMatrix and providing the results in the keyStateData structure. Useful for an update of many keyStates from the keyMatrix, such as using WASD and SPACE keyboard layouts for movement.

create_joyState()

Creates a joyState structure that can be updated by the update_joystick1_state or update_joystick2_state macros.

It provides an area for the current state of a joystick to be stored. Within a joyState structure are 5 keyState values used to hold the state of each direction, and of the fire button.

initialize_joystick_state(joyState)

Set all values in a joyState structure to the state of no directions selected, and no fire.

update_joystick1_state(joyState)

Update the joyState structure with the current data available in joystick port 1.

update_joystick2_state(joyState)

Update the joyState structure with the current data available in joystick port 2.

Structured tests

if_key_down(keyState)

This statement checks the high bit of the data referred to by the keyState label. If the bit is clear, then the key is currently in the down position.

The keyState is tested using the BIT instruction and checking the state of the negative flag.

if_key_up(keyState)

This statement checks the high bit of the data referred to by the keyState label. If the bit is set, then the key is currently in the up position.

The keyState is tested using the BIT instruction and checking the state of the negative flag.

if_key_pressed(keyState)

This statement checks to see if the key has just been pressed, ie that the previous state shows the key was up, but the current state shows the key is now down.

The keyState is tested using the BIT instruction and checking the state of both the negative flag and the overflow flag.

I class this as a one-shot state test as when updating the keyState it is not possible to have multple key_pressed states in a row.

if_key_not_pressed(keyState)

This statement checks to see if the key is NOT in the 'pressed' state.

The keyState is tested using the BIT instruction and checking the state of both the negative flag and the overflow flag.

if_key_released(keyState)

This statement checks to see if the key has just been released, ie that the previous state shows the key was down, but the current state shows the key is now u[].

The keyState is tested using the BIT instruction and checking the state of both the negative flag and the overflow flag.

I class this as a one-shot state test as when updating the keyState it is not possible to have multple key_pressed states in a row.

if_key_not_released(keyState)

This statement checks to see if the key is NOT in the 'released' state.

The keyState is tested using the BIT instruction and checking the state of both the negative flag and the overflow flag.

while_key_not_pressed(keyState)

This statement checks to see if the key is NOT in the 'pressed' state. If this is not the case, the statement will jump to the end of the loop.

The keyState is tested using the BIT instruction and checking the state of both the negative flag and the overflow flag.

loop_if_key_up(keyState)

This statement checks the high bit of the data referred to by the keyState label. If the bit is set, then the key is currently in the up position, and will emit a jump back to the top of the loop

The keyState is tested using the BIT instruction and checking the state of the negative flag.

loop_if_key_down(keyState)

This statement checks the high bit of the data referred to by the keyState label. If the bit is clear, then the key is currently in the down position, and will emit a jump back to the top of the loop

The keyState is tested using the BIT instruction and checking the state of the negative flag.

loop_if_key_not_pressed(keyState)

This statement checks to see if the key is NOT in the 'pressed' state, and if that is the case, will emit a branch back to the top of the loop.

The keyState is tested using the BIT instruction and checking the state of both the negative flag and the overflow flag.

Structures used by this library

keyMatrix

This is an area of 8 consecutive bytes that are used to take a snapshot of the keyboard state for later decoding.

The create_keyMatrix macro is available to create a data area of the correct size.

keyState

This is a single byte that is used to hold the last 8 settings of a key or for a joystick, all 4 directions and the fire button.

The most recent event is held in high bit, while the oldest is held in the low bit. This allows the last two events in the keyState to be tested using the BIT instruction without affecting the contents of any register.

A bit is set to 1 if the controller is inactive, or 0 if it is active, which mirrors the state from the IO ports.

keyStateList

This is a lo-hi list of row and column mask bytes used for querying the keyMatrix by the update_keystate_list macro. The 'row' is the offset within the keyMatrix, and the colMask is the bit mask for the key.

The list should be defined in the following way:

    keyStateList: {
        lo:
            .byte keyInfo(" ").row
            .byte keyInfo("W").row
            .byte keyInfo("A").row
            .byte keyInfo("S").row
            .byte keyInfo("D").row
        hi:
            .byte keyInfo(" ").colMask
            .byte keyInfo("W").colMask
            .byte keyInfo("A").colMask
            .byte keyInfo("S").colMask
            .byte keyInfo("D").colMask
        end:
        .errorif hi-lo != end-hi, "Number of hi and lo bytes does not match"
    }

There is no macro to create this structure, as a variable number of arguments would be required to build the structure, and KickAss doesn't support that for macros.

keyStateData

This is a list of keyState bytes that, if using a keyStateList, should be defined to have the same number of entries as the keyStateList.

One way to define this is as follows:

    keyStateData: {
        space:      .byte $ff
        w:          .byte $ff
        a:          .byte $ff
        s:          .byte $ff
        d:          .byte $ff
    }

You can include validation to ensure that the keyStateData structure size matches that if your keyStateList by including the following code immediately before the closing brace:

    end:
    .errorif keyStateData.end-keyStateData != keyStateList.hi-keyStateList.lo, "keyStateData size does not have the same number of keys as keyStateList"

There is no macro to create this structure, as a variable number of arguments would be required to build the structure, and KickAss doesn't support that for macros.

joyState

This is a set of 5 keyState bytes used to hold the current state of all 4 directions of the joystick and the fire button.

It can be defined in the following way:

    joyState: {
        up:     .byte $ff
        down:   .byte $ff
        left:   .byte $ff
        right:  .byte $ff
        fire:   .byte $ff
    }

The create_joyState macro is available to create a data area using this definition.

Lookup parameters

keyNames

Rather than use numbers to identify the keys on the keyboard, I elected to use strings to name those keys. The majory of the keys are single characters, but there are a few that are longer (eg "RUNSTOP"), and there are also some keys with multiple interchangeable names (eg " " and "SPACE are the same). All names should be in uppercase.

A list of the keyNames that are available can be found in the Controller keyNames wiki page.

What is not in this library

Potentially missing statements

  • loop_if_key_not_released(keyState)
  • while_key_not_released(keyState)
In addition, as each keyState can hold the last 8 states, it would also be possible to check:
  • If down, how many states it has been held down for.
  • If up, how many states it has been released for.
  • How many of the last 8 states has it been pressed or not.

Missing statements that I think are justified

The following are one-shot type events, and because of this I can see no reason to include them in the loop structured commands.

  • while_key_pressed
  • while_key_released
  • loop_if_key_pressed
  • loop_if_key_released
If you can think of a use for these, they can be simulated in the following way:
    // Simulate while_key_pressed(keyState)
    if_key_not_pressed(keyState)
        exit_loop
    endif