in_KeyPressed() for non-Sinclair targets?

Discussion about other targets
Post Reply
User avatar
RobertK
Well known member
Posts: 347
Joined: Mon Feb 26, 2018 12:58 pm

in_KeyPressed() for non-Sinclair targets?

Post by RobertK »

I am currently porting a ZX81 game I have written to some other Z80 systems, and I have basically solved all issues, except for this one:

My game has a two-player-mode where both players should be able to press a key simultaneously (the keys are always pressed briefly, but not held). On the ZX81 and the other Sinclair computers this can be achieved by using the in_KeyPressed() function, which returns the current state of a specific key.

For the other targets I have provisionally implemented standardized ANSI VT100 keyboard input with kbhit() and getch(), but this does not allow two buttons to be pressed simultaneously - the keypress of one player momentarily blocks the other player's keys.

Is there any equivalent for the in_KeyPressed() function, at least for some other targets? Or is there any workaround?

My game is basically finished for Jupiter Ace, Mattel Aquarius and Robotron Z1013, so any target-specific solution for these targets would be most interesting to me.
User avatar
dom
Well known member
Posts: 2090
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

I'm afraid there isn't. kbhit/getch go through getk() which normally calls the ROM so only picks up a single keypress.

We'd need to write alternate keyboard handlers for all the ports and there's not usually masses of information available on the ports and scancodes.

Having said that, I've just found: http://www.forums1.jupiter-ace.co.uk/pr ... dread.html for the Jupiter Ace which looks suspiciously Sinclair like and probably easy-ish to add as a result.
stefano
Well known member
Posts: 2144
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

this kind of problems is addressed with joystick() in games.h, but I'm afraid the current implementation on zx81 and J.ace is the generic one, which is a quick placeholder based on getk() :(

a way to test joystick() is to try snakes.c in examples/graphics. it is also a nice way to test the ym chip sound..
User avatar
RobertK
Well known member
Posts: 347
Joined: Mon Feb 26, 2018 12:58 pm

Post by RobertK »

Ok, that's a pity, I'll have to live with that.
dom wrote:Having said that, I've just found: http://www.forums1.jupiter-ace.co.uk/pr ... dread.html for the Jupiter Ace which looks suspiciously Sinclair like and probably easy-ish to add as a result.
It would be great if you could implement in_KeyPressed() for that system as well. The Jupiter Ace is such a great little machine, it would certainly deserve more software.
stefano wrote:a way to test joystick() is to try snakes.c in examples/graphics.
BTW, this is exactly the game I am working on (minus the AI opponent) :-)

Thanks for the info about games.h, I didn't know that yet and that's certainly useful, although it does not solve my problem.

A quick test shows that on the ZX81 it allows simulatenous key presses, while on the Jupiter Ace it does not, as expected.

Code: Select all

// joytest.c
// games.h joystick test (based on snakes.c)

// zcc +zx81 -create-app -startup=2 -o joytest_ZX81 joytest.c

// zcc +ace -vn -create-app joytest.c -o jt.bin
// load the game on the Jupiter Ace by typing
// 0 0 bload jt.bin

#include <games.h>
#include <stdio.h>

void main(void) {
        int joyType1;
        int joyType2;
        int joy1;
        int joy2;
        int x;

        printf("%c",12);                                         // clear the screen          
        
        printf("*** joystick test ***");

    printf("\n\njoystick 1:\n");

    for (x = 0; x != GAME_DEVICES; x++)
        printf("%u - %s\n", x + 1, joystick_type[x]);

    joyType1 = 0;
    while ((joyType1 < 1) || (joyType1 > GAME_DEVICES))
        joyType1 = getk() - 48;

    while (getk())
        ;

    printf("\n\njoystick 2:\n");

    for (x = 0; x != GAME_DEVICES; x++)
        printf("%u - %s\n", x + 1, joystick_type[x]);

    joyType2 = 0;
    while ((joyType2 < 1) || (joyType2 > GAME_DEVICES))
        joyType2 = getk() - 48;
                
        printf("\n\nwaiting for joystick input...\n");
        
        while(1)
        {
                joy1=joystick(joyType1);
                joy2=joystick(joyType2);
                printf("joy 1: %d, joy 2: %d\n",joy1,joy2);
        }        
}
User avatar
dom
Well known member
Posts: 2090
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

