Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added keyboard and mouse input remapping, mouse movement to joystick logic, GUI and more #1356

Open
wants to merge 99 commits into
base: main
Choose a base branch
from

Conversation

kalaposfos13
Copy link
Contributor

@kalaposfos13 kalaposfos13 commented Oct 12, 2024

An updated overview of the PR as of 2 months later, since so much has changed that not a lot remains from the original version:

The current state of input handling

  • Most controllers work out of the box, with Xbox controllers' back button emulating a touchpad press as well.
  • However, these are the default bindings, and they are unchangeable.
  • Keyboard inputs are technically supported, but only as single buttons, you can't rebind them and the configuration is basically unplayabe.
  • You can't use the mouse at all.

I decided that since more and more games are finally becoming more and more playable, an update to this system is really needed, as a core part of PC gaming is the ability to rebind controls however you want, and a lot of people prefer using KBM over controller.

An overview of the changes

  • I added the ability to rebind your mouse, keyboard and controller inputs, with up to 3 inputs per output.
  • You can create a custom configuration for every game in your library.
  • I added a GUI for this (accessed by the previously unused Controller button) where you can edit your bindings straight from the launcher. You can even reload the configuration mid-game, giving you the ability to change keybinds without restarting the emulator.
  • I added an implementation of mouse-to-joystick emulation, making controlling the camera in games like Bloodborne with your mouse movement possible.
  • A more detailed user manual can be found by clicking the Help button in the aforementioned config editor.

