Backends: OSX: Add Game Controller support. (#4759)
diff --git a/backends/imgui_impl_osx.h b/backends/imgui_impl_osx.h
index e4c1d04..c223c2c 100644
--- a/backends/imgui_impl_osx.h
+++ b/backends/imgui_impl_osx.h
@@ -5,6 +5,7 @@
 // Implemented features:
 //  [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
 //  [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend).
+//  [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
 // Issues:
 //  [ ] Platform: Keys are all generally very broken. Best using [event keycode] and not [event characters]..
 
diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm
index 97555e6..0c1b3de 100644
--- a/backends/imgui_impl_osx.mm
+++ b/backends/imgui_impl_osx.mm
@@ -5,6 +5,7 @@
 // Implemented features:
 //  [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
 //  [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend).
+//  [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
 // Issues:
 //  [ ] Platform: Keys are all generally very broken. Best using [event keycode] and not [event characters]..
 
@@ -17,9 +18,11 @@
 #include "imgui_impl_osx.h"
 #import <Cocoa/Cocoa.h>
 #include <mach/mach_time.h>
+#import <GameController/GameController.h>
 
 // CHANGELOG
 // (minor and older changes stripped away, please see git history for details)
+//  2021-12-13: Add game controller support.
 //  2021-09-21: Use mach_absolute_time as CFAbsoluteTimeGetCurrent can jump backwards.
 //  2021-08-17: Calling io.AddFocusEvent() on NSApplicationDidBecomeActiveNotification/NSApplicationDidResignActiveNotification events.
 //  2021-06-23: Inputs: Added a fix for shortcuts using CTRL key instead of CMD key.
@@ -234,6 +237,50 @@
     }
 }
 
+void ImGui_ImplOSX_UpdateGamepads()
+{
+    ImGuiIO& io = ImGui::GetIO();
+    memset(io.NavInputs, 0, sizeof(io.NavInputs));
+    if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
+        return;
+
+    GCController* controller;
+    if (@available(macOS 11.0, *))
+        controller = GCController.current;
+    else
+        controller = GCController.controllers.firstObject;
+
+    if (controller == nil || controller.extendedGamepad == nil)
+    {
+        io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
+        return;
+    }
+
+    GCExtendedGamepad* gp = controller.extendedGamepad;
+
+#define MAP_BUTTON(NAV_NO, NAME) { io.NavInputs[NAV_NO] = gp.NAME.isPressed ? 1.0 : 0.0; }
+    MAP_BUTTON(ImGuiNavInput_Activate, buttonA);
+    MAP_BUTTON(ImGuiNavInput_Cancel, buttonB);
+    MAP_BUTTON(ImGuiNavInput_Menu, buttonX);
+    MAP_BUTTON(ImGuiNavInput_Input, buttonY);
+    MAP_BUTTON(ImGuiNavInput_DpadLeft, dpad.left);
+    MAP_BUTTON(ImGuiNavInput_DpadRight, dpad.right);
+    MAP_BUTTON(ImGuiNavInput_DpadUp, dpad.up);
+    MAP_BUTTON(ImGuiNavInput_DpadDown, dpad.down);
+    MAP_BUTTON(ImGuiNavInput_FocusPrev, leftShoulder);
+    MAP_BUTTON(ImGuiNavInput_FocusNext, rightShoulder);
+    MAP_BUTTON(ImGuiNavInput_TweakSlow, leftTrigger);
+    MAP_BUTTON(ImGuiNavInput_TweakFast, rightTrigger);
+#undef MAP_BUTTON
+
+    io.NavInputs[ImGuiNavInput_LStickLeft] = gp.leftThumbstick.left.value;
+    io.NavInputs[ImGuiNavInput_LStickRight] = gp.leftThumbstick.right.value;
+    io.NavInputs[ImGuiNavInput_LStickUp] = gp.leftThumbstick.up.value;
+    io.NavInputs[ImGuiNavInput_LStickDown] = gp.leftThumbstick.down.value;
+
+    io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
+}
+
 void ImGui_ImplOSX_NewFrame(NSView* view)
 {
     // Setup display size
@@ -256,6 +303,7 @@
     g_Time = current_time;
 
     ImGui_ImplOSX_UpdateMouseCursorAndButtons();
+    ImGui_ImplOSX_UpdateGamepads();
 }
 
 static int mapCharacterToKey(int c)
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index bc72a06..6af83a6 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -103,6 +103,7 @@
 - Backends: DX12: Fixed DRAW_EMPTY_SCISSOR_RECTANGLE warnings. (#4775)
 - Backends: SDL_Renderer: Added support for large meshes (64k+ vertices) with 16-bit indices,
   enabling 'ImGuiBackendFlags_RendererHasVtxOffset' in the backend. (#3926) [@rokups]
+- Backends: OSX: Add Game Controller support (need linking GameController framework) (#4759) [@stuartcarnie]
 - Backends: WebGPU: Passing explicit buffer sizes to wgpuRenderPassEncoderSetVertexBuffer() and
   wgpuRenderPassEncoderSetIndexBuffer() functions as validation layers appears to not do what the
   in-flux specs says. (#4766) [@meshula]
diff --git a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj
index 040fcd6..4bb4fc2 100644
--- a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj
+++ b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj
@@ -7,6 +7,7 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05318E0E274C397200A8DE2E /* GameController.framework */; };
 		07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; };
 		07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; };
 		5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; };