I've recently added in_Inkey() support for: Jupiter Ace, Casio PV-2000, Sega SC-3000 and the VZ machines. This is addition to the ZX Spectrum, ZX81 and X1 support that was already present.

To easily add support for more, getting hold of the keyboard matrix is essential, examples of what's needed can be found on issues: https://github.com/z88dk/z88dk/issues/7 ... -391503455 and https://github.com/z88dk/z88dk/issues/6 ... -313274380
User avatar
RobertK
Well known member
Posts: 347
Joined: Mon Feb 26, 2018 12:58 pm

Post by RobertK »

Thanks for these additions, I have successfully tested in_KeyPressed() on the Jupiter Ace and the VZ.

My joystick test program above now shows that both "joysticks" can be used simultaneously on the Jupiter Ace, that's great. On the VZ however, the result is not the best: you hear a beep every time you "move" the joystick, and there seems to be some sort of auto repeat function, so for example when you briefly press Q for "Up", you see the value 8 that joystick() correctly returned, but when you press and hold Q, this keyboard input is also displayed on the screen, so you see either Q8 or 8Q.

Another thing about the VZ is the "Visible Cursor Problem". I am not sure if Fabrizio's issue is really completely solved, and I doubt that it is at all connected to the keyboard input method used in the program. I have exactly the same problem in my program on the VZ, and it also occurs on every "nth" startup, but long before the program waits for any keyboard input. You notice that it's there when you see a blinking pixel on the startup screen. The 6x4 text output is rather slow, so it takes some time until the entire text is on the screen, but the blinking cursor is there right from the beginning. And as Fabrizio described it, when you reload the game program, the problem is usually gone (and if it isn't, you have to try reloading it again until it's gone).

Image
User avatar
dom
Well known member
Posts: 2090
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

There's definitely something causing problems in the VZ firmware - given that you've got these problems and you're not calling fgetc or you've redirected that routines to the inkey routines, then it may be the interrupt code that's causing trouble.

As an experiment it might be worth sticking in an asm("di") at the start of main to see if that clears things up.
User avatar
RobertK
Well known member
Posts: 347
Joined: Mon Feb 26, 2018 12:58 pm

Post by RobertK »

I have no idea what it does :), but I have now added

Code: Select all

#asm
di
#endasm
at the start of main(), and on ten attempts I couldn't reproduce the problem anymore!

I will keep on trying, but currently it looks as if this has solved the problem...
User avatar
dom
Well known member
Posts: 2090
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

Okay, it was just a hunch, but sadly has turned out to have an effect.

So the VZ is reading the keyboard and displaying the cursor during the interrupt. When it's definitely confirmed, I'll disable interrupts in the crt0 so you won't need that workaround.
User avatar
RobertK
Well known member
Posts: 347
Joined: Mon Feb 26, 2018 12:58 pm

Post by RobertK »

