Open ingvart opened 11 months ago
WantCaptureMouse
and WantCaptureKeyboard
get updated during ImGui::NewFrame()
. So for an actual mouse it works since moving the cursor over ImGui items and clicking are distributed over lots of frames. With touch events, the emulated mouse moves to the touch position when it happens, so no frames in between. Your workaround would need to distribute the additional move and original touch down events across frames, introducing a latency of one frame.
An alternative would be to just give those events to ImGui, but buffer them for a frame for your own viewport. Then you could use WantCaptureMouse
to determine if the events from the previous frame should be handled by your OpenGL viewport, resulting in the added latency for that part only. If you want to get rid of that latency as well, you need to decide based on position if you want to handle that event. But this gets complicated fast since even positions within the bounds of your viewport can be obstructed by ImGui windows, so you would need to iterate through all windows visible during the last frame to decide.
It was a long time I've wrote this code, but I think this is exactly to solve this problem:
auto position = convertTouchToImGuiSpace(touch);
auto& io = ImGui::GetIO();
auto oldPosition = io.MousePos;
io.MousePos = position;
ImGui::UpdateHoveredWindowAndCaptureFlags();
if (ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow) or io.WantCaptureMouse) {
event->stopPropagation();
_capturedTouches.insert(touch->getID());
}
io.MousePos = oldPosition;
Thank you.
This worked. My solution is now:
#include "imgui_internal.h"
...
bool Main::handleEvents()
{
SDL_Event e;
while (SDL_PollEvent(&e))
{
// Touch finger events are not superceeded by mouse movement events, and we therefore
// update ImGui with the mouse position and give it a chance to process it before
// checking if ImGui is going to use the mouse or not.
if (e.type ==SDL_MOUSEBUTTONDOWN || e.type ==SDL_MOUSEBUTTONUP) {
io->MousePos = ImVec2(e.button.x, e.button.y);
ImGui::UpdateHoveredWindowAndCaptureFlags();
}
ImGui_ImplSDL2_ProcessEvent(&e);
if (e.type ==SDL_MOUSEBUTTONDOWN || e.type ==SDL_MOUSEBUTTONUP || e.type == SDL_MOUSEMOTION) {
// Check if ImGui needs the mouse click or move
if (ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow) || io->WantCaptureMouse) {
return true;
}
}
...
}
...
}
Note:
I had to include "imgui_internal.h" to use UpdateHoveredWindowAndCaptureFlags()
I also found that setting up a fake "mouse move"-SDL_Event with a new mouse position and calling ImGui_ImplSDL2_ProcessEvent before calling io->WantCaptureMouse did not work. It seems like ImGui_ImplSDL2_ProcessEvent does not update io->MousePos immediately, but queues this event (probably for the next "frame", as explained above).
Many thanks!
Btw, I'm not 100% sure, but I think ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)
part is not necessary and a check on io->WantCaptureMouse
is enough.
Changing from
if (ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow) or io.WantCaptureMouse) {
to
if (io.WantCaptureMouse) {
works fine.
Version/Branch of Dear ImGui:
Version: 1.89.2 Branch: master
Back-end/Renderer/Compiler/OS
Back-ends: imgui_impl_sdl imgui_impl_opengl3
My Issue/Question:
Example code:
Issue description:
My laptop has a touchscreen. My application draws OpenGL on the screen and uses ImGui. If I click the OpenGL area with the mouse, "io->WantCaptureMouse" will return false as expected. If I move the mouse to the ImGui area and click, it will return true, as expected. If I then move the mouse back to the OpenGL area, it will again return false, as expected. If I then touch the screen with my finger on the ImGui area, it will return false the first time, and then return true consecutively. If I then (after touching ImGui components) touch the OpenGL area again, it will return true the first time, and then return false consecutively. So the first touch with a finger is not "updated" in ImGui, and WantCaptureMouse returns the wrong value.
I have not found a way to work around this yet.
I am suspecting that the issue is due to ImGui not receiving any mouse move events and depends on these to determine that the mouse has entered it's area. Between two clicks with the mouse, a series of mouse move events will be generated by SDL. Between a click with the mouse or finger and another click with a finger, no mouse move events are generated.
Perhaps I can create a "fake" mouse move event before sending the mouse click event from a finger to "update" ImGui with the current mouse position, but it does seem a little unnecessary. But until I find a better solution, I will attempt this.
Or am I doing something wrong?
Thank you!