A technical overview of the control flow of the new input handling system

  1. Upon launching a game, the config is read in from the correct file. Next, the main SDL event handling loop is started. A separate timer is also created for mouse polling, which runs on a completely different system than everything else.
  2. The event handling loop waits for an event. If one is found, and it is a controller, keyboard or mouse (button or wheel) event, the main part of input handling starts.
  3. Based on the event, a custom input ID is calculated (these are just the SDL ID-s but with an offset based on which device it is, as all of them start at 0). For analog inputs, the distance is also stored.
  4. Next, we add or remove this ID based on the event type to the list of currently active inputs (for example, we add it if it's a keydown, but remove it if it's a keyup event). If that list changed (holding down a keyboard button will generate multiple keydown events, for example, so not every event changes the list), we recalculate the state of the emulated controller, otherwise, we finish the handling of this event here.
  5. If the list changed, the following things happen: First, we reset the "new" state of the controller (from now on, this refers to the emulated one). It has two states: the actual and the "new", and the later is used by the algorithm, and when it finishes, changes the actual state to the newly calculated state.
  6. We then iterate over the list of all bindings. This is a sorted list, with the bindings whose inputs have more keys being higher priority than those with less. (example: [a, b] > [c] and [a, b] < [c, d, e]). For every binding, we check if all of its input ID-s are in the list of active ID-s, and if so, we flag them as "used" (The list actually stores ID - bool pairs, and the flag is reset to false every new input frame). If an input's all ID-s are found, but all of them are "used", that means the input is overridden by another one (example: [w, lalt] overrides [w], so pressing [w, lalt] doesn't activate both). This is why the bindings being sorted matters.
  7. If a binding's input is determined to be valid and not overridden, we then update the corresponding output's "new" state. If it's a button, we set its "button pressed" flag to true, meaning that if any of the inputs bound to this is active, it will be pressed, and only becomes unpressed when all of those are. If it's an axis, we add the offset that is stored in the binding to it (That is either +-127 if it's a button input, or the value we read in with the input ID, and if one of the inputs is analog (you can bind an axis and a button to an axis, and that makes that axis only activate if the button is help as well)) we pass the value from that. This is what makes WASD feel much better, as now holding A and D now centers the joystick, since one adds 127 and the other adds -127, canceling each other out.
  8. The actual controller state is updated from the new controller state.

This explanation leaves things like halfmode_joystick and key_toggle handling out, but it is already quite complicated without those.

@kalaposfos13
Copy link
Contributor Author

kalaposfos13 commented Oct 13, 2024

Update:
Mouse movement input is now not hard-coded, and can be set to either joystick, and it can be toggled ingame with f7, as it currently overwrites all other inputs to the bound joystick.

@georgemoralis
Copy link
Collaborator

i have some doubt for mouse . Most games calls sceMouse lib library to do it natively . check draft #633

@kalaposfos13
Copy link
Contributor Author

Well for the games that support it just disable this? I wrote this specifically for Bloodborne that doesn't have support, and there, this works fine. I know that this isn't the cleanest option, but for some games you use either this or nothing

@georgemoralis
Copy link
Collaborator

well sure bb what else :D . Need to check how to have both working . Maybe have an config option to enable/disable this

@kalaposfos13
Copy link
Contributor Author

I checked the libMouse branch, and it looks like it can coexist with this, even without manual config other than not adding mouse bindings to my keyboardInputConfig.ini file like this:
This is my waitEvent:

case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP:
case SDL_EVENT_MOUSE_BUTTON_UP:
case SDL_EVENT_MOUSE_BUTTON_DOWN:
    SDL_AddTimer(33, keyRepeatCallback, (void*)payload_to_timer);
    onKeyPress(&event);
    break;

and this is yours:

case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP:
  onKeyPress(&event);
  break;
case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP:
  onMouseAction(&event);
  break;

These can be merged into one, and while I haven't tested this, this will probably work fine, since they use different things, and the overhead of checking mouse input both ways is probably negligible.
Here's an example of merging the two:

case SDL_EVENT_MOUSE_BUTTON_UP:
case SDL_EVENT_MOUSE_BUTTON_DOWN:
    onMouseAction(&event);
    // no break here
case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP:
    SDL_AddTimer(33, keyRepeatCallback, (void*)payload_to_timer);
    onKeyPress(&event);
    break;

@stinkyolddude
Copy link

Update: Mouse movement input is now not hard-coded, and can be set to either joystick, and it can be toggled ingame with f7, as it currently overwrites all other inputs to the bound joystick.

What are the new controls and how do I change them? I really wanna take the X O Square and Triangle buttons off the Numpad. That would help a lot!

@kalaposfos13
Copy link
Contributor Author

What are the new controls and how do I change them? I really wanna take the X O Square and Triangle buttons off the Numpad. That would help a lot!

You can find the new bindings in the user/keyboardInputConfig.ini file, and they are already changed. To use it, just copy it to your user/ directory and you are good to go, and the syntax is fairly straightforward

@kalaposfos13
Copy link
Contributor Author

kalaposfos13 commented Oct 14, 2024

Quick notice, as it stands now mouse wheel support is incompatible with Logitech mouse software due to an unknown bug (the wheel inputs don't get registered correctly, the rest work fine)

@kalaposfos13
Copy link
Contributor Author

I finished the first version of my controller remapping support, but not everything is done yet, here's the current status:

  • Button-to-button mapping: works
  • Axis-to-axis mapping: works if you don't mix the types (joystick axis to trigger or vice versa). If you do, it still activates outputs, but for example, binding r2 to rightjoystick_x only pushes it in the positive direction, and you have no way of making it go the other way.
  • Button-to-axis mapping: works
  • Axis-to-button mapping: works with the triggers, but with the joystick, the current implementation doesn't differentiate between positive or negative directions, so you an only bind one output to it, and it will activate both ways
  • Button+axis-to-axis: works (e.g. the joystick only 'activates' if a button is held)
  • Touchpad remapping: you can bind buttons to it, but not the other way.

For axis-to-axis mapping, there's a new syntax: axis_left_x = axis_left_x
I also changed the folder name from kbmConfig to inputConfig.

…s and buttons

The touchpad's button state was correctly handled, so games that use that were fine, but the touchDown flag was always set to true, so games that use this flag had problems, like Gravity Rush
@kalaposfos13
Copy link
Contributor Author

The latest commit should fix Gravity Rush's intro getting stuck after the first input.

@kalaposfos13
Copy link
Contributor Author

kalaposfos13 commented Nov 29, 2024

If the game isn't rendering correctly, then inputs not registering us most likely not an issue from this PR, but whatever other error you had. This can be easily tested by checking what happens on main. CUSAXXXXX.ini will always get generated (if it isn't already) when you boot up the selected game.

@kalaposfos13
Copy link
Contributor Author

Yes, I have seen that already. That is the RPCS3 remapping window modified by @rainmakerv3 for his version of controller remapping. We have already had a short talk about adding a further modified version to this PR, but for that we'd need someone who has a visual Qt editor set up with this project, which I've been unable to do yet on Linux

@rainmakerv3
Copy link
Contributor

rainmakerv3 commented Dec 9, 2024

I think I can now find some time to edit the UI for your purposes @kalaposfos13 , but I would need to know what the end state functionality would be (are you implementing stick to button remapping, will each side of the axis be mappable, etc). Or maybe it would be simpler if we just list what changes I need to make on my existing UI.

For keyboard though it's tricky. we can't use drop-down boxes for inputs (too many choices), and I believe there need to be some new fields for modifiers and half mode for each possible key (maybe a drop down for modifier and a checkbox for halfmode?), as well as sliders for the float values for mouse. So maybe I can do controller first and we'll see about kbm in the future

Also for reference @GHU7924 , if you or anyone who's interested on windows you can actually edit this using QT creator without need for any C++ coding knowledge, it's entirely GUI driven

@kalaposfos13
Copy link
Contributor Author

My idea is that there is 3 tabs: One for the keyboard and mouse, one for the controller and one fallback plaintext editor. I dont know how the keys will be displayed or inputted, and my only idea for that is a drop-down menu (something like the game selector) and you can add/remove entries to/from it, and the entries are just the text of what goes after the "=" sign in the config file (e.g. "lalt, w"). This means that the file parser will have to add each line to a list of inputs to the corresponding output, based on whether the input is KBM or controller (technically it can even be mixed) and saving is just the reverse (maybe add #Keyboard shortcuts and #Controller shortcuts at the beginning of each section). Where currently the "Analog stick settings are, there could be the misc settings like mouse_to_joystick, mouse_movement_controls etc.

Let me know if I missed anything.

@kalaposfos13
Copy link
Contributor Author

We should move this conversation about the new GUI to Discord, as it might be easier there and we don't have to spam this poor PR's comment section even more, as it is already quite long. @GHU7924 do you use Discord?

@GHU7924
Copy link

GHU7924 commented Dec 21, 2024

So, people.
If you have any ideas for a GUI controller, then follow the Link.

If you have experience in creating a GUI and you are ready to help @kalaposfos13 , then welcome (or find it in the discord).

@rainmakerv3
Copy link
Contributor

rainmakerv3 commented Dec 23, 2024

I have a functional prototype for GUI (controller only, KBM is a lot more involved) , shown here:
image

The design assumes that each analog direction will be mappable at some point. I can finalize and clean it up when the controller code is finished, but at least this gives an idea of how controller GUI can work with this implementation

You can try it here:

https://github.com/rainmakerv3/shadPS4/actions/runs/12480051512
code: rainmakerv3@29793ef

@GHU7924
Copy link

GHU7924 commented Dec 24, 2024

@kalaposfos13 [CUSA30992] Teenage Mutant Ninja Turtles: Shredder's Revenge (1.08)

I tried the Main build and the kbm-only build, but there is no reaction to pressing the buttons of the gamepad and keyboard.
Can you figure out the problem?

If anyone has this game, could you let us know if you have the same problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants