Skip to content

Commit c9808c0

Browse files
committed
prevent mouse jumping upon switching to relative movement
1 parent 700487f commit c9808c0

1 file changed

Lines changed: 119 additions & 118 deletions

File tree

sources/libengine/window/window.cpp

Lines changed: 119 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,6 @@
1919

2020
namespace cage
2121
{
22-
namespace privat
23-
{
24-
struct GraphicsContext;
25-
}
26-
2722
namespace
2823
{
2924
ModifiersFlags getKeyModifiers(int mods)
@@ -45,29 +40,24 @@ namespace cage
4540
return r;
4641
}
4742

48-
struct MouseOffset
49-
{
50-
Vec2 off;
51-
};
52-
5343
class WindowImpl : public Window
5444
{
5545
public:
56-
Vec2 lastMouseButtonPressPositions[5] = {};
57-
uint64 lastMouseButtonPressTimes[5] = {}; // unused, left, right, unused, middle
58-
5946
Holder<privat::GraphicsContext> graphicsContext;
6047
ConcurrentQueue<GenericInput> eventsQueue;
6148
FlatSet<uint32> stateKeys;
49+
uint64 lastMouseButtonPressTimes[5] = {}; // unused, left, right, unused, middle
50+
Vec2 lastMouseButtonPressPositions[5] = {};
51+
Vec2 lastRelativePosition;
52+
Vec2 stateMousePosition;
53+
Vec2 stateMouseScale;
6254
MouseButtonsFlags stateButtons = MouseButtonsFlags::None;
6355
ModifiersFlags stateMods = ModifiersFlags::None;
64-
Vec2 stateMousePosition;
65-
Vec2 lastRelativePosition;
66-
Vec2 mouseScale;
6756
GLFWwindow *window = nullptr;
6857
bool focus = true;
6958
bool mouseIntendVisible = true;
7059
bool mouseIntendRelative = false;
60+
bool mouseAllowRelativeMovement = false; // prevent mouse jumping shortly after switching from absolute to relative movement
7161

7262
#ifdef GCHL_WINDOWS_THREAD
7363
Holder<Thread> windowThread;
@@ -152,23 +142,34 @@ namespace cage
152142

153143
void initializeEvents();
154144

155-
void updateMouseMode()
145+
bool getRelative() const { return glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED; }
146+
147+
Vec2 getPosition()
156148
{
157-
int intent = GLFW_CURSOR_NORMAL;
158-
if (!mouseIntendVisible)
159-
intent = GLFW_CURSOR_HIDDEN;
160-
if (mouseIntendRelative)
161-
intent = GLFW_CURSOR_DISABLED;
162-
glfwSetInputMode(window, GLFW_CURSOR, intent);
149+
Vec2 pos;
150+
double xpos, ypos;
151+
glfwGetCursorPos(window, &xpos, &ypos);
152+
pos[0] = xpos;
153+
pos[1] = ypos;
154+
return pos * stateMouseScale;
155+
}
163156

164-
mouseScale = Vec2(1);
165-
int fbw = 0, fbh = 0, ww = 0, wh = 0;
166-
glfwGetFramebufferSize(window, &fbw, &fbh);
167-
glfwGetWindowSize(window, &ww, &wh);
168-
if (fbw > 0 && fbh > 0 && ww > 0 && wh > 0)
157+
bool determineMouseDoubleClick(MouseButtonsFlags buttons, Vec2 cp)
158+
{
159+
CAGE_ASSERT((uint32)buttons < array_size(lastMouseButtonPressTimes));
160+
const uint64 ct = applicationTime();
161+
uint64 &lt = lastMouseButtonPressTimes[(uint32)buttons];
162+
Vec2 &lp = lastMouseButtonPressPositions[(uint32)buttons];
163+
if (ct - lt < 300'000 && distance(cp, lp) < 10)
164+
{
165+
lt = 0;
166+
return true;
167+
}
168+
else
169169
{
170-
mouseScale[0] = double(fbw) / double(ww);
171-
mouseScale[1] = double(fbh) / double(wh);
170+
lt = ct;
171+
lp = cp;
172+
return false;
172173
}
173174
}
174175

@@ -188,6 +189,8 @@ namespace cage
188189
if constexpr (std::is_same_v<T, input::MouseRelativeMove>)
189190
{
190191
CAGE_ASSERT(i.relative);
192+
if (!mouseAllowRelativeMovement)
193+
return;
191194
const Vec2 n = i.position;
192195
if (valid(lastRelativePosition))
193196
i.position = n - lastRelativePosition;
@@ -203,35 +206,97 @@ namespace cage
203206
events.dispatch(i);
204207
}
205208

206-
bool getRelative() const { return glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED; }
207-
208-
Vec2 getPosition()
209+
void updateMouseMode()
209210
{
210-
Vec2 pos;
211-
double xpos, ypos;
212-
glfwGetCursorPos(window, &xpos, &ypos);
213-
pos[0] = xpos;
214-
pos[1] = ypos;
215-
return pos * mouseScale;
211+
int intent = GLFW_CURSOR_NORMAL;
212+
if (!mouseIntendVisible)
213+
intent = GLFW_CURSOR_HIDDEN;
214+
if (mouseIntendRelative)
215+
intent = GLFW_CURSOR_DISABLED;
216+
glfwSetInputMode(window, GLFW_CURSOR, intent);
217+
218+
stateMouseScale = Vec2(1);
219+
int fbw = 0, fbh = 0, ww = 0, wh = 0;
220+
glfwGetFramebufferSize(window, &fbw, &fbh);
221+
glfwGetWindowSize(window, &ww, &wh);
222+
if (fbw > 0 && fbh > 0 && ww > 0 && wh > 0)
223+
{
224+
stateMouseScale[0] = double(fbw) / double(ww);
225+
stateMouseScale[1] = double(fbh) / double(wh);
226+
}
216227
}
217228

218-
bool determineMouseDoubleClick(MouseButtonsFlags buttons, Vec2 cp)
229+
void processEvents()
219230
{
220-
CAGE_ASSERT((uint32)buttons < array_size(lastMouseButtonPressTimes));
221-
const uint64 ct = applicationTime();
222-
uint64 &lt = lastMouseButtonPressTimes[(uint32)buttons];
223-
Vec2 &lp = lastMouseButtonPressPositions[(uint32)buttons];
224-
if (ct - lt < 300'000 && distance(cp, lp) < 5)
231+
#ifndef GCHL_WINDOWS_THREAD
232+
updateMouseMode();
225233
{
226-
lt = 0;
227-
return true;
234+
ScopeLock l(cageGlfwMutex());
235+
glfwPollEvents();
228236
}
229-
else
237+
#endif
238+
239+
GenericInput e;
240+
while (eventsQueue.tryPop(e))
230241
{
231-
lt = ct;
232-
lp = cp;
233-
return false;
242+
switch (e.typeHash())
243+
{
244+
case detail::typeHash<input::MouseMove>():
245+
updateMouseStateAndDispatch<input::MouseMove>(e);
246+
break;
247+
case detail::typeHash<input::MouseRelativeMove>():
248+
updateMouseStateAndDispatch<input::MouseRelativeMove>(e);
249+
break;
250+
case detail::typeHash<input::MousePress>():
251+
updateMouseStateAndDispatch<input::MousePress>(e);
252+
break;
253+
case detail::typeHash<input::MouseDoublePress>():
254+
updateMouseStateAndDispatch<input::MouseDoublePress>(e);
255+
break;
256+
case detail::typeHash<input::MouseRelease>():
257+
updateMouseStateAndDispatch<input::MouseRelease>(e);
258+
break;
259+
case detail::typeHash<input::MouseWheel>():
260+
updateMouseStateAndDispatch<input::MouseWheel>(e);
261+
break;
262+
case detail::typeHash<input::KeyPress>():
263+
{
264+
stateKeys.insert(e.get<input::KeyPress>().key);
265+
stateMods = e.get<input::KeyPress>().mods;
266+
events.dispatch(e);
267+
const input::KeyPress p = e.get<input::KeyPress>();
268+
events.dispatch(input::KeyRepeat{ p.window, p.key, p.mods });
269+
break;
270+
}
271+
case detail::typeHash<input::KeyRelease>():
272+
stateKeys.erase(e.get<input::KeyRelease>().key);
273+
stateMods = e.get<input::KeyRelease>().mods;
274+
events.dispatch(e);
275+
break;
276+
case detail::typeHash<input::KeyRepeat>():
277+
stateKeys.insert(e.get<input::KeyRepeat>().key);
278+
stateMods = e.get<input::KeyRepeat>().mods;
279+
events.dispatch(e);
280+
break;
281+
case detail::typeHash<input::Character>():
282+
stateMods = e.get<input::Character>().mods;
283+
events.dispatch(e);
284+
break;
285+
case detail::typeHash<input::WindowFocusGain>():
286+
focus = true;
287+
events.dispatch(e);
288+
break;
289+
case detail::typeHash<input::WindowFocusLose>():
290+
focus = false;
291+
events.dispatch(e);
292+
break;
293+
default:
294+
events.dispatch(e);
295+
break;
296+
}
234297
}
298+
299+
mouseAllowRelativeMovement = true;
235300
}
236301
};
237302

@@ -319,7 +384,7 @@ namespace cage
319384
e.mods = getKeyModifiers(w);
320385
e.position[0] = xpos;
321386
e.position[1] = ypos;
322-
e.position *= impl->mouseScale;
387+
e.position *= impl->stateMouseScale;
323388
if (glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_LEFT))
324389
e.buttons |= MouseButtonsFlags::Left;
325390
if (glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_RIGHT))
@@ -579,6 +644,7 @@ namespace cage
579644
if (impl->mouseIntendRelative != relative)
580645
impl->lastRelativePosition = Vec2::Nan();
581646
impl->mouseIntendRelative = relative;
647+
impl->mouseAllowRelativeMovement = false;
582648
}
583649