dom wrote:I've just committed VG5k support. I've updated the joystick() function to use the actual joysticks as well (https://github.com/z88dk/z88dk/issues/779)
Great! But should in_keypressed() already work with the current nightly build?
Here is a little test, on the VG5k the behaviour is not as expected...

Code: Select all

// Compile with
// zcc +zx81 -startup=2 -o inkeypressedtest_ZX81 -create-app inkeypressedtest.c
// zcc +vg5k -lm -o inkeypressedtest_vg5000 -create-app inkeypressedtest.c

#include <stdio.h>

void main()
{ 
  int exitLoop;
  printf("\ninkeypressed() test\n");
  printf("\npress x to exit\n");
  
  exitLoop=0;
  while(exitLoop==0)
  {
        printf("key s pressed: %d\n",in_KeyPressed(in_LookupKey('S')));
        if (in_KeyPressed(in_LookupKey('X'))) exitLoop=1;
  }
  
  return;
}
User avatar
dom
Well known member
Posts: 2090
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

I'll look into that, I've also added Exidy Sorcerer, Aquarius and TRS80/EG2000 support
User avatar
dom
Well known member
Posts: 2090
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

Sorry, I've fixed that now - I had the mask the wrong way so it was looking at the wrong bit of the keyboard port.

I had the same problem in the TRS80 code as well!
User avatar
RobertK
Well known member
Posts: 347
Joined: Mon Feb 26, 2018 12:58 pm

Post by RobertK »

Thanks for the latest additions. On VG5k, TRS-80 and EG2000 in_KeyPressed() works perfectly.

However, on the Aquarius there is the problem that two buttons cannot be pressed simultaneously. And if you press and hold one button and then press another, the first button (that you are still holding) gets "unpressed".

Is this a feature of this machine, or is this maybe a bug that can be fixed?

I have modified my little test program so that it checks the status of two buttons (s and d).

Code: Select all

// Compile with
// zcc +zx81 -startup=2 -o inkeypressedtest_ZX81 -create-app inkeypressedtest.c
// zcc +vg5k -lm -o inkeypressedtest_vg5000 -create-app inkeypressedtest.c
// zcc +aquarius -lm -o inkeypressedtest_aquarius -create-app inkeypressedtest.c

#include <stdio.h>

void main()
{ 
  int exitLoop;
  printf("%c",12); // clear the screen
  printf("\ninkeypressed() test\n");
  printf("\npress x to exit\n");
  
  exitLoop=0;
  while(exitLoop==0)
  {
        printf("key s / d pressed: %d / %d\n", in_KeyPressed(in_LookupKey('s')), in_KeyPressed(in_LookupKey('d')));
        if (in_KeyPressed(in_LookupKey('x'))) exitLoop=1;
  }
  
  printf("%c",12); // clear the screen 
  return;
}
User avatar
dom
Well known member
Posts: 2090
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

I'm wondering if it's an issue with the emulator (I presume you're using VirtualAquarius). I can't spot anything in the code that would lead to this behaviour.

I'm not sure how to load tapes into mame, but that's obviously a good sanity check, though looking at the code there I think multiple key presses are supported.
User avatar
dom
Well known member
Posts: 2090
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

Actually, I've just added ROM support for the aquarius (compile with -subtype=rom) so these should be loadable into Mame and multi keypresses tested.

I'm as usual struggling to find the machine ROMs to run but you might have more luck and be able to verify.
User avatar
RobertK
Well known member
Posts: 347
Joined: Mon Feb 26, 2018 12:58 pm

Post by RobertK »

Hmm, after loading the compiled ROM image into Aquarius or MAME, the screen shows nothing and you only hear frequent beeping sounds. Maybe the new ROM image generator is not working as it should.

BTW, there is another very old Aquarius emulator named "AqEmu", this one also supports ROM loading and shows the same result.
User avatar
dom
Well known member
Posts: 2090
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

I've adjusted some memory pointers so cartridges now load correctly. The start of RAM (used for variables) is now 0x3900 and REGISTER_SP=0x3fff REGISTER_SP can be adjusted with -pragma-define:REGISTER_SP=nnnn to support the different RAM configurations. Though I can't spot the option in mame to change the memory configuration.

Cartridges now load and run in both Mame and VirtualAquarius first time. The good news is that mame supports multiple keypresses!
User avatar
RobertK
Well known member
Posts: 347
Joined: Mon Feb 26, 2018 12:58 pm

Post by RobertK »

Thanks, that's good news. But how do I compile the program to get the cart running? So I have to add -pragma-define:REGISTER_SP=0x3fff, and also something to define the RAM start address?
User avatar
dom
Well known member
Posts: 2090
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

Sorry. Yes I missed this one.

You should?t need to tweak anything unless you?re targeting an expanded Aquarius cartridge.
User avatar
RobertK
Well known member
Posts: 347
Joined: Mon Feb 26, 2018 12:58 pm

Post by RobertK »

Hmm, the compiled cartridge runs on Virtual Aquarius, but in MAME it doesn't, I only get an empty screen and frequent beeping.
User avatar
dom
Well known member
Posts: 2090
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

Yes, on mame a default compile of plottest resets itself repeatedly.

My hunch is that we're calling a ROM routine but we've overwritten the memory so it ends up resetting. Using -pragma-redirect:fputc_cons=fputc_cons_generic means that we avoid calling the ROM and it successfully works.

If you can confirm I'll document it as a gotcha.
User avatar
RobertK
Well known member
Posts: 347
Joined: Mon Feb 26, 2018 12:58 pm

Post by RobertK »

With that parameter added the cartridge ROM file works both in MAME and in Virtual Aquarius, thanks.

And now I can also confirm that in MAME in_keypressed() works as expected, that means that two buttons can be presses simultaneously. So that keyboard problem is really a feature of the Virtual Aquarius emulator.
Post Reply