summaryrefslogtreecommitdiff
path: root/src/gfx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gfx.cpp')
-rw-r--r--src/gfx.cpp47
1 files changed, 47 insertions, 0 deletions
diff --git a/src/gfx.cpp b/src/gfx.cpp
index b10943553..64c7d9186 100644
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -1603,6 +1603,53 @@ void SetAnimatedMouseCursor(const AnimCursor *table)
SwitchAnimatedCursor();
}
+/**
+ * Update cursor position on mouse movement.
+ * @param x New X position.
+ * @param y New Y position.
+ * @param queued True, if the OS queues mouse warps after pending mouse movement events.
+ * False, if the warp applies instantaneous.
+ * @return true, if the OS cursor position should be warped back to this->pos.
+ */
+bool CursorVars::UpdateCursorPosition(int x, int y, bool queued_warp)
+{
+ /* Detecting relative mouse movement is somewhat tricky.
+ * - There may be multiple mouse move events in the video driver queue (esp. when OpenTTD lags a bit).
+ * - When we request warping the mouse position (return true), a mouse move event is appended at the end of the queue.
+ *
+ * So, when this->fix_at is active, we use the following strategy:
+ * - The first movement triggers the warp to reset the mouse position.
+ * - Subsequent events have to compute movement relative to the previous event.
+ * - The relative movement is finished, when we receive the event matching the warp.
+ */
+
+ if (x == this->pos.x && y == this->pos.y) {
+ /* Warp finished. */
+ this->queued_warp = false;
+ }
+
+ this->delta.x = x - (this->queued_warp ? this->last_position.x : this->pos.x);
+ this->delta.y = y - (this->queued_warp ? this->last_position.y : this->pos.y);
+
+ this->last_position.x = x;
+ this->last_position.y = y;
+
+ bool need_warp = false;
+ if (this->fix_at) {
+ if (!this->queued_warp && (this->delta.x != 0 || this->delta.y != 0)) {
+ /* Trigger warp. */
+ this->queued_warp = queued_warp;
+ need_warp = true;
+ }
+ } else if (this->pos.x != x || this->pos.y != y) {
+ this->queued_warp = false; // Cancel warping, we are no longer confining the position.
+ this->dirty = true;
+ this->pos.x = x;
+ this->pos.y = y;
+ }
+ return need_warp;
+}
+
bool ChangeResInGame(int width, int height)
{
return (_screen.width == width && _screen.height == height) || VideoDriver::GetInstance()->ChangeResolution(width, height);