584650
Vec2 Window::mousePosition() const
@@ -615,72 +681,7 @@ namespace cage
615681
void Window::processEvents()
616682
{
617683
WindowImpl *impl = (WindowImpl *)this;
618-
#ifndef GCHL_WINDOWS_THREAD
619-
impl->updateMouseMode();
620-
{
621-
ScopeLock l(cageGlfwMutex());
622-
glfwPollEvents();
623-
}
624-
#endif
625-
GenericInput e;
626-
while (impl->eventsQueue.tryPop(e))
627-
{
628-
switch (e.typeHash())
629-
{
630-
case detail::typeHash<input::MouseMove>():
631-
impl->updateMouseStateAndDispatch<input::MouseMove>(e);
632-
break;
633-
case detail::typeHash<input::MouseRelativeMove>():
634-
impl->updateMouseStateAndDispatch<input::MouseRelativeMove>(e);
635-
break;
636-
case detail::typeHash<input::MousePress>():
637-
impl->updateMouseStateAndDispatch<input::MousePress>(e);
638-
break;
639-
case detail::typeHash<input::MouseDoublePress>():
640-
impl->updateMouseStateAndDispatch<input::MouseDoublePress>(e);
641-
break;
642-
case detail::typeHash<input::MouseRelease>():
643-
impl->updateMouseStateAndDispatch<input::MouseRelease>(e);
644-
break;
645-
case detail::typeHash<input::MouseWheel>():
646-
impl->updateMouseStateAndDispatch<input::MouseWheel>(e);
647-
break;
648-
case detail::typeHash<input::KeyPress>():
649-
{
650-
impl->stateKeys.insert(e.get<input::KeyPress>().key);
651-
impl->stateMods = e.get<input::KeyPress>().mods;
652-
events.dispatch(e);
653-
const input::KeyPress p = e.get<input::KeyPress>();
654-
events.dispatch(input::KeyRepeat{ p.window, p.key, p.mods });
655-
break;
656-
}
657-
case detail::typeHash<input::KeyRelease>():
658-
impl->stateKeys.erase(e.get<input::KeyRelease>().key);
659-
impl->stateMods = e.get<input::KeyRelease>().mods;
660-
events.dispatch(e);
661-
break;
662-
case detail::typeHash<input::KeyRepeat>():
663-
impl->stateKeys.insert(e.get<input::KeyRepeat>().key);
664-
impl->stateMods = e.get<input::KeyRepeat>().mods;
665-
events.dispatch(e);
666-
break;
667-
case detail::typeHash<input::Character>():
668-
impl->stateMods = e.get<input::Character>().mods;
669-
events.dispatch(e);
670-
break;
671-
case detail::typeHash<input::WindowFocusGain>():
672-
impl->focus = true;
673-
events.dispatch(e);
674-
break;
675-
case detail::typeHash<input::WindowFocusLose>():
676-
impl->focus = false;
677-
events.dispatch(e);
678-
break;
679-
default:
680-
events.dispatch(e);
681-
break;
682-
}
683-
}
684+
impl->processEvents();
684685
}
685686

686687
Vec2i Window::resolution() const

0 commit comments

Comments
 (0)