Backends: OSX: Fix keys remaining stuck in pressed state when CMD-tabbing to a different application. (#3832)
diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm
index 62bba02..354501e 100644
--- a/backends/imgui_impl_osx.mm
+++ b/backends/imgui_impl_osx.mm
@@ -18,6 +18,7 @@
 
 // CHANGELOG
 // (minor and older changes stripped away, please see git history for details)
+//  2021-04-19: Inputs: Added a fix for keys remaining stuck in pressed state when CMD-tabbing into different application.
 //  2021-01-27: Inputs: Added a fix for mouse position not being reported when mouse buttons other than left one are down.
 //  2020-10-28: Inputs: Added a fix for handling keypad-enter key.
 //  2020-05-25: Inputs: Added a fix for missing trackpad clicks when done with "soft tap".
@@ -30,12 +31,15 @@
 //  2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
 //  2018-07-07: Initial version.
 
+@class ImFocusObserver;
+
 // Data
 static CFAbsoluteTime g_Time = 0.0;
 static NSCursor*      g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
 static bool           g_MouseCursorHidden = false;
 static bool           g_MouseJustPressed[ImGuiMouseButton_COUNT] = {};
 static bool           g_MouseDown[ImGuiMouseButton_COUNT] = {};
+static ImFocusObserver* g_FocusObserver = NULL;
 
 // Undocumented methods for creating cursors.
 @interface NSCursor()
@@ -45,6 +49,31 @@
 + (id)_windowResizeEastWestCursor;
 @end
 
+static void resetKeys()
+{
+    ImGuiIO& io = ImGui::GetIO();
+    memset(io.KeysDown, 0, sizeof(io.KeysDown));
+    io.KeyCtrl = io.KeyShift = io.KeyAlt = io.KeySuper = false;
+}
+
+@interface ImFocusObserver : NSObject
+
+- (void)onApplicationBecomeInactive:(NSNotification*)aNotification;
+
+@end
+
+@implementation ImFocusObserver
+
+- (void)onApplicationBecomeInactive:(NSNotification*)aNotification
+{
+    // Unfocused applications do not receive input events, therefore we must manually
+    // release any pressed keys when application loses focus, otherwise they would remain
+    // stuck in a pressed state. https://github.com/ocornut/imgui/issues/3832
+    resetKeys();
+}
+
+@end
+
 // Functions
 bool ImGui_ImplOSX_Init()
 {
@@ -123,11 +152,18 @@
         return s_clipboard.Data;
     };
 
+    g_FocusObserver = [[ImFocusObserver alloc] init];
+    [[NSNotificationCenter defaultCenter] addObserver:g_FocusObserver
+                                             selector:@selector(onApplicationBecomeInactive:)
+                                                 name:NSApplicationDidResignActiveNotification
+                                               object:nil];
+
     return true;
 }
 
 void ImGui_ImplOSX_Shutdown()
 {
+    g_FocusObserver = NULL;
 }
 
 static void ImGui_ImplOSX_UpdateMouseCursorAndButtons()
@@ -200,13 +236,6 @@
     return -1;
 }
 
-static void resetKeys()
-{
-    ImGuiIO& io = ImGui::GetIO();
-    for (int n = 0; n < IM_ARRAYSIZE(io.KeysDown); n++)
-        io.KeysDown[n] = false;
-}
-
 bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view)
 {
     ImGuiIO& io = ImGui::GetIO();
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index acd86b9..56686f2 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -64,6 +64,7 @@
   effectively fixing mouse access on Raspberry Pi. (#2837, #3950) [@lethal-guitar, @hinxx]
 - Backends: Win32: Clearing keyboard down array when losing focus (WM_KILLFOCUS). (#2062, #3532, #3961)
   [@1025798851]
+- Backends: OSX: Fix keys remaining stuck when CMD-tabbing to a different application. (#3832) [@rokups]
 - Backends: DirectX9: calling IDirect3DStateBlock9::Capture() after CreateStateBlock() which appears to
   workaround/fix state restoring issues. Unknown exactly why so, but bit of a cargo-cult fix. (#3857)
 - Backends: DirectX10, DirectX11: fixed a crash when backing/restoring state if nothing is bound when