Team-Doominati / Doominati

Avoiding the sins of ZDoom since 2016.
GNU General Public License v2.0
7 stars 1 forks source link

Input rewrite #17

Open marrub-- opened 7 years ago

marrub-- commented 7 years ago

needs regular inputs, probably buffered, IME support (should display ingame and not on system), and some way to network sync via magic

marrub-- commented 6 years ago

I need to rewrite the input system a bit, when I do there are several goals:

All of these are fairly simple, thankfully. The binding API should probably be a bit like UE4.

marrub-- commented 6 years ago

I'm honestly having trouble thinking of what API this should have. The internals will have to be rewritten in accordance with it, so I can't really do anything with it until the API is more clear. Suggestions welcome, the goals above all need to be solved. The entire API looks like this right now (I've only changed some things for consistency):

DGE_Native DGE_Point3R DGE_Input_GetAxis(unsigned num);
DGE_Native unsigned DGE_Input_GetButtons(void);
DGE_Native DGE_Point2I DGE_Input_GetCursor(void);
Kyle873 commented 6 years ago

Considering my own use-case, here's a jumbled mess of words about what I was thinking:

For both direct and virtual input, there should probably be separate ways to check for a button being pressed, released and held, because all 3 states have different use cases.

Personally, I don't really use an IME nor know how they function internally or are implemented, so I can't speak much to that part.

marrub-- commented 6 years ago

IMEs basically translate keyboard inputs to a buffer, which is then translated and then finalized into a completed input.

For example, kyouhaiitenkidesuna becomes きょうはいいてんきですな as you type, and then the user can press spacebar when they want to change it into a different possible variation like きょうはいいてんきですな -> 今日は良い天気ですな. During this state (called henkan) you can press spacebar for more choices, enter to complete the input, and whatever else the IME itself implements.

Virtual inputs

This should be its own issue really, considering its complexity. The biggest question is, as usual, "where do we store this information?" This is entirely a user option, so either we make a user configuration format in-engine or we do it in scripts with a native like DGE_Input_SetBind.

Text input

help my brain I don't know at all how to do this, I don't know how other engines do this. I'll have to look into it, especially because this needs to be part of InputSource, which is networked.

Cursor position

There's one for world coordinates currently. Adding one for screen coordinates would be easy, but I don't see the use for it as all rendering is done in world coordinates.

Direct key checking

I don't know about this because it's potentially hard to network. It could work, but unless we can think of a way to network it correctly (without eating bandwidth) its use would have to be discouraged.

Button state checking

I think it would be best to change the button API from:

DGE_Native unsigned DGE_Input_GetButtons(void);

To:

enum // DGE_ButtonState
{
   DGE_Button_Clear, // button is up
   DGE_Button_Down,  // button has just been pressed
   DGE_Button_Held,  // button is being held
   DGE_Button_Up     // button has just been released
};

DGE_Native int DGE_Input_GetButtonState(unsigned btn);

Which kills two birds with one stone: You now have 4294967295 buttons, and you can get their individual states.

Axes

I think the way we handle this is already pretty good, besides the internals. You can get 4294967295 axes, and all of them return 3D input. (Yes, trust me, some devices have 3D input.)

Kyle873 commented 6 years ago

Virtual inputs

I was expecting a native actually, I didn't even consider a format like KEYCONF or something. Which is the better option I guess could also depend on the scope/size of the project, so maybe having both wouldn't be a bad idea? A native in script could be useful for the use-casing of what I describe below in direct key checking.

Text input

Yeah, I doubt I'll be any help there. I have no idea how that works internally besides saying to go check out how other engines implement it I guess.

Cursor position

Ah right, that's a good point. Will it still have some use in terms of building a GUI, though?

Direct key checking

If virtual keys are quick and easy to add/create, then I don't really see this as needing to be necessary, especially if networking them would be a concern. My whole argument for having it in the first place stems from just "needing a quick or rough input check for something that may be debugging/testing/etc related", not to actually be used in any sort of final product or release.

Button state checking

Yeah, I approve of this for sure.

Axes

Yeah, I know. the DS4 exposes it's gyro and such IIRC so in theory that would totally be usable as an axis input if you wanted to do some crazy shit with input devices that support it.

marrub-- commented 6 years ago

Will it still have some use in terms of building a GUI, though?

Nope, because the GUI is also world coordinates. The GUI I'm writing right now uses the GetCursorPos function as-is, actually.

A native in script could be useful for the use-casing of what I describe below in direct key checking.

That's good, it would probably be best to just have a native set like this then:

DGE_Native void DGE_Input_SetBindKey(unsigned btn, int ch);
DGE_Native void DGE_Input_SetBindPad(unsigned btn, int num); // takes an enum that has common controller button names
DGE_Native void DGE_Input_SetAxisKey(unsigned axis, int chFrwd, int chBack, int chLeft, int chRght);
DGE_Native void DGE_Input_SetAxisPad(unsigned axis, int num); // takes an enum that has common controller axis names

And the user would provide their own config file format then. If we in the future add an internal config format this wouldn't clash.

DavidPH commented 6 years ago

Do remember that any rewrite of the input API needs to include specifying what player to get input for.

Also, as far as extension buttons, I definitely like the idea of allowing arbitrary extra buttons to be defined. And a step further, I wonder if we even want to have "builtin" buttons. That way games with very few needed buttons would be more easily optimized by the netcode, etc. That said, buttons should be defined statically, in either GAMEDEFS or CODEDEFS.

marrub-- commented 6 years ago

GAMEDEFS could definitely have that, as it's entirely static data that shouldn't be able to change (without recompiling of course.) So you'd basically just be defining the amount of bindable keys and axes.

marrub-- commented 6 years ago

Partially done in 9e3e31a now. This is the final API unless there are any objections:

enum // DGE_Axis
{
   DGE_Axis_Up,
   DGE_Axis_Down,
   DGE_Axis_Left,
   DGE_Axis_Right,
   DGE_Axis_Forward,
   DGE_Axis_Backward,
};

enum // DGE_ButtonState
{
   DGE_Button_Down    = 1 << 0,
   DGE_Button_WasDown = 1 << 1,
   DGE_Button_Hold    = DGE_Button_Down | DGE_Button_WasDown,
   DGE_Button_Release = DGE_Button_WasDown,
   DGE_Button_Press   = DGE_Button_Down,
};

enum // DGE_Key
{
   DGE_Key_Backspace = '\b',
   DGE_Key_Tab       = '\t',
   DGE_Key_Return    = '\r',
   DGE_Key_Escape    = '\033',
   DGE_Key_Delete    = '\177',

   DGE_Key_Special  = 0x40000000,
   DGE_Key_Capslock = DGE_Key_Special + 0x39,

   DGE_Key_F1, DGE_Key_F2,  DGE_Key_F3,  DGE_Key_F4,
   DGE_Key_F5, DGE_Key_F6,  DGE_Key_F7,  DGE_Key_F8,
   DGE_Key_F9, DGE_Key_F10, DGE_Key_F11, DGE_Key_F12,
   DGE_Key_SysRq,
   DGE_Key_ScrollLock,
   DGE_Key_Pause,

   DGE_Key_Insert, DGE_Key_Home, DGE_Key_PageUp,
                   DGE_Key_End,  DGE_Key_PageDown,

   DGE_Key_Right, DGE_Key_Left, DGE_Key_Down, DGE_Key_Up,

   DGE_Key_NumLock,
   DGE_Key_KP_Div, DGE_Key_KP_Mul, DGE_Key_KP_Sub, DGE_Key_KP_Add,
   DGE_Key_KP_Enter,
   DGE_Key_KP_1, DGE_Key_KP_2, DGE_Key_KP_3,
   DGE_Key_KP_4, DGE_Key_KP_5, DGE_Key_KP_6,
   DGE_Key_KP_7, DGE_Key_KP_8, DGE_Key_KP_9,
   DGE_Key_KP_0, DGE_Key_KP_Dot
};

enum // DGE_MouseButton
{
   DGE_Mouse_Left,
   DGE_Mouse_Middle,
   DGE_Mouse_Right,
   DGE_Mouse_Extra1,
   DGE_Mouse_Extra2,
   DGE_Mouse_Extra3,
   DGE_Mouse_Extra4
};

enum // DGE_PadControl
{
   DGE_Pad_A,
   DGE_Pad_B,
   DGE_Pad_X,
   DGE_Pad_Y,
   DGE_Pad_Back,
   DGE_Pad_Menu,
   DGE_Pad_Start,
   DGE_Pad_StickLeft,
   DGE_Pad_StickRight,
   DGE_Pad_ShoulderLeft,
   DGE_Pad_ShoulderRight,
   DGE_Pad_DPadUp,
   DGE_Pad_DPadDown,
   DGE_Pad_DPadLeft,
   DGE_Pad_DPadRight,
   DGE_Pad_LStickUp,
   DGE_Pad_LStickDown,
   DGE_Pad_LStickLeft,
   DGE_Pad_LStickRight,
   DGE_Pad_RStickUp,
   DGE_Pad_RStickDown,
   DGE_Pad_RStickLeft,
   DGE_Pad_RStickRight,
   DGE_Pad_TriggerLeft,
   DGE_Pad_TriggerRight
};

DGE_Native DGE_Point3R DGE_Input_GetAxis(unsigned player, unsigned num);
DGE_Native unsigned DGE_Input_GetButton(unsigned player, unsigned btn);
DGE_Native DGE_Point2I DGE_Input_GetCursor(unsigned player);
DGE_Native void DGE_Input_SetAxisKey(unsigned num, unsigned axis, int set);
DGE_Native void DGE_Input_SetAxisPad(unsigned num, unsigned axis, unsigned set);
DGE_Native void DGE_Input_SetAxisMouse(unsigned num, unsigned axis, unsigned set);
DGE_Native void DGE_Input_SetBindKey(unsigned btn, int ch);
DGE_Native void DGE_Input_SetBindPad(unsigned btn, unsigned num);
DGE_Native void DGE_Input_SetBindMouse(unsigned btn, unsigned num);