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

Custom Mapping #4

Closed
ThirteenAG opened this issue Oct 26, 2019 · 10 comments
Closed

Custom Mapping #4

ThirteenAG opened this issue Oct 26, 2019 · 10 comments
Assignees

Comments

@ThirteenAG
Copy link

Have you considered adding a custom mapping option? For example, this project fixes mapping in scarface game:
https://github.com/aap/XDinput/blob/master/dinput8/IDirectInputDevice8A.cpp#L115
I was thinking, maybe Xidi should offer additional functionality to achieve the same result?

@samuelgr samuelgr self-assigned this Oct 28, 2019
@samuelgr
Copy link
Owner

Thanks for bringing this up. I've had this feature in mind for a while - leaving this issue open to track it.

@samuelgr
Copy link
Owner

For developers, there actually is a way of creating a custom mapping already. However, it is not particularly well-documented and is likely more cumbersome than it needs to be. I will try to address this in a future version.

@samuelgr samuelgr added this to the 1.1.0 milestone Mar 10, 2020
@v00d00m4n
Copy link

v00d00m4n commented Aug 6, 2020

can you describe how to do custom mapping in current version?

@samuelgr
Copy link
Owner

Right now it is necessary to create a subclass of Mapper::Base.

@samuelgr
Copy link
Owner

This is addressed in v2.0.0. Have a look at the file Source/MapperDefinitions.cpp - creating a custom mapper is now as simple as adding a new element to the array defined there.

@samuelgr samuelgr removed this from the 1.1.0 milestone Jan 25, 2021
@v00d00m4n
Copy link

This is addressed in v2.0.0. Have a look at the file Source/MapperDefinitions.cpp - creating a custom mapper is now as simple as adding a new element to the array defined there.

Well, by custom mapping we all mean mapping that does not require source code editing and compilation, please add same mapping structure support into INI file or separate CustomMapping.cfg so we can just remap whatever we want and however we want.

This compicated code:
Mapper(L"XInputSharedTriggers", {
.stickLeftX = std::make_unique(EAxis::X),
.stickLeftY = std::make_unique(EAxis::Y),
.stickRightX = std::make_unique(EAxis::RotX),
.stickRightY = std::make_unique(EAxis::RotY),
.dpadUp = std::make_unique(EPovDirection::Up),
.dpadDown = std::make_unique(EPovDirection::Down),
.dpadLeft = std::make_unique(EPovDirection::Left),
.dpadRight = std::make_unique(EPovDirection::Right),
.triggerLT = std::make_unique(EAxis::Z, AxisMapper::EDirection::Positive),
.triggerRT = std::make_unique(EAxis::Z, AxisMapper::EDirection::Negative),
.buttonA = std::make_unique(EButton::B1),
.buttonB = std::make_unique(EButton::B2),
.buttonX = std::make_unique(EButton::B3),
.buttonY = std::make_unique(EButton::B4),
.buttonLB = std::make_unique(EButton::B5),
.buttonRB = std::make_unique(EButton::B6),
.buttonBack = std::make_unique(EButton::B7),
.buttonStart = std::make_unique(EButton::B8),
.buttonLS = std::make_unique(EButton::B9),
.buttonRS = std::make_unique(EButton::B10)
})
could be simplified to ini format like this:

[Mapper]
Type = CustomTypeName // should not be hardcoded, scan section names in format [Mapper:*] do add support of any number of custom types with different non predefined names, and add them to list of existing hardcoded types, in case if Mapper name match hardcoded one - override it with one from ini.

[Mapper:CustomTypeName]

            LX = A:X //simplified LefxAsixX to L:X, and Axis:X to A:X
            LY = A:Y
            RX =A:X 
            RY = A:Y
            D:U = P:U //simplified pov direction to P, dpad to D for more intuitive use, and directions simplified to U,D,L,R
            D:D = P:D

...
LT = A:Z+ //interpret pure axis name like Z as FULL AXIS, and name with + or - suffix lik Z+ or Z_ as positive or negative half of axis, should be universal for any maaping be it stick or trigger or button
RT = A:Z-
A = B:1 //simplified Button to B and name of buttons just to numbers
B = B:2
...
LS = B:9
RS = B:10

ALsdo i suggest to add half of axes remapping (could be usefull for some rare games) for axes, to allow, for example map each of stick direction to any pov direction or even button, to let, for example, any stick to act ad dpad in game, or even as face buttons
so we need extra lines like this:

LU = A:Y+
LD = A:Y-
LR = A:X+
LL = A:X-
RU = P:U
RD = P:D
RR = P:R
RL = P:L

these should override LX, LY and RX and RY, in case if just one half of axis remaped , rest of axis should be defined by LX, LY, RX, RY.

Another thing which i strongly suggest to add, is multi mapping per single button or axis or dpad.

For example LT and RT could be mapped like this:

            LT = A:Z+ ; B:11 // ; is used as separator for multi binds
            RT = A:Z- ; B:12

