finalburnneo / FBNeo

FinalBurn Neo - We are Team FBNeo.
http://neo-source.com
Other
881 stars 355 forks source link

MSX games are missing keyboard input on Libretro build #1678

Closed vanfanel closed 4 months ago

vanfanel commented 4 months ago

Hi @dinkc64 (@barbudreadmon told me to ask you here)

I have noticed that MSX games on FBNeo (Libretro build) are missing keyboard input.

-I'm using latest stable FBNeo code on GNU/Linux, with latest stable RetroArch (1.17.0). -I have Settings->Input->Max Users set to 3, and in the core options, I have Port 3 Controls->Device Type set to keyboard, since that's what I had on my previous notes. -I have Settings->Auto Enable Game Focus Mode set to Detect, and no keyboard keys are mapped as RetroArch or Joystick keys.

With all that, MSX games supporting keyboard input (which are the vast majority) should obey to keyboard input, but they don't. For example, Knightmare or Penguin Adventure only respond to the SPACE key, all other keys are ignored (even arrow keys are ignored, and as I said they are not mapped to RetroArch).

Using the exact same configuration, full keyboard works with no problem on the dosbox-core core.

Do you know what could be happening?

barbudreadmon commented 4 months ago

@dinkc64 Setting aside all the libretro/retroarch vocabulary, msxKeyCallback is correctly detecting the keyboard presses, but they don't seem to affect those 2 games in any way (aside from the "space" key). Is it expected behavior ?

vanfanel commented 4 months ago

This is a scan of the Knighmare MSX manual, where it's also specified that the game can be player with keyboard or joystick (see page 2 and page 3 of the manual):

https://ia801504.us.archive.org/24/items/Knightmare1986KonamiGBFR/manual-knightmare.pdf

dinkc64 commented 4 months ago

The msx keyboard needs a keydown / keyup event, the keydown event turns on the bit, and key up event turns it off, to send a '1'

void sendchar(uint8_t thekey, uint8_t KeyDown) { uint8_t charvalue[1] = '1'; int shifted = (get_shiftkey_state_somehow()) ? 0xf0 : 0x00; cBurnerKeyCallback(charvalue[0], shifted|KeyType, KeyDown); }

sendchar('1', 1); <- when user presses 1 sendchar('1', 0); <- when user stops pressing 1

barbudreadmon commented 4 months ago

I discovered some keyboard keys weren't mapped in the libretro port, yet even after mapping them i still can't control that knightmare game through the keyboard.

intkeyOn and intkeyOff are properly called on keyup/keydown events.

Is this game really playable through keyboard in our win32 builds ?

dinkc64 commented 4 months ago

The game works perfectly fine with the joystick & with the cursor keys. You'll have to map the cursor keys (key up, key down, key left, key right) in the input editor, then use space to fire (space is mapped through the keyboard callback)

best regards,

dinkc64 commented 4 months ago

btw, most msx games work with cursor keys + space for fire as an option in-case a joystick isn't plugged in/available kinda like how most spectrum games use q,a (up+down) and o,p (left/right) and space or m for fire instead of joy. In the rare cases when a game doesn't support joy at all on msx or speccy, a dip option exists to map joy#1 to cursor keys + space or qaop on speccy

best regards,

barbudreadmon commented 4 months ago

I finally tracked down the problem, ULDR are working correctly through the usage of msxKeyCallback, then they get reset to their keyup state by :

https://github.com/finalburnneo/FBNeo/blob/5f11128964ca64f454fb7f146b3f063364b30231/src/burn/drv/msx/d_msx.cpp#L1591-L1594

It's also a problem for F1-F6.

Basically i have multiple entries to the same input, and the states of those entries are not consistent. I'll need to think of a good solution around this.

barbudreadmon commented 4 months ago

Ok, i could solve this through some tricks from within the libretro port, but i wonder if it might not be a better idea to only allow keydown events within DrvFrame.

@dinkc64 what do you think ? I made a PR to illustrate what i have in mind : https://github.com/finalburnneo/FBNeo/pull/1679

dinkc64 commented 4 months ago

sure, do whatever you want, just make sure to test it :)

dinkc64 commented 4 months ago

I really don't understand how it's supposed to work? isn't that change going to cause some keydown/up's to get missed? test things like the cassette auto-loading thing too please

barbudreadmon commented 4 months ago

I am actually worried about the same thing, i'll see if i can find a seemingly more failproof method

barbudreadmon commented 4 months ago

This is a tough one, i was thinking of tracking whether a given key had a keydown event or not within a frame, and rejecting keyup events on that same key within the same frame, but it's difficult with msxKeyCallback being called outside of DrvFrame. Any good idea ?