@@ -32,6 +33,7 @@
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
+		05318E0E274C397200A8DE2E /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; };
 		07A82ED62139413C0078D120 /* imgui_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_internal.h; path = ../../imgui_internal.h; sourceTree = "<group>"; };
 		07A82ED72139413C0078D120 /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = ../../imgui_widgets.cpp; sourceTree = "<group>"; };
 		5079822D257677DB0038A28D /* imgui_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_tables.cpp; path = ../../imgui_tables.cpp; sourceTree = "<group>"; };
@@ -76,6 +78,7 @@
 			files = (
 				8309BDC6253CCCFE0045E2A1 /* AppKit.framework in Frameworks */,
 				83BBE9EC20EB471700295997 /* MetalKit.framework in Frameworks */,
+				05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */,
 				83BBE9ED20EB471700295997 /* Metal.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -133,6 +136,7 @@
 		83BBE9E320EB46B800295997 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				05318E0E274C397200A8DE2E /* GameController.framework */,
 				8309BDC5253CCCFE0045E2A1 /* AppKit.framework */,
 				8309BD8E253CCAAA0045E2A1 /* UIKit.framework */,
 				83BBE9EE20EB471C00295997 /* ModelIO.framework */,
diff --git a/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj b/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj
index 82fb267..a168373 100644
--- a/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj
+++ b/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj
@@ -7,6 +7,7 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		05E31B59274EF0700083FCB6 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05E31B57274EF0360083FCB6 /* GameController.framework */; };
 		07A82EDB213941D00078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82EDA213941D00078D120 /* imgui_widgets.cpp */; };
 		4080A99820B02D340036BA46 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4080A98A20B02CD90036BA46 /* main.mm */; };
 		4080A9A220B034280036BA46 /* imgui_impl_opengl2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4080A99E20B034280036BA46 /* imgui_impl_opengl2.cpp */; };
@@ -32,6 +33,7 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+		05E31B57274EF0360083FCB6 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; };
 		07A82EDA213941D00078D120 /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = ../../imgui_widgets.cpp; sourceTree = "<group>"; };
 		4080A96B20B029B00036BA46 /* example_osx_opengl2 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = example_osx_opengl2; sourceTree = BUILT_PRODUCTS_DIR; };
 		4080A98A20B02CD90036BA46 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = SOURCE_ROOT; };
@@ -57,6 +59,7 @@
 			files = (
 				4080A9B520B034EA0036BA46 /* OpenGL.framework in Frameworks */,
 				4080A9B320B034E40036BA46 /* Cocoa.framework in Frameworks */,
+				05E31B59274EF0700083FCB6 /* GameController.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -95,6 +98,7 @@
 		4080A9B120B034E40036BA46 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				05E31B57274EF0360083FCB6 /* GameController.framework */,
 				4080A9B420B034EA0036BA46 /* OpenGL.framework */,
 				4080A9B220B034E40036BA46 /* Cocoa.framework */,
 			);