which means that LT and RT reports to game that both Z+- axis and B11 and B12 pressed. Why we may need it?
Well some games supports binding axis and buttons anywhere, some only allows to use axis for moves and rotations, and such a universal bind will allow game to bind axis in case it supported, or fallback to button in case it does not!
Also to make sure that axis gets priority over button or opposite, we can add 1ms delay according to order of mutlibinds so 0 slot gets 0ms delay, 1st 1ms delay, 2nd, 2ms delay and so on, DelayInMs=Number of slot. This will allow most of games, in case you do remapping in their menues, to catch axis firts and bind it 1st in case both are supported

Also to override this behavior we can add extra parameter into formula which will define delay, because some games are smart enought to prioritzed axis over buttons in case both are pressed at same time.

for example it could be done line this:

            RT = A:Z-(0) ; B:12(0) // (*) - delay before output of mapped button

which means both has no delay but default should be equal to

            RT = A:Z-(0) ; B:12(1)

This technique could be expanded even further, to make a different types of button presses as different binds. For example you can bind one X button to a several dinput buttons like this:

            X(100) = B:1 //TAP
            X(250) = B:2 //PRESS
            X(500) = B:3 //HOLD
            X = B:4 //RELEASE no matter the timing

this will bind very quick tap of 100ms to 1, average tap of 250ms on B2, and hold of 500+ to B3 and release (no matter how long you press it it will always trigger once you release, while first 3 cases will trigger only if time or release was equal or lesser than set delay, but higher than any delay smaller than this. So you hold button 0-100 ms and release it at any delay up to 100 you get B1 pressed, you hold it 101-250 ms and release it in set window - you press B2, you hold it 250-500 you press B3 ) to B4. its pretty much equal to things like onTAP onPRESS onHOLD onRELEASE in many game engines.

There are also things like double and tripple taps and even shifts (when you press one button and it changes button of one or many other buttons).

Double taps could be done by expanding previous format to this:

            X(100,100) = B:1 //TAP

this means that if same button was released at 100 ms, and immediately pressed again and released at 100ms time frame, we consider it as double tapping.

and this

X(100,100,100) = B:1 //TAP

would be a tripple tap! and we actually may have a 4 and 5 taps, as long as we dont limit array of delays between () separated by ,

As for shift, i suggest to do it like this, use same multibind as i suggested above with Sh:ShiftName as yet another bind to allow same button to work as usually while acting like shift:
[Mapper:CustomTypeName]
LT = A:Z+(0) ; B:11(0), Sh:Shift1(0) // Sw is shift bind, temporary rebins button while this button is held, Shift1 is subname of type
RT = A:Z- ; B:12

[Mapper:CustomTypeName:Shift1]
RT = B:13

In this case everything will act as in CustomTypeName, except RT, it will be remapped as B13 while LT is held, and once it released it will became Z- and B12 again.

You can add any number of shifts wiht any name without space, for example you can add special shifts for menus, for onfoot invehicle controls.

In addition to Shift we also need as Switch, it should use same subtype names as shift (actually it would be good if you can use one submapper from both switch and shift), like this:

[Mapper:CustomTypeName]
LT = A:Z+(0) ; B:11(0), Sw:Shift1(0) // Sw is switch, but it could use same subname after CustomTypeName, they should be universal for better flexibility
RT = A:Z- ; B:12

[Mapper:CustomTypeName:Shift1]
RT = B:13

Difference between Shift and Switch is that shift works while keep holding button, while Switch keeps same button rebind even after release on button.

To get out of switch mode to default one you can bind Sw:Default (which will rebind everything according to CustomTypeName) or Sw:Previous (Which will return to previously used shift mode, which could be default or could be not) or any other custom name like Sw:Something.

[Mapper:CustomTypeName:Shift1]
LT = A:Z+(0) ; B:11(0), Sw:Default(0)
RT = B:13

This is similar to how button macroses worked in unreal 1 and 2 games, but more advaced and flexible.

This could help with games that has some separate binds in menues that you cant rebind or have not enought free buttons for them and temporary need to unbind other buttons to avoid problems.

You may ask why we would need all of those, and here is the reason:
Many old games prior Xbox 360 and Xinput era, even if ported from consoled, used the PC mindset of binds, where one button is one function, and many games that allows to bind gamepad buttons, has more functions than buttons on gamepad, and while some games technically allow to bind same button on 2 different functions, most of games actually will clear previous binds of same button, or game will tell you that same button is bound twice and would not allow to save until you will rebind function to some free button.

This happens even in games that has console versions with multi binds on same button.

This is where all of this stuff would be useful.

Some of games with such behavior like GTA3, Vice City and San Andreas fixed gamepad support with memory hacking, but other games are not so lucky to be fixed like this, which is why we need some universal solution for this problem. There is ofcource Xinput Plus which partially solves this problem and actually has shift secondary bindings, but its not enough, it lacks configurable delays, multibinds, and other things i suggested.

Another thing which i suggest to add after you implement all of this is ability to bind keyboard and mouse buttons instead of gamepad buttons and axes.

You may argue that many programs exist that does that, and yes they are, but they are all external and does not allow to fix gamepad controls in games natively in games that does not allow gamepad input in some cases, like menues, inventories, and few other places where you can only use keyboard and mouse. All of universal rules from above should apply as well.

