Saturday, August 22, 2020

The Mouse Move Event

GBufferedInput is an event-based library that provides raw input. The goal of the mouse move feature is to give the developers a message every time the mouse changes position. One of the conditions of this event is to report pixel changes in mouse movement only. This condition exists because there are platforms that report this event regardless of any change in position. 

Feature implementation steps
The first step in working on this feature is to add the new 
GBufferedInput event flag, MOUSEMOVE. Next is to understand how GBufferedInput creates events from the information it receives from each platform. Finally, add the event to the GBufferedInput implementation in a way that conforms with the established behavior of the existing code.


Windows

On Windows, GBufferedInput replaces the procedure Windows sends events to, with one that is set up by GWindowGBufferedInput reports events to GWindow after it is done with them. Utilizing the raw input model, GBufferedInput gets input data directly from the device and uses it to generate events. 


Multiple mouse movement events are provided in the raw input model.


  • Relative Movement: Provides the change in the mouse position.
  • Absolute Movement: Provides the screen position of the mouse.
  • Virtual Movement: Provides the mouse position within a virtual environment. 

Virtual movement will be ignored since it is outside the scope of the Gateware feature. GBufferedInput will look for relative and absolute movement events. The existing Windows implementation of GBufferedInput only generates one event per message from Windows. The problem is that the raw input model can report a mouse button event with a mouse movement event within the same message. Considering how plentiful mouse movement messages are, I chose to ignore the mouse move event when there is also a button event. I did this initially to preserve the behavior of the existing implementation; one message generates one event. I later changed this implementation to create multiple events, to match GBufferedInput's behavior on every other platform.


Linux

On Linux, the implementation of GBufferedInput does not have a function that X11 calls whenever an event message is ready. Instead, a thread continuously queries input changes. Another difference is that multiple events are sent per query, which is unlike the behavior of the Windows implementation. 


Even though there are mouse move events that can be received from X11, my feature code doesn't use them. The current implementation gets the updated mouse position every thread cycle. Instead of waiting for an event, where the mouse may not have actually moved, I chose to check the current mouse position with its last position and generate the event if there was a difference. Given the implementation's query nature, I believe this is the best option over waiting for the mouse move event. It is possible that in the time between queries, a mouse movement event may be missed, checking the mouse position every cycle is more reliable in this case.


Mac

The Mac implementation of GBufferedInput uses inheritance to get events. Overriding an event function of NSResponder is all that needs to be done to start receiving events. This is also unlike Windows and Linux, and a much easier way to set up events. 


Usually, overriding a member function of NSResponder is all you have to do to start receiving events. However, the mouseMoved() function has an extra step, requiring the window to be enabled to accept mouse move events. By default, a window ignores mouse move events due to how frequently they occur.


Unit Testing catches problems

A Unit Test needed to be made to ensure that the MOUSEMOVE event was working correctly. GBufferedInput didn't have a Unit Test for any mouse input, so I made one. In addition to testing the MOUSEMOVE event, all mouse buttons and the scroll wheel would also be tested. The Unit Test revealed that various events were not responding correctly, depending on the platform. It's an issue that will have to be addressed at some point. Otherwise, the feature is complete.


Conclusion

The MOUSEMOVE event is a helpful feature for UI, FPS movement, and many types of games. With each of these features, I see the different ways each platform operates and how to work with them. I also learn more and more about the inner working of Gateware and how it makes complicated things easier for developers. 

No comments:

Post a Comment