Plan for gfx directx
This article contains the todo list discussion for the gfx_directx backend. It also presents ideas for hardware accelerated graphics operations.
Input
The input is largely gathered from window messages. Currently, the engine asks for snapshots of current state of each input device. It is the task of the backend to interpret the messages into a block of current state and events. The engine may also attempt to manipulate the position of the mouse cursor within the window. The backend should respect those manipulations unless overridden.
Keyboard
Messages
The WM_KEYDOWN message fires every time a key press occurs. It continues firing if that key is held down. It contains information about the actual key being pressed, including scan code, whether it's an extended key, and the virtual key it represents.
The continuous firing for the same key being held down should not generate new events for the engine, since the engine manages that anyway. The backend ignores continuous firing.
The WM_KEYUP message fires every time a key release occurs. It contains information about the actual key being released, including scan code, whether it's an extended key, and the virtual key it represents. There is a bug with the SHIFT keys. It can be recreated as follows:
- Hold down both SHIFT keys
- Release one SHIFT key
The one SHIFT key that was released did not have a WM_KEYUP message sent to the window because the other SHIFT key is still depressed. When the other SHIFT key releases, the window receives the WM_KEYUP message for that SHIFT key, but not the one that was released first.
The workaround for this case was using GetAsyncKeyState(VK_LSHIFT) and GetAsyncKeyState(VK_RSHIFT) right before copying all the OHR scancode values to the engine's keyboard state buffer. The VK_SHIFT virtual key is manually toggled, as discussed in L/R Keys.
L/R Keys
The Ctrl, Alt, Win, Shift, and NumPad keys all have duplicates. Currently, they are all being checked for left vs. right state. This is done by checking the 0x1000000 bit (extended key bit), or the scan code for Shift keys.
Using this feature, NumLock no longer needs to be enabled to differentiate between the NumPad keys and their duplicate counterparts. The NumPad 5 key is a duplicate of the CLEAR key (VK_CLEAR).
gfx_sdl fails to note when both Ctrl, Alt, Shift, and Enter keys are pressed. With Enter, it updates it's state after the other Enter is released. The other said keys do not update state. gfx_directx should ignore this type of behavior, but for compatibility, it will only fire the generic Ctrl, Alt, and Shift once while either of the L/R keys are depressed until both are released.
The VK_CONTROL(Ctrl), VK_MENU(Alt), and VK_SHIFT(Shift) keys are the generic virtual key codes. They are tested accordingly:
...after evaluating a keypress for a L/R vk code, it's generic being VK_*... if(m_virtualKeys[ VK_* ] == 0x0) { m_virtualKeys[ VK_* ] = 0x80; KB_CREATE_KEYPRESS(m_ohrScans[ c_vk2fb[ VK_* ] ]); }
And then for the key release:
...after evaluating a key release for a L/R vk code, it's generic being VK_*... if(m_virtualKeys[ VK_L* ] == 0x0 && m_virtualKeys[ VK_R* ] == 0x0) { m_virtualKeys[ VK_* ] = 0x0; KB_CREATE_KEYRELEASE(m_ohrScans[ c_vk2fb[ VK_* ] ]); }
Toggle Keys
Toggle keys are reported as actual keyboard state, possible with GetKeyState() right before copying the OHR scancodes to the engine's keyboard state buffer.
Leaving the Window
Keyboard state, aside from toggle keys, should probably be cleared when the window becomes inactive instead of maintaining its last state. At least, it's state should be cleared upon returning to the window. This must still be implemented.
System Keys
Some key combinations spawn system messages, such as Alt-Tab, Alt-F4, Alt-Space, etc. Currently, system key presses are respected. Perhaps an option should allow those system key presses to be ignored. By default, though, the option should allow system messages. This, too, must be implemented.
Mouse
Messages
The window receives many messages related to the mouse: WM_NCMOUSEMOVE, WM_MOUSEMOVE, WM_NC*BUTTONDOWN, WM_*BUTTONDOWN, WM_NC*BUTTONUP, WM_*BUTTONUP, WM_MOUSEWHEEL, and WM_NCHITTEST. (The '*' wildcard represents L, R, or M, for Left, Right, and Middle mouse buttons.) The NC in the message name refers to the non-client area of the window, such as the window title, close button, borders, etc.
The input currently exhibits a problem in gathering mouse input when the cursor is hidden by the engine, then the user attempts to resize the window. It's discussed in Showing and Hiding the Cursor.
Clipping to the Window
The mouse will clip to the window only when a mouse button is being held down or io_clipcursor() is called from the engine. The mouse should be free-able (which it currently is), as discussed in Toggling Dead/Live Input. Haven't stumbled across any bugs here.
Engine Controlling Cursor
The engine makes calls to io_setmouse(), which tries to set the position of the cursor on the client area of the ohr window. The engine does not need to know any other information about the screen or client dimensions, just simply requesting the cursor move.
There is a bug reproduced by going into the maptile editor, and pressing the keyboard left/right/up/down keys. The mouse does not exactly move to the right position, which can eventually cause the cursor to jump to wrong positions.
The mouse_event() function is used to adjust the system cursor's position, which would report appropriate window messages to affect input state as seen by the engine. The call currently used is:
DWORD xPos, yPos; RECT rClient, rDesktop; GetClientRect(g_Window.getWindowHandle(), &rClient); POINT pos = {rClient.right * x/320.0f, rClient.bottom * y/200.0f}; ClientToScreen(g_Window.getWindowHandle(), &pos); GetWindowRect(GetDesktopWindow(), &rDesktop); xPos = 1 + (DWORD)((float)pos.x / (float)rDesktop.right * 65535.0f); yPos = 1 + (DWORD)((float)pos.y / (float)rDesktop.bottom * 65535.0f); mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, xPos, yPos, 0, NULL);
(where 'x' and 'y' are the engine's requested cursor position placement)
Leaving the Window
Input state should be cleared when the window loses focus. This includes dropping the clipped cursor area.
Showing and Hiding the Cursor
The ShowCursor() function is used to show or hide the cursor. There is a bug that is reproduced by:
- Enter maptile editor
- Drag window border to some dimension
- Hover mouse over client area
Input has also fallen to a dead state. This may not be a Showing/Hiding cursor bug, but a Dead/Live input state error.
Toggling Dead/Live Input
The backend should allow the user to override the engine's request for the mouse cursor by disabling input to the engine. This is currently done by using the ScrollLock toggle key. This toggle has no effect in fullscreen mode. Setting the input state to 'dead' allows the cursor to be free of the window (in case io_clipcursor() was called by the engine) and prevents any mouse movement being updated.
It has been discussed to use a different key / key combination for disabling/enabling input. ScrollLock is a good choice because it's a toggle key, and it's unlikely to be used by anybody in game implementations.
The Showing and Hiding the Cursor bug may actually be a bug caused by a toggle in the Dead/Live input state.