dinkc64 commented 4 months ago

So when hooking it up it doesn't work at all on your side? I figured it wont matter if a keydown or up is in drvframe or not, because it's modifying a bitmap of memory that the msx can read thru the ppi chip. Each really fast key press (peck!) can usually last 2-4 frames, well, from my tests, so as long as msx can read that bit changed, it should be ok.. i think? :)

barbudreadmon commented 4 months ago

I might have poorly explained this.

The ppi doesn't have the opportunity to read the changed bits.

Using the names of the functions in the win32 builds :

  1. when pressing ULDR or F1-F6 on keyboard, BurnerHandlerKeyCallback change the bits
  2. RunFrame is called thereafter, and, if DrvJoy4 is unmapped or mapped somewhere else, it'll change back the bits from (1) before the ppi chip has a chance to read them.

What i'd want is for the bits from BurnerHandlerKeyCallback to not be changed back due to whatever is mapped (or not) to DrvJoy4. In the libretro port, i use the physical keyboard for BurnerHandlerKeyCallback, while i map DrvJoy4 to the gamepad as some kind of shortcut. Hence why ULDR and F1-F6 from the physical keyboard get ignored. If ignoring those keydown events from BurnerHandlerKeyCallback in the win32 builds is intentional, i could probably handle this in the port code instead.

dinkc64 commented 4 months ago

Nothing is ignored on the win32 build

example, I press any key that the handler takes care of: frame# 1 KD received between fr#1 and 2 2
3 4 KU received between 4 and 5 5 6 7

computer has frames 2.3.4 to process it on w32: KD,KU is read when inputs are read, right before DrvFrame runs

are you pressing KD and letting up (KU) between 1 and 2 frame? are you running the keycallback from a separate thread maybe? try to meetup when i'm on and we can explore better solutions or something? ... becasue I don't understand how your problem is happening :)

barbudreadmon commented 4 months ago

Hmmm, i just tested the win32 builds and i have exactly the same behavior : Keyboard's ULDR is getting ignored despite the handler if "Key UP", "Key DOWN", "Key LEFT" and "Key RIGHT" don't match that mapping in "Map Game Inputs". (tested on knightmare with a fresh setup)

dinkc64 commented 4 months ago

It's because keyboard's UDLR only is mapped through the game's inputs, its not read via the keycallback

best regards,

barbudreadmon commented 4 months ago

Ok, if this is intentional then i'll add some tricks in the libretro port to map the key to both.

dinkc64 commented 4 months ago

both?

barbudreadmon commented 4 months ago

I need keyboard's ULDR and F1-F6 mapped on both physical keyboard and gamepad. This is due to some people wanting the full keyboard experience while some others are playing on devices that don't even have keyboards, and remapping from one to the other through retroarch is not exactly a pleasant experience...

I thought i could use the handler for the keyboard while using the inputlist for the gamepad, but it turns out the inputlist cancels ULDR/F1-F6 coming from the handler before the ppi has any chance to read it. No worries, i'll find a solution on my side.

dinkc64 commented 4 months ago

Oh, I see now. What a headache :/

barbudreadmon commented 4 months ago

Any port-side workaround i come up with is just horrible, so i'm thinking of just mapping those inputlist keys back to the keyboard as they used to be. IIRC they were moved to gamepad due to some user complaining about being unable to play msx out-of-the-box on his smartphone... I should have ignored that request tbh, it's not my problem if he didn't want to use retroarch's remapping feature on his marvelous device.

vanfanel commented 4 months ago

Any port-side workaround i come up with is just horrible, so i'm thinking of just mapping those inputlist keys back to the keyboard as they used to be. IIRC they were moved to gamepad due to some user complaining about being unable to play msx out-of-the-box on his smartphone... I should have ignored that request tbh, it's not my problem if he didn't want to use retroarch's remapping feature on his marvelous device.

I totally second this. Someone being unable/unwilling to properly configure RetroArch in order to play games isn't your problem (or anybody's for that matter). Remapping is there for a reason.

barbudreadmon commented 4 months ago

@vanfanel It should be ok with https://github.com/libretro/FBNeo/commit/4a555e062b3a388dfc0893515cde78ce0b0b3909 I had a hard time deciding where i should map the "STOP" key on keyboard, i ended up mapping it to break.

vanfanel commented 4 months ago

@barbudreadmon Fantastic!! Fabulous!! I had a LONG go at Knighmare, and it now works perfect with the keyboard. I am very sorry this issue was such a rabbit hole, really. Thanks a lot for looking into it!

dinkc64 commented 4 months ago

Always nice when a bug-story has a happy ending :)