Backends: OSX: Removed ImGui_ImplOSX_HandleEvent() from backend API. Move event tracking (desktop only) to OSX backend. (#4821)

Fix using NSKeyUp (#5268).
This commit is contained in:
stuartcarnie 2022-04-27 16:51:01 +03:00 committed by ocornut
parent 26f817807c
commit e66fc22057
6 changed files with 58 additions and 56 deletions

View File

@ -22,4 +22,3 @@
IMGUI_IMPL_API bool ImGui_ImplOSX_Init(NSView* _Nonnull view); IMGUI_IMPL_API bool ImGui_ImplOSX_Init(NSView* _Nonnull view);
IMGUI_IMPL_API void ImGui_ImplOSX_Shutdown(); IMGUI_IMPL_API void ImGui_ImplOSX_Shutdown();
IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(NSView* _Nullable view); IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(NSView* _Nullable view);
IMGUI_IMPL_API bool ImGui_ImplOSX_HandleEvent(NSEvent* _Nonnull event, NSView* _Nullable view);

View File

@ -23,6 +23,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2022-05-03: Inputs: Removed ImGui_ImplOSX_HandleEvent() from backend API in favor of backend automatically handling event capture.
// 2022-04-27: Misc: Store backend data in a per-context struct, allowing to use this backend with multiple contexts. // 2022-04-27: Misc: Store backend data in a per-context struct, allowing to use this backend with multiple contexts.
// 2022-03-22: Inputs: Monitor NSKeyUp events to catch missing keyUp for key when user press Cmd + key // 2022-03-22: Inputs: Monitor NSKeyUp events to catch missing keyUp for key when user press Cmd + key
// 2022-02-07: Inputs: Forward keyDown/keyUp events to OS when unused by dear imgui. // 2022-02-07: Inputs: Forward keyDown/keyUp events to OS when unused by dear imgui.
@ -66,6 +67,7 @@ struct ImGui_ImplOSX_Data
ImGuiObserver* Observer; ImGuiObserver* Observer;
KeyEventResponder* KeyEventResponder; KeyEventResponder* KeyEventResponder;
NSTextInputContext* InputContext; NSTextInputContext* InputContext;
id Monitor;
ImGui_ImplOSX_Data() { memset(this, 0, sizeof(*this)); } ImGui_ImplOSX_Data() { memset(this, 0, sizeof(*this)); }
}; };
@ -76,6 +78,10 @@ static void ImGui_ImplOSX_DestroyBackendData() { IM_DELETE(ImGui
static inline CFTimeInterval GetMachAbsoluteTimeInSeconds() { return static_cast<CFTimeInterval>(static_cast<double>(clock_gettime_nsec_np(CLOCK_UPTIME_RAW)) / 1e9); } static inline CFTimeInterval GetMachAbsoluteTimeInSeconds() { return static_cast<CFTimeInterval>(static_cast<double>(clock_gettime_nsec_np(CLOCK_UPTIME_RAW)) / 1e9); }
// Forward Declarations
static void ImGui_ImplOSX_AddTrackingArea(NSView* _Nonnull view);
static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view);
// Undocumented methods for creating cursors. // Undocumented methods for creating cursors.
@interface NSCursor() @interface NSCursor()
+ (id)_windowResizeNorthWestSouthEastCursor; + (id)_windowResizeNorthWestSouthEastCursor;
@ -429,15 +435,7 @@ bool ImGui_ImplOSX_Init(NSView* view)
bd->KeyEventResponder = [[KeyEventResponder alloc] initWithFrame:NSZeroRect]; bd->KeyEventResponder = [[KeyEventResponder alloc] initWithFrame:NSZeroRect];
bd->InputContext = [[NSTextInputContext alloc] initWithClient:bd->KeyEventResponder]; bd->InputContext = [[NSTextInputContext alloc] initWithClient:bd->KeyEventResponder];
[view addSubview:bd->KeyEventResponder]; [view addSubview:bd->KeyEventResponder];
ImGui_ImplOSX_AddTrackingArea(view);
// Some events do not raise callbacks of AppView in some circumstances (for example when CMD key is held down).
// This monitor taps into global event stream and captures these events.
NSEventMask eventMask = NSEventMaskFromType(NSKeyUp) | NSEventMaskFlagsChanged;
[NSEvent addLocalMonitorForEventsMatchingMask:eventMask handler:^NSEvent * _Nullable(NSEvent *event)
{
ImGui_ImplOSX_HandleEvent(event, bd->KeyEventResponder);
return event;
}];
io.SetPlatformImeDataFn = [](ImGuiViewport* viewport, ImGuiPlatformImeData* data) -> void io.SetPlatformImeDataFn = [](ImGuiViewport* viewport, ImGuiPlatformImeData* data) -> void
{ {
@ -462,6 +460,11 @@ void ImGui_ImplOSX_Shutdown()
{ {
ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData(); ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
bd->Observer = NULL; bd->Observer = NULL;
if (bd->Monitor != NULL)
{
[NSEvent removeMonitor:bd->Monitor];
bd->Monitor = NULL;
}
ImGui_ImplOSX_DestroyBackendData(); ImGui_ImplOSX_DestroyBackendData();
} }
@ -591,7 +594,7 @@ void ImGui_ImplOSX_NewFrame(NSView* view)
ImGui_ImplOSX_UpdateImePosWithView(view); ImGui_ImplOSX_UpdateImePosWithView(view);
} }
bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view)
{ {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
@ -716,3 +719,27 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view)
return false; return false;
} }
static void ImGui_ImplOSX_AddTrackingArea(NSView* _Nonnull view)
{
// If we want to receive key events, we either need to be in the responder chain of the key view,
// or else we can install a local monitor. The consequence of this heavy-handed approach is that
// we receive events for all controls, not just Dear ImGui widgets. If we had native controls in our
// window, we'd want to be much more careful than just ingesting the complete event stream.
// To match the behavior of other backends, we pass every event down to the OS.
ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
if (bd->Monitor)
return;
NSEventMask eventMask = 0;
eventMask |= NSEventMaskMouseMoved | NSEventMaskScrollWheel;
eventMask |= NSEventMaskLeftMouseDown | NSEventMaskLeftMouseUp | NSEventMaskLeftMouseDragged;
eventMask |= NSEventMaskRightMouseDown | NSEventMaskRightMouseUp | NSEventMaskRightMouseDragged;
eventMask |= NSEventMaskOtherMouseDown | NSEventMaskOtherMouseUp | NSEventMaskOtherMouseDragged;
eventMask |= NSEventMaskKeyDown | NSEventMaskKeyUp | NSEventMaskFlagsChanged;
bd->Monitor = [NSEvent addLocalMonitorForEventsMatchingMask:eventMask
handler:^NSEvent* _Nullable(NSEvent* event)
{
ImGui_ImplOSX_HandleEvent(event, view);
return event;
}];
}