For example we have game that has full gamepad support in gameplay, but dont allow to bind menu or pause to gamepad and has hardcode ESC button for that, which is common mistake in many old games, but actually allows to bind "back" function to gamepad. And menu only allows to input with keyboard or mouse, so with all the stuff i suggested we can fix it like this:

[Mapper:CustomTypeName]
RX = A:RotX // MA: is for mouse button emulates mouse cursor with Right Stick
RY = A:RotY
LT = B:11
RT = B:12
Back = B:11 // lets say it in game map
Start = KB:ESC, Sw:PCmenu // KB: is for keyboard button, this multibind presses ESC to bring up menu, and switches mapper to mouse and keyboard specific mode

[Mapper:CustomTypeName:PCmenu]
RX = MA:X // MA: is for mouse button emulates mouse cursor with Right Stick
RY = MA:Y
LT = MB:R // MB for mouse button, L, R, M, EXT and so on, according to windows api https://docs.microsoft.com/en-us/windows/win32/inputdev/mouse-input
RT = MB:L
Back = KB:ESC; // we temporary turn it into universal back button that works in sub menues prior main one, but does not switch back to gamepad binds
Start = KB:ESC, Sw:Previous // Pressed ESC to get back to game, and also switched back to previous mapper game used

This could be done with Shift as well, more error free, but less comfortable because you have to hold some button to fix game in mouse input mode.

Another case where it can be used is games like splinter cell 1 you can actually bind Weapon selection mode to gamepad, but once mode if on, it only accept keyboard and mouse inputs, so you have to bind shift mode to same button which is bind to weapon selection, and temporary rebind axis to mouse, and dpad to keyboard arrows, and triggers to mouse buttons to confirm selection. Main menu would need a switch to a same sub binds.

One more game that could benefit from its Deus Ex, which is pretty much configurable to be controlled with gamepad natively, until any menu or inventory will popup, so such temporary switch to mouse emulation mode will allow game to have fully native gamepad support without need for external tools.

One more game that could be solved with all of these features if classic Mafia 1.

Some games also has bad aiming with gamepad axis and good with mouse, so emulation could be helpful to improve this.

There is a game Omicron that actually has dinput remapper that does exactly this - allows to use mouse aim while keeping native gamepad controls, actually this tool is like missing part of Xidi (i asked for sources and was actually going to do something like xidi based on it, but author lost sources, yet compiled wrapper could be used as reference to see and mimic how it works).

And to make mouse emulation better we need sensitivity, acceleration and deadzone settings with negative value support (to reduce existing acceleration and sensitivity just in case). Preferably added to axis bind like this:

RY = MA:Y(0)[SEN:100, ACC:0,DZ:10] // i used [] to keep () for delays, but it can be reformed to more universal array like (DEL,SEN,ACC,DZ) which will differ depending on input type we dealing with, so if its not axis or analogue button - anything but delay should be ignored).

I think this will allow to fully control most of games natively with gamepad, but there could be few cases i did not witness or forgot about which would need something more than this (probably old games with wheels and some extra controllers support).

@samuelgr
Copy link
Owner

Well, by custom mapping we all mean mapping that does not require source code editing and compilation, please add same mapping structure support into INI file or separate CustomMapping.cfg so we can just remap whatever we want and however we want.

The original requestor linked to a project that appears to need source code editing to change the layout of the controller. That said, custom mappers in a configuration file is a very reasonable request and a natural extension of all the code changes in v2.0.0. I am reopening this issue with text file-based mapping as the deliverable.

@v00d00m4n I appreciate all of the input in your previous comment, especially that you took the time to explain the "why" rather than just the "what" behind these requests. I will need to spend some more time thinking about which of these I can and want to do, along with how to do it, but if I understand correctly here is a summary of the suggestions:

  • Separate XInput axes into half-axes (i.e. left-stick-X+ and left-stick-X- instead of just left-stick)
  • Support multiple bindings per XInput controller element
    • Delay by a configurable amount between subsequent mappings being activated
  • Different bindings by how long an XInput controller element is activated
  • Access multiple sets of bindings by using shift (hold) and/or switch (toggle) controls to change between them
  • Keyboard emulation
  • Mouse emulation

To keep discussions organized, I want this issue to be confined just to the custom mapper via configuration file. Could you please create separate issues to track the discussions for each of these other suggestions?

@samuelgr samuelgr reopened this Jan 31, 2021
@BinToss
Copy link

BinToss commented Mar 13, 2021

Hey, Sam. GitHub allows you to change the title of the issue if you'd like.

You could add a checklist to the first post that would show in the Issues list.
Alternatively, you can use a Project to organize and manage issues.
e.g. https://github.com/yumiris/OpenSauce/projects

Example of a Checklist

image
image

@samuelgr
Copy link
Owner

As of v3.0.0 custom mappers can be defined in the configuration file.

@ThirteenAG
Copy link
Author

@samuelgr finally got around to try this, wanted to say great job!

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

No branches or pull requests

4 participants