Using the Keyboard

First of all, I want to thank Antonio Villena (https://antoniovillena.es/ ) for his help, knowledge, and patience with me for the information in this article.

I struggled with the next part, for some reason I was not able to resolve in my head on keyboard usage. I had to employ the knowledge of Antonio Villena in order to get this sorted out.

My main menu needed to have an additional option, I wanted the player to be able to press 5 during the main menu and retrieve the high score list.

Currently, that code looks like:

while (1)//main menu
{
    i= inp(0xf7fe) & 0x1f;
        
    if( i==0x1e )//press 1, select kempston joystick
    {
        Input = Joystick;
        //kempston joystick and zx interface 2, port 1
        break;
    }
    else if( i==0x1d )//press 2, select cursor joystick
    {
        Input = Cursors;
        //cursor joystick
        break;
    }
    else if( i==0x1b )//press 3, select keyboard control
    {
        Input = Keyboard;
        //QAOP space
        break;
    }
    else if( i==0x17 )//press 4 redefine keys
    {
        Redefine();
    }
}

The problem stems from not knowing what these hex addresses actually stand for, there are 6 hex numbers that I am seeing 0xf7fe, 0x1f, 0x1e, 0x1d, 0x1b and 0x17, What the Hex is going on here?

In my continuing conversation with him on how to do some programming items in the ZX Spectrum, I was trying out how to use an additional key to display the high score information. I knew that there was going to have to be some input from the payer to activate the function. The option I wanted seemed simple enough. I want the player to press 5 and display the high score option.

So the conversation turned to the menu option, he had worked out several types of codes for me on the main menu, but for some reason, I struggled to get them to work properly. Finally, I asked “What is the I== 0x17? Hex-wise does that represent a key?”

The answer came pretty quickly. F7FE represents a port, the port that controls keys 1 – 2 – 3 – 4 – 5. The Hex that is used with the F7FE are the bits that represent the actual key used, you only need the first 5 bits to find the key used. You have to think in Binary. You read a byte and perform an AND operation with 0x1f

So, the bit pattern is as follows.

  • F7FE with a mask of 00011111 which is 0x1f(in hex), if a 1 is pressed, you will get a 00011110 returned.
  • F7FE with a mask of 00011111 which is 0x1f(in hex), if a 2 is pressed, you will get a 00011101 returned.
  • F7FE with a mask of 00011111 which is 0x1f(in hex), if a 3 is pressed, you will get a 00011011 returned.
  • F7FE with a mask of 00011111 which is 0x1f(in hex), if a 4 is pressed, you will get a 00010111 returned.
  • F7FE with a mask of 00011111 which is 0x1f(in hex), if a 5 is pressed, you will get a 00001111 returned.

Antonio states that:

That’s 00011110 when 1 pressed
00011111 is the mask to filter the 5 lower bits of the port
Because in the higher bits there is other info like EAR port that can change
So when 1 is pressed the port is XXX11110, when X is unknown
This is the reason we apply the AND mask.

This is all documented in the ZX Spectrum Disassembly guide.

;   Using shift keys and a combination of modes the Spectrum 40-key keyboard
;   can be mapped to 256 input characters
; ---------------------------------------------------------------------------
;
;         0     1     2     3     4 -Bits-  4     3     2     1     0
; PORT                                                                    PORT
;
; F7FE  [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ]  |  [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 0 ]   EFFE
;  ^                                   |                                   v
; FBFE  [ Q ] [ W ] [ E ] [ R ] [ T ]  |  [ Y ] [ U ] [ I ] [ O ] [ P ]   DFFE
;  ^                                   |                                   v
; FDFE  [ A ] [ S ] [ D ] [ F ] [ G ]  |  [ H ] [ J ] [ K ] [ L ] [ ENT ] BFFE
;  ^                                   |                                   v
; FEFE  [SHI] [ Z ] [ X ] [ C ] [ V ]  |  [ B ] [ N ] [ M ] [sym] [ SPC ] 7FFE
;  ^     $27                                                 $18           v
; Start                                                                   End
;        00100111                                            00011000
;
; ---------------------------------------------------------------------------
;   The above map may help in reading.
;   The neat arrangement of ports means that the B register need only be
;   rotated left to work up the left hand side and then down the right
;   hand side of the keyboard. When the reset bit drops into the carry
;   then all 8 half-rows have been read. Shift is the first key to be
;   read. The lower six bits of the shifts are unambiguous.

This was grabbed from the site.

https://web.archive.org/web/20150501015411/http://www.wearmouth.demon.co.uk/zx82.htm

So, in order to solve my issue and have the user press 5 to retrieve the high scores, we have to look for bit 5 to register as 0 which translates to hex 0x0F.

That means that my code should look like this to add the press 5 option.

while (1)//main menu
{
    i= inp(0xf7fe) & 0x1f;

    if( i==0x1e )//press 1, select kempston joystick
    {
        Input = Joystick;
        //kempston joystick and zx interface 2, port 1
        break;
    }
    else if( i==0x1d )//press 2, select cursor joystick
    {
        Input = Cursors;
        //cursor joystick
        break;
    }
    else if( i==0x1b )//press 3, select keyboard control
    {
        Input = Keyboard;
        //QAOP space
        break;
    }
    else if( i==0x17 )//press 4 redefine keys
    {
        Redefine();
    }
    else if( i==0x0F )// press 5 for high score   0000 1111
    {
        clearScreen();
        printHighScores();
    }
}

The two functions, clearScreen() and printHighScores() I have yet to blog about, so that information is coming in the future, you can comment them out for now if you are actively programming.

Compile and Test and BINGO! Works like a champ.

Thanks, Antonio, I was stuck in the mire and you pulled me out from my programming dungeon I had found myself caught in.

Now, with that base logic, it’s time to get a little more involved with that code. Let’s concentrate on what will happen if we press the 5 key.

else if( i==0x0F )// press 5 for high score   0000 1111
{
    clearScreen();
    printHighScores();
 
    while (1)
    {
        PrintStr(pressSpace, 0x080B);
        i= inp(0x7ffe) & 0x1f;

        if( i==0x1e )//space pressed
            break;
    }
    Pause (100);
    clearScreen();
    Bitmap(0, 0);
    goto start;
}

So, what I am doing here is, the user presses the 5 key, we clear the screen and we then print the high scores. Next, I am entering an endless loop.

During the endless loop, I am doing a few things, I print a string that says, “Press Space. I then look at port 0X7FFE which is the row that includes the SPACE key. If the Bit 0x1e is registered as 0, the computer knows that the SPACE key has been pressed and we can then exit the loop.

Once out of the loop, we Pause for a short time and then run the ClearScreen function, we call up Bitmap (0,0) which is the main screen and then we use the infamous command GOTO start.

Goto Start is a label in the code, which resets all of our in-game variables and starts the main menu loop all over again.

So now, our complete main menu code now looks like this:

while (1)//main menu
{        
    i= inp(0xf7fe) & 0x1f;
    
    if( i==0x1e )//press 1, select kempston joystick
    {
        Input = Joystick;
        //kempston joystick and zx interface 2, port 1
        break;
    }
    else if( i==0x1d )//press 2, select cursor joystick
    {
        Input = Cursors;
        //cursor joystick
        break;
    }
    else if( i==0x1b )//press 3, select keyboard control
    {
        Input = Keyboard;
        //QAOP space
        break;
    }
    else if( i==0x17 )//press 4 redefine keys
    {
        Redefine();
    }
    else if( i==0x0F )// press 5 for high score   0000 1111
    {
        clearScreen();
        printHighScores();
        
        while (1)
        {
            PrintStr(pressSpace, 0x080B);
            i= inp(0x7ffe) & 0x1f;

        if( i==0x1e )//space pressed
            break;
        }
        Pause (100);
        clearScreen();
        Bitmap(0, 0);
        
        goto start;
    }
}

Seems simple enough, but I certainly choked on this bit of code. Thank you again, Antonio Villena, for helping me with this. Live long and prosper.

Advertisements

Author: andydansby

I'm a hobbyist coder working with the ZX Spectrum. Living in New York state near the Syracuse area. I grew up in Virgina. The first computer my parents bought for me was a Timex Sinclair 2068.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s