View File

@ -39,6 +39,10 @@ Breaking changes:
- Renamed ImGuiKeyModFlags to ImGuiModFlags. Kept inline redirection enums (will obsolete). - Renamed ImGuiKeyModFlags to ImGuiModFlags. Kept inline redirection enums (will obsolete).
(This was never used in public API functions but technically present in imgui.h and ImGuiIO). (This was never used in public API functions but technically present in imgui.h and ImGuiIO).
- Backends: OSX: Removed ImGui_ImplOSX_HandleEvent() from backend API in favor of backend
automatically handling event capture. Examples that are using the OSX backend have removed
all the now-unnecessary calls to ImGui_ImplOSX_HandleEvent(), applications can do as well.
[@stuartcarnie] (#4821)
Other Changes: Other Changes:
@ -105,6 +109,7 @@ Other Changes:
- Backends: OSX, Metal: Store backend data in a per-context struct, allowing to use these backends with - Backends: OSX, Metal: Store backend data in a per-context struct, allowing to use these backends with
multiple contexts. (#5203, #5221, #4141) [@noisewuwei] multiple contexts. (#5203, #5221, #4141) [@noisewuwei]
- Examples: Emscripten+WebGPU: Fix building for latest WebGPU specs. (#3632) - Examples: Emscripten+WebGPU: Fix building for latest WebGPU specs. (#3632)
- Examples: OSX+Metal, OSX+OpenGL: Removed now-unnecessary calls to ImGui_ImplOSX_HandleEvent(). (#4821)
----------------------------------------------------------------------- -----------------------------------------------------------------------

View File

@ -17,7 +17,7 @@
#include "imgui_impl_metal.h" #include "imgui_impl_metal.h"
#if TARGET_OS_OSX #if TARGET_OS_OSX
#include "imgui_impl_osx.h" #include "imgui_impl_osx.h"
@interface AppViewController : NSViewController @interface AppViewController : NSViewController<NSWindowDelegate>
@end @end
#else #else
@interface AppViewController : UIViewController @interface AppViewController : UIViewController
@ -100,15 +100,8 @@
self.mtkView.delegate = self; self.mtkView.delegate = self;
#if TARGET_OS_OSX #if TARGET_OS_OSX
// Add a tracking area in order to receive mouse events whenever the mouse is within the bounds of our view
NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect
options:NSTrackingMouseMoved | NSTrackingInVisibleRect | NSTrackingActiveAlways
owner:self
userInfo:nil];
[self.view addTrackingArea:trackingArea];
ImGui_ImplOSX_Init(self.view); ImGui_ImplOSX_Init(self.view);
[NSApp activateIgnoringOtherApps:YES];
#endif #endif
} }
@ -209,20 +202,18 @@
#if TARGET_OS_OSX #if TARGET_OS_OSX
// Forward Mouse events to Dear ImGui OSX backend. - (void)viewWillAppear
-(void)mouseDown:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); } {
-(void)rightMouseDown:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); } [super viewWillAppear];
-(void)otherMouseDown:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); } self.view.window.delegate = self;
-(void)mouseUp:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); } }
-(void)rightMouseUp:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); }
-(void)otherMouseUp:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); } - (void)windowWillClose:(NSNotification *)notification
-(void)mouseMoved:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); } {
-(void)mouseDragged:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); } ImGui_ImplMetal_Shutdown();
-(void)rightMouseMoved:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); } ImGui_ImplOSX_Shutdown();
-(void)rightMouseDragged:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); } ImGui::DestroyContext();
-(void)otherMouseMoved:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); } }
-(void)otherMouseDragged:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); }
-(void)scrollWheel:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); }
#else #else
@ -286,9 +277,8 @@
backing:NSBackingStoreBuffered backing:NSBackingStoreBuffered
defer:NO]; defer:NO];
self.window.contentViewController = rootViewController; self.window.contentViewController = rootViewController;
[self.window orderFront:self];
[self.window center]; [self.window center];
[self.window becomeKeyWindow]; [self.window makeKeyAndOrderFront:self];
} }
return self; return self;
} }

View File

@ -142,26 +142,6 @@
-(void)animationTimerFired:(NSTimer*)timer { [self setNeedsDisplay:YES]; } -(void)animationTimerFired:(NSTimer*)timer { [self setNeedsDisplay:YES]; }
-(void)dealloc { animationTimer = nil; } -(void)dealloc { animationTimer = nil; }
//-----------------------------------------------------------------------------------
// Input processing
//-----------------------------------------------------------------------------------
// Forward Mouse/Keyboard events to Dear ImGui OSX backend.
// Other events are registered via addLocalMonitorForEventsMatchingMask()
-(void)mouseDown:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); }
-(void)rightMouseDown:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); }
-(void)otherMouseDown:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); }
-(void)mouseUp:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); }
-(void)rightMouseUp:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); }
-(void)otherMouseUp:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); }
-(void)mouseMoved:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); }
-(void)mouseDragged:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); }
-(void)rightMouseMoved:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); }
-(void)rightMouseDragged:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); }
-(void)otherMouseMoved:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); }
-(void)otherMouseDragged:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); }
-(void)scrollWheel:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); }
@end @end
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------

View File

@ -386,6 +386,7 @@ CODE
When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
You can read releases logs https://github.com/ocornut/imgui/releases for more details. You can read releases logs https://github.com/ocornut/imgui/releases for more details.
- 2022/05/03 (1.88) - backends: osx: removed ImGui_ImplOSX_HandleEvent() from backend API in favor of backend automatically handling event capture. All ImGui_ImplOSX_HandleEvent() calls should be removed as they are now unnecessary.
- 2022/04/05 (1.88) - inputs: renamed ImGuiKeyModFlags to ImGuiModFlags. Kept inline redirection enums (will obsolete). This was never used in public API functions but technically present in imgui.h and ImGuiIO. - 2022/04/05 (1.88) - inputs: renamed ImGuiKeyModFlags to ImGuiModFlags. Kept inline redirection enums (will obsolete). This was never used in public API functions but technically present in imgui.h and ImGuiIO.
- 2022/01/20 (1.87) - inputs: reworded gamepad IO. - 2022/01/20 (1.87) - inputs: reworded gamepad IO.
- Backend writing to io.NavInputs[] -> backend should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values. - Backend writing to io.NavInputs[] -> backend should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values.