Sfoglia il codice sorgente

Merge pull request #4224 from aws-lumberyard-dev/burelc/restructureXcbCode

Consolidate all xcb functionality into one subdirectory
Steve Pham 4 anni fa
parent
commit
c75e6860bb
20 ha cambiato i file con 565 aggiunte e 440 eliminazioni
  1. 2 2
      Code/Editor/Core/QtEditorApplication_linux.cpp
  2. 1 1
      Code/Framework/AzFramework/CMakeLists.txt
  3. 20 25
      Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbApplication.cpp
  4. 7 13
      Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbApplication.h
  5. 42 0
      Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbConnectionManager.h
  6. 40 0
      Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbEventHandler.h
  7. 271 0
      Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp
  8. 46 0
      Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.h
  9. 38 0
      Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInterface.h
  10. 22 29
      Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp
  11. 9 10
      Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.h
  12. 18 0
      Code/Framework/AzFramework/Platform/Common/Xcb/azframework_xcb_files.cmake
  13. 0 54
      Code/Framework/AzFramework/Platform/Linux/AzFramework/API/ApplicationAPI_Linux.h
  14. 4 2
      Code/Framework/AzFramework/Platform/Linux/AzFramework/Application/Application_Linux.cpp
  15. 27 0
      Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_Linux.cpp
  16. 0 293
      Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_xcb.cpp
  17. 4 3
      Code/Framework/AzFramework/Platform/Linux/AzFramework/Windowing/NativeWindow_Linux.cpp
  18. 8 2
      Code/Framework/AzFramework/Platform/Linux/platform_linux.cmake
  19. 1 5
      Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake
  20. 5 1
      Gems/Atom/RHI/Vulkan/Code/Source/Platform/Linux/RHI/WSISurface_Linux.cpp

+ 2 - 2
Code/Editor/Core/QtEditorApplication_linux.cpp

@@ -9,7 +9,7 @@
 #include "QtEditorApplication.h"
 
 #ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-#include <AzFramework/API/ApplicationAPI_Linux.h>
+#include <AzFramework/XcbEventHandler.h>
 #endif
 
 namespace Editor
@@ -19,7 +19,7 @@ namespace Editor
         if (GetIEditor()->IsInGameMode())
         {
 #ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-            AzFramework::LinuxXcbEventHandlerBus::Broadcast(&AzFramework::LinuxXcbEventHandler::HandleXcbEvent, static_cast<xcb_generic_event_t*>(message));
+            AzFramework::XcbEventHandlerBus::Broadcast(&AzFramework::XcbEventHandler::HandleXcbEvent, static_cast<xcb_generic_event_t*>(message));
 #endif
             return true;
         }

+ 1 - 1
Code/Framework/AzFramework/CMakeLists.txt

@@ -95,4 +95,4 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
 
     endif()
 
-endif()
+endif()

+ 20 - 25
Code/Framework/AzFramework/Platform/Linux/AzFramework/Application/Application_Linux_xcb.cpp → Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbApplication.cpp

@@ -6,29 +6,26 @@
  *
  */
 
-#include <AzFramework/API/ApplicationAPI_Platform.h>
-#include <AzFramework/Application/Application.h>
-#include "Application_Linux_xcb.h"
+#include <AzFramework/XcbApplication.h>
+#include <AzFramework/XcbEventHandler.h>
 
-////////////////////////////////////////////////////////////////////////////////////////////////////
 namespace AzFramework
 {
-#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    class LinuxXcbConnectionManagerImpl
-        : public LinuxXcbConnectionManagerBus::Handler
+    class XcbConnectionManagerImpl
+        : public XcbConnectionManagerBus::Handler
     {
     public:
-        LinuxXcbConnectionManagerImpl()
+        XcbConnectionManagerImpl()
         {
             m_xcbConnection = xcb_connect(nullptr, nullptr);
-            AZ_Error("ApplicationLinux", m_xcbConnection != nullptr, "Unable to connect to X11 Server.");
-            LinuxXcbConnectionManagerBus::Handler::BusConnect();
+            AZ_Error("Application", m_xcbConnection != nullptr, "Unable to connect to X11 Server.");
+            XcbConnectionManagerBus::Handler::BusConnect();
         }
 
-        ~LinuxXcbConnectionManagerImpl()
+        ~XcbConnectionManagerImpl() override
         {
-            LinuxXcbConnectionManagerBus::Handler::BusDisconnect();
+            XcbConnectionManagerBus::Handler::BusDisconnect();
             xcb_disconnect(m_xcbConnection);   
         }
 
@@ -42,53 +39,51 @@ namespace AzFramework
     };
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    ApplicationLinux_xcb::ApplicationLinux_xcb()
+    XcbApplication::XcbApplication()
     {
         LinuxLifecycleEvents::Bus::Handler::BusConnect();
-        m_xcbConnectionManager = AZStd::make_unique<LinuxXcbConnectionManagerImpl>();
-        if (LinuxXcbConnectionManagerInterface::Get() == nullptr)
+        m_xcbConnectionManager = AZStd::make_unique<XcbConnectionManagerImpl>();
+        if (XcbConnectionManagerInterface::Get() == nullptr)
         {
-            LinuxXcbConnectionManagerInterface::Register(m_xcbConnectionManager.get());
+            XcbConnectionManagerInterface::Register(m_xcbConnectionManager.get());
         }
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    ApplicationLinux_xcb::~ApplicationLinux_xcb()
+    XcbApplication::~XcbApplication()
     {
-        if (LinuxXcbConnectionManagerInterface::Get() == m_xcbConnectionManager.get())
+        if (XcbConnectionManagerInterface::Get() == m_xcbConnectionManager.get())
         {
-            LinuxXcbConnectionManagerInterface::Unregister(m_xcbConnectionManager.get());
+            XcbConnectionManagerInterface::Unregister(m_xcbConnectionManager.get());
         }
         m_xcbConnectionManager.reset();
         LinuxLifecycleEvents::Bus::Handler::BusDisconnect();
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    void ApplicationLinux_xcb::PumpSystemEventLoopOnce()
+    void XcbApplication::PumpSystemEventLoopOnce()
     {
         if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection())
         {
             if (xcb_generic_event_t* event = xcb_poll_for_event(xcbConnection))
             {
-                LinuxXcbEventHandlerBus::Broadcast(&LinuxXcbEventHandlerBus::Events::HandleXcbEvent, event);
+                XcbEventHandlerBus::Broadcast(&XcbEventHandlerBus::Events::HandleXcbEvent, event);
                 free(event);
             }
         }
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    void ApplicationLinux_xcb::PumpSystemEventLoopUntilEmpty()
+    void XcbApplication::PumpSystemEventLoopUntilEmpty()
     {
         if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection())
         {
             while (xcb_generic_event_t* event = xcb_poll_for_event(xcbConnection))
             {
-                LinuxXcbEventHandlerBus::Broadcast(&LinuxXcbEventHandlerBus::Events::HandleXcbEvent, event);
+                XcbEventHandlerBus::Broadcast(&XcbEventHandlerBus::Events::HandleXcbEvent, event);
                 free(event);
             }
         }
     }
 
-#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB        
-
 } // namespace AzFramework

+ 7 - 13
Code/Framework/AzFramework/Platform/Linux/AzFramework/Application/Application_Linux_xcb.h → Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbApplication.h

@@ -5,27 +5,24 @@
  * SPDX-License-Identifier: Apache-2.0 OR MIT
  *
  */
+
 #pragma once
 
 #include <AzFramework/API/ApplicationAPI_Platform.h>
 #include <AzFramework/Application/Application.h>
+#include <AzFramework/XcbConnectionManager.h>
 
-////////////////////////////////////////////////////////////////////////////////////////////////////
 namespace AzFramework
 {
-
-#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-
-    ////////////////////////////////////////////////////////////////////////////////////////////////
-    class ApplicationLinux_xcb
+    class XcbApplication
         : public Application::Implementation
         , public LinuxLifecycleEvents::Bus::Handler
     {
     public:
         ////////////////////////////////////////////////////////////////////////////////////////////
-        AZ_CLASS_ALLOCATOR(ApplicationLinux_xcb, AZ::SystemAllocator, 0);
-        ApplicationLinux_xcb();
-        ~ApplicationLinux_xcb() override;
+        AZ_CLASS_ALLOCATOR(XcbApplication, AZ::SystemAllocator, 0);
+        XcbApplication();
+        ~XcbApplication() override;
 
         ////////////////////////////////////////////////////////////////////////////////////////////
         // Application::Implementation
@@ -33,9 +30,6 @@ namespace AzFramework
         void PumpSystemEventLoopUntilEmpty() override;
 
     private:
-        AZStd::unique_ptr<LinuxXcbConnectionManager>    m_xcbConnectionManager;
+        AZStd::unique_ptr<XcbConnectionManager> m_xcbConnectionManager;
     };
-
-#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-
 } // namespace AzFramework

+ 42 - 0
Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbConnectionManager.h

@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <AzCore/EBus/EBus.h>
+#include <AzCore/Interface/Interface.h>
+#include <AzCore/RTTI/RTTI.h>
+
+#include <xcb/xcb.h>
+
+namespace AzFramework
+{
+    class XcbConnectionManager
+    {
+    public:
+        AZ_RTTI(XcbConnectionManager, "{1F756E14-8D74-42FD-843C-4863307710DB}");
+
+        virtual ~XcbConnectionManager() = default;
+
+        virtual xcb_connection_t* GetXcbConnection() const = 0;
+    };
+
+    class XcbConnectionManagerBusTraits
+        : public AZ::EBusTraits
+    {
+    public:
+        //////////////////////////////////////////////////////////////////////////
+        // EBusTraits overrides
+        static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
+        static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
+        //////////////////////////////////////////////////////////////////////////
+    };
+
+    using XcbConnectionManagerBus = AZ::EBus<XcbConnectionManager, XcbConnectionManagerBusTraits>;
+    using XcbConnectionManagerInterface = AZ::Interface<XcbConnectionManager>;
+} // namespace AzFramework

+ 40 - 0
Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbEventHandler.h

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <AzCore/EBus/EBus.h>
+#include <AzCore/RTTI/RTTI.h>
+
+#include <xcb/xcb.h>
+
+namespace AzFramework
+{
+    class XcbEventHandler
+    {
+    public:
+        AZ_RTTI(XcbEventHandler, "{3F756E14-8D74-42FD-843C-4863307710DB}");
+
+        virtual ~XcbEventHandler() = default;
+
+        virtual void HandleXcbEvent(xcb_generic_event_t* event) = 0;
+    };
+
+    class XcbEventHandlerBusTraits
+        : public AZ::EBusTraits
+    {
+    public:
+        //////////////////////////////////////////////////////////////////////////
+        // EBusTraits overrides
+        static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
+        static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
+        //////////////////////////////////////////////////////////////////////////
+    };
+
+    using XcbEventHandlerBus = AZ::EBus<XcbEventHandler, XcbEventHandlerBusTraits>;
+} // namespace AzFramework

+ 271 - 0
Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp

@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
+#include <AzFramework/XcbEventHandler.h>
+#include <AzFramework/XcbConnectionManager.h>
+#include <AzFramework/XcbInputDeviceKeyboard.h>
+
+#define explicit ExplicitIsACXXKeyword
+#include <xcb/xkb.h>
+#undef explicit
+#include <xkbcommon/xkbcommon-keysyms.h>
+#include <xkbcommon/xkbcommon.h>
+#include <xkbcommon/xkbcommon-x11.h>
+
+namespace AzFramework
+{
+    XcbInputDeviceKeyboard::XcbInputDeviceKeyboard(InputDeviceKeyboard& inputDevice)
+        : InputDeviceKeyboard::Implementation(inputDevice)
+    {
+        XcbEventHandlerBus::Handler::BusConnect();
+
+        auto* interface = AzFramework::XcbConnectionManagerInterface::Get();
+        if (!interface)
+        {
+            AZ_Warning("ApplicationLinux", false, "XCB interface not available");
+            return;
+        }
+
+        auto* connection = interface->GetXcbConnection();
+        if (!connection)
+        {
+            AZ_Warning("ApplicationLinux", false, "XCB connection not available");
+            return;
+        }
+
+        XcbStdFreePtr<xcb_xkb_use_extension_reply_t> xkbUseExtensionReply{
+            xcb_xkb_use_extension_reply(connection, xcb_xkb_use_extension(connection, 1, 0), nullptr)
+        };
+        if (!xkbUseExtensionReply)
+        {
+            AZ_Warning("ApplicationLinux", false, "Failed to initialize the xkb extension");
+            return;
+        }
+        if (!xkbUseExtensionReply->supported)
+        {
+            AZ_Warning("ApplicationLinux", false, "The X server does not support the xkb extension");
+            return;
+        }
+
+        m_coreDeviceId = xkb_x11_get_core_keyboard_device_id(connection);
+
+        m_xkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
+        m_xkbKeymap.reset(xkb_x11_keymap_new_from_device(m_xkbContext.get(), connection, m_coreDeviceId, XKB_KEYMAP_COMPILE_NO_FLAGS));
+        m_xkbState.reset(xkb_x11_state_new_from_device(m_xkbKeymap.get(), connection, m_coreDeviceId));
+
+        m_initialized = true;
+    }
+
+    bool XcbInputDeviceKeyboard::IsConnected() const
+    {
+        auto* connection = AzFramework::XcbConnectionManagerInterface::Get()->GetXcbConnection();
+        return connection && !xcb_connection_has_error(connection);
+    }
+
+    bool XcbInputDeviceKeyboard::HasTextEntryStarted() const
+    {
+        return false;
+    }
+
+    void XcbInputDeviceKeyboard::TextEntryStart(const InputDeviceKeyboard::VirtualKeyboardOptions& options)
+    {
+    }
+
+    void XcbInputDeviceKeyboard::TextEntryStop()
+    {
+    }
+
+    void XcbInputDeviceKeyboard::TickInputDevice()
+    {
+        ProcessRawEventQueues();
+    }
+
+    void XcbInputDeviceKeyboard::HandleXcbEvent(xcb_generic_event_t* event)
+    {
+        if (!m_initialized)
+        {
+            return;
+        }
+
+        switch (event->response_type & ~0x80)
+        {
+        case XCB_KEY_PRESS:
+        {
+            auto* keyPress = reinterpret_cast<xcb_key_press_event_t*>(event);
+
+            const InputChannelId* key = InputChannelFromKeyEvent(keyPress->detail);
+            if (key)
+            {
+                QueueRawKeyEvent(*key, true);
+            }
+            break;
+        }
+        case XCB_KEY_RELEASE:
+        {
+            auto* keyRelease = reinterpret_cast<xcb_key_release_event_t*>(event);
+
+            const InputChannelId* key = InputChannelFromKeyEvent(keyRelease->detail);
+            if (key)
+            {
+                QueueRawKeyEvent(*key, false);
+            }
+            break;
+        }
+        }
+    }
+
+    [[nodiscard]] const InputChannelId* XcbInputDeviceKeyboard::InputChannelFromKeyEvent(xcb_keycode_t code) const
+    {
+        const xcb_keysym_t keysym = xkb_state_key_get_one_sym(m_xkbState.get(), code);
+
+        switch(keysym)
+        {
+            case XKB_KEY_0: return &InputDeviceKeyboard::Key::Alphanumeric0;
+            case XKB_KEY_1: return &InputDeviceKeyboard::Key::Alphanumeric1;
+            case XKB_KEY_2: return &InputDeviceKeyboard::Key::Alphanumeric2;
+            case XKB_KEY_3: return &InputDeviceKeyboard::Key::Alphanumeric3;
+            case XKB_KEY_4: return &InputDeviceKeyboard::Key::Alphanumeric4;
+            case XKB_KEY_5: return &InputDeviceKeyboard::Key::Alphanumeric5;
+            case XKB_KEY_6: return &InputDeviceKeyboard::Key::Alphanumeric6;
+            case XKB_KEY_7: return &InputDeviceKeyboard::Key::Alphanumeric7;
+            case XKB_KEY_8: return &InputDeviceKeyboard::Key::Alphanumeric8;
+            case XKB_KEY_9: return &InputDeviceKeyboard::Key::Alphanumeric9;
+            case XKB_KEY_A:
+            case XKB_KEY_a: return &InputDeviceKeyboard::Key::AlphanumericA;
+            case XKB_KEY_B:
+            case XKB_KEY_b: return &InputDeviceKeyboard::Key::AlphanumericB;
+            case XKB_KEY_C:
+            case XKB_KEY_c: return &InputDeviceKeyboard::Key::AlphanumericC;
+            case XKB_KEY_D:
+            case XKB_KEY_d: return &InputDeviceKeyboard::Key::AlphanumericD;
+            case XKB_KEY_E:
+            case XKB_KEY_e: return &InputDeviceKeyboard::Key::AlphanumericE;
+            case XKB_KEY_F:
+            case XKB_KEY_f: return &InputDeviceKeyboard::Key::AlphanumericF;
+            case XKB_KEY_G:
+            case XKB_KEY_g: return &InputDeviceKeyboard::Key::AlphanumericG;
+            case XKB_KEY_H:
+            case XKB_KEY_h: return &InputDeviceKeyboard::Key::AlphanumericH;
+            case XKB_KEY_I:
+            case XKB_KEY_i: return &InputDeviceKeyboard::Key::AlphanumericI;
+            case XKB_KEY_J:
+            case XKB_KEY_j: return &InputDeviceKeyboard::Key::AlphanumericJ;
+            case XKB_KEY_K:
+            case XKB_KEY_k: return &InputDeviceKeyboard::Key::AlphanumericK;
+            case XKB_KEY_L:
+            case XKB_KEY_l: return &InputDeviceKeyboard::Key::AlphanumericL;
+            case XKB_KEY_M:
+            case XKB_KEY_m: return &InputDeviceKeyboard::Key::AlphanumericM;
+            case XKB_KEY_N:
+            case XKB_KEY_n: return &InputDeviceKeyboard::Key::AlphanumericN;
+            case XKB_KEY_O:
+            case XKB_KEY_o: return &InputDeviceKeyboard::Key::AlphanumericO;
+            case XKB_KEY_P:
+            case XKB_KEY_p: return &InputDeviceKeyboard::Key::AlphanumericP;
+            case XKB_KEY_Q:
+            case XKB_KEY_q: return &InputDeviceKeyboard::Key::AlphanumericQ;
+            case XKB_KEY_R:
+            case XKB_KEY_r: return &InputDeviceKeyboard::Key::AlphanumericR;
+            case XKB_KEY_S:
+            case XKB_KEY_s: return &InputDeviceKeyboard::Key::AlphanumericS;
+            case XKB_KEY_T:
+            case XKB_KEY_t: return &InputDeviceKeyboard::Key::AlphanumericT;
+            case XKB_KEY_U:
+            case XKB_KEY_u: return &InputDeviceKeyboard::Key::AlphanumericU;
+            case XKB_KEY_V:
+            case XKB_KEY_v: return &InputDeviceKeyboard::Key::AlphanumericV;
+            case XKB_KEY_W:
+            case XKB_KEY_w: return &InputDeviceKeyboard::Key::AlphanumericW;
+            case XKB_KEY_X:
+            case XKB_KEY_x: return &InputDeviceKeyboard::Key::AlphanumericX;
+            case XKB_KEY_Y:
+            case XKB_KEY_y: return &InputDeviceKeyboard::Key::AlphanumericY;
+            case XKB_KEY_Z:
+            case XKB_KEY_z: return &InputDeviceKeyboard::Key::AlphanumericZ;
+            case XKB_KEY_BackSpace: return &InputDeviceKeyboard::Key::EditBackspace;
+            case XKB_KEY_Caps_Lock: return &InputDeviceKeyboard::Key::EditCapsLock;
+            case XKB_KEY_Return: return &InputDeviceKeyboard::Key::EditEnter;
+            case XKB_KEY_space: return &InputDeviceKeyboard::Key::EditSpace;
+            case XKB_KEY_Tab: return &InputDeviceKeyboard::Key::EditTab;
+            case XKB_KEY_Escape: return &InputDeviceKeyboard::Key::Escape;
+            case XKB_KEY_F1: return &InputDeviceKeyboard::Key::Function01;
+            case XKB_KEY_F2: return &InputDeviceKeyboard::Key::Function02;
+            case XKB_KEY_F3: return &InputDeviceKeyboard::Key::Function03;
+            case XKB_KEY_F4: return &InputDeviceKeyboard::Key::Function04;
+            case XKB_KEY_F5: return &InputDeviceKeyboard::Key::Function05;
+            case XKB_KEY_F6: return &InputDeviceKeyboard::Key::Function06;
+            case XKB_KEY_F7: return &InputDeviceKeyboard::Key::Function07;
+            case XKB_KEY_F8: return &InputDeviceKeyboard::Key::Function08;
+            case XKB_KEY_F9: return &InputDeviceKeyboard::Key::Function09;
+            case XKB_KEY_F10: return &InputDeviceKeyboard::Key::Function10;
+            case XKB_KEY_F11: return &InputDeviceKeyboard::Key::Function11;
+            case XKB_KEY_F12: return &InputDeviceKeyboard::Key::Function12;
+            case XKB_KEY_F13: return &InputDeviceKeyboard::Key::Function13;
+            case XKB_KEY_F14: return &InputDeviceKeyboard::Key::Function14;
+            case XKB_KEY_F15: return &InputDeviceKeyboard::Key::Function15;
+            case XKB_KEY_F16: return &InputDeviceKeyboard::Key::Function16;
+            case XKB_KEY_F17: return &InputDeviceKeyboard::Key::Function17;
+            case XKB_KEY_F18: return &InputDeviceKeyboard::Key::Function18;
+            case XKB_KEY_F19: return &InputDeviceKeyboard::Key::Function19;
+            case XKB_KEY_F20: return &InputDeviceKeyboard::Key::Function20;
+            case XKB_KEY_Alt_L: return &InputDeviceKeyboard::Key::ModifierAltL;
+            case XKB_KEY_Alt_R: return &InputDeviceKeyboard::Key::ModifierAltR;
+            case XKB_KEY_Control_L: return &InputDeviceKeyboard::Key::ModifierCtrlL;
+            case XKB_KEY_Control_R: return &InputDeviceKeyboard::Key::ModifierCtrlR;
+            case XKB_KEY_Shift_L: return &InputDeviceKeyboard::Key::ModifierShiftL;
+            case XKB_KEY_Shift_R: return &InputDeviceKeyboard::Key::ModifierShiftR;
+            case XKB_KEY_Super_L: return &InputDeviceKeyboard::Key::ModifierSuperL;
+            case XKB_KEY_Super_R: return &InputDeviceKeyboard::Key::ModifierSuperR;
+            case XKB_KEY_Down: return &InputDeviceKeyboard::Key::NavigationArrowDown;
+            case XKB_KEY_Left: return &InputDeviceKeyboard::Key::NavigationArrowLeft;
+            case XKB_KEY_Right: return &InputDeviceKeyboard::Key::NavigationArrowRight;
+            case XKB_KEY_Up: return &InputDeviceKeyboard::Key::NavigationArrowUp;
+            case XKB_KEY_Delete: return &InputDeviceKeyboard::Key::NavigationDelete;
+            case XKB_KEY_End: return &InputDeviceKeyboard::Key::NavigationEnd;
+            case XKB_KEY_Home: return &InputDeviceKeyboard::Key::NavigationHome;
+            case XKB_KEY_Insert: return &InputDeviceKeyboard::Key::NavigationInsert;
+            case XKB_KEY_Page_Down: return &InputDeviceKeyboard::Key::NavigationPageDown;
+            case XKB_KEY_Page_Up: return &InputDeviceKeyboard::Key::NavigationPageUp;
+            case XKB_KEY_Num_Lock: return &InputDeviceKeyboard::Key::NumLock;
+            case XKB_KEY_KP_0: return &InputDeviceKeyboard::Key::NumPad0;
+            case XKB_KEY_KP_1: return &InputDeviceKeyboard::Key::NumPad1;
+            case XKB_KEY_KP_2: return &InputDeviceKeyboard::Key::NumPad2;
+            case XKB_KEY_KP_3: return &InputDeviceKeyboard::Key::NumPad3;
+            case XKB_KEY_KP_4: return &InputDeviceKeyboard::Key::NumPad4;
+            case XKB_KEY_KP_5: return &InputDeviceKeyboard::Key::NumPad5;
+            case XKB_KEY_KP_6: return &InputDeviceKeyboard::Key::NumPad6;
+            case XKB_KEY_KP_7: return &InputDeviceKeyboard::Key::NumPad7;
+            case XKB_KEY_KP_8: return &InputDeviceKeyboard::Key::NumPad8;
+            case XKB_KEY_KP_9: return &InputDeviceKeyboard::Key::NumPad9;
+            case XKB_KEY_KP_Add: return &InputDeviceKeyboard::Key::NumPadAdd;
+            case XKB_KEY_KP_Decimal: return &InputDeviceKeyboard::Key::NumPadDecimal;
+            case XKB_KEY_KP_Divide: return &InputDeviceKeyboard::Key::NumPadDivide;
+            case XKB_KEY_KP_Enter: return &InputDeviceKeyboard::Key::NumPadEnter;
+            case XKB_KEY_KP_Multiply: return &InputDeviceKeyboard::Key::NumPadMultiply;
+            case XKB_KEY_KP_Subtract: return &InputDeviceKeyboard::Key::NumPadSubtract;
+            case XKB_KEY_apostrophe: return &InputDeviceKeyboard::Key::PunctuationApostrophe;
+            case XKB_KEY_backslash: return &InputDeviceKeyboard::Key::PunctuationBackslash;
+            case XKB_KEY_bracketleft: return &InputDeviceKeyboard::Key::PunctuationBracketL;
+            case XKB_KEY_bracketright: return &InputDeviceKeyboard::Key::PunctuationBracketR;
+            case XKB_KEY_comma: return &InputDeviceKeyboard::Key::PunctuationComma;
+            case XKB_KEY_equal: return &InputDeviceKeyboard::Key::PunctuationEquals;
+            case XKB_KEY_hyphen: return &InputDeviceKeyboard::Key::PunctuationHyphen;
+            case XKB_KEY_period: return &InputDeviceKeyboard::Key::PunctuationPeriod;
+            case XKB_KEY_semicolon: return &InputDeviceKeyboard::Key::PunctuationSemicolon;
+            case XKB_KEY_slash: return &InputDeviceKeyboard::Key::PunctuationSlash;
+            case XKB_KEY_grave:
+            case XKB_KEY_asciitilde: return &InputDeviceKeyboard::Key::PunctuationTilde;
+            case XKB_KEY_ISO_Group_Shift: return &InputDeviceKeyboard::Key::SupplementaryISO;
+            case XKB_KEY_Pause: return &InputDeviceKeyboard::Key::WindowsSystemPause;
+            case XKB_KEY_Print: return &InputDeviceKeyboard::Key::WindowsSystemPrint;
+            case XKB_KEY_Scroll_Lock: return &InputDeviceKeyboard::Key::WindowsSystemScrollLock;
+            default: return nullptr;
+        }
+    }
+} // namespace AzFramework

+ 46 - 0
Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.h

@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
+#include <AzFramework/XcbEventHandler.h>
+#include <AzFramework/XcbInterface.h>
+
+#include <xcb/xcb.h>
+#include <xkbcommon/xkbcommon.h>
+
+namespace AzFramework
+{
+    class XcbInputDeviceKeyboard
+        : public InputDeviceKeyboard::Implementation
+        , public XcbEventHandlerBus::Handler
+    {
+    public:
+        AZ_CLASS_ALLOCATOR(XcbInputDeviceKeyboard, AZ::SystemAllocator, 0);
+
+        using InputDeviceKeyboard::Implementation::Implementation;
+        XcbInputDeviceKeyboard(InputDeviceKeyboard& inputDevice);
+
+        bool IsConnected() const override;
+
+        bool HasTextEntryStarted() const override;
+        void TextEntryStart(const InputDeviceKeyboard::VirtualKeyboardOptions& options) override;
+        void TextEntryStop() override;
+        void TickInputDevice() override;
+
+        void HandleXcbEvent(xcb_generic_event_t* event) override;
+
+    private:
+        [[nodiscard]] const InputChannelId* InputChannelFromKeyEvent(xcb_keycode_t code) const;
+
+        XcbUniquePtr<xkb_context, xkb_context_unref> m_xkbContext;
+        XcbUniquePtr<xkb_keymap, xkb_keymap_unref> m_xkbKeymap;
+        XcbUniquePtr<xkb_state, xkb_state_unref> m_xkbState;
+        int m_coreDeviceId{-1};
+        bool m_initialized{false};
+    };
+} // namespace AzFramework

+ 38 - 0
Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInterface.h

@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <xcb/xcb.h>
+
+#include <AzCore/std/smart_ptr/unique_ptr.h>
+
+namespace AzFramework
+{
+    // @brief Wrap a function pointer in a type
+    // This serves as a convenient way to wrap a function pointer in a given
+    // type. That type can then be used in a `unique_ptr` or `shared_ptr`.
+    // Using a type instead of a function pointer by value prevents the need to
+    // copy the pointer when copying the smart poiner.
+    template<auto Callable>
+    struct XcbDeleterFreeFunctionWrapper
+    {
+        using value_type = decltype(Callable);
+        static constexpr value_type s_value = Callable;
+        constexpr operator value_type() const noexcept
+        {
+            return s_value;
+        }
+    };
+
+    template<typename T, auto fn>
+    using XcbUniquePtr = AZStd::unique_ptr<T, XcbDeleterFreeFunctionWrapper<fn>>;
+
+    template<typename T>
+    using XcbStdFreePtr = XcbUniquePtr<T, ::free>;
+} // namespace AzFramework

+ 22 - 29
Code/Framework/AzFramework/Platform/Linux/AzFramework/Windowing/NativeWindow_Linux_xcb.cpp → Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp

@@ -6,41 +6,37 @@
  *
  */
 
-#include <AzFramework/API/ApplicationAPI_Platform.h>
 #include <AzFramework/Application/Application.h>
 #include <AzFramework/Windowing/NativeWindow.h>
-#include <xcb/xcb.h>
+#include <AzFramework/XcbNativeWindow.h>
+#include <AzFramework/XcbConnectionManager.h>
 
-#include "NativeWindow_Linux_xcb.h"
+#include <xcb/xcb.h>
 
 namespace AzFramework
 {
-#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-
-    [[maybe_unused]] const char LinuxXcbErrorWindow[] = "NativeWindow_Linux_xcb";
+    [[maybe_unused]] const char XcbErrorWindow[] = "XcbNativeWindow";
     static constexpr uint8_t s_XcbFormatDataSize = 32;              // Format indicator for xcb for client messages
     static constexpr uint16_t s_DefaultXcbWindowBorderWidth = 4;    // The default border with in pixels if a border was specified
     static constexpr uint8_t s_XcbResponseTypeMask = 0x7f;          // Mask to extract the specific event type from an xcb event
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    NativeWindowImpl_Linux_xcb::NativeWindowImpl_Linux_xcb() 
+    XcbNativeWindow::XcbNativeWindow() 
         : NativeWindow::Implementation()
     {
-        if (auto xcbConnectionManager = AzFramework::LinuxXcbConnectionManagerInterface::Get();
+        if (auto xcbConnectionManager = AzFramework::XcbConnectionManagerInterface::Get();
             xcbConnectionManager != nullptr)
         {
             m_xcbConnection = xcbConnectionManager->GetXcbConnection();
         }
-        AZ_Error(LinuxXcbErrorWindow, m_xcbConnection != nullptr, "Unable to get XCB Connection");
+        AZ_Error(XcbErrorWindow, m_xcbConnection != nullptr, "Unable to get XCB Connection");
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    NativeWindowImpl_Linux_xcb::~NativeWindowImpl_Linux_xcb()
-    {
-    }
+    XcbNativeWindow::~XcbNativeWindow() = default;
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    void NativeWindowImpl_Linux_xcb::InitWindow(const AZStd::string& title,
+    void XcbNativeWindow::InitWindow(const AZStd::string& title,
                                                 const WindowGeometry& geometry,
                                                 const WindowStyleMasks& styleMasks)
     {
@@ -98,13 +94,13 @@ namespace AzFramework
         
         xcb_intern_atom_cookie_t cookieProtocol = xcb_intern_atom(m_xcbConnection, 1, strlen(wmProtocolString), wmProtocolString);
         xcb_intern_atom_reply_t* replyProtocol = xcb_intern_atom_reply(m_xcbConnection, cookieProtocol, nullptr);
-        AZ_Error(LinuxXcbErrorWindow, replyProtocol != nullptr, "Unable to query xcb '%s' atom", wmProtocolString);
+        AZ_Error(XcbErrorWindow, replyProtocol != nullptr, "Unable to query xcb '%s' atom", wmProtocolString);
         m_xcbAtomProtocols = replyProtocol->atom;
 
         const static char* wmDeleteWindowString = "WM_DELETE_WINDOW";
         xcb_intern_atom_cookie_t cookieDeleteWindow = xcb_intern_atom(m_xcbConnection, 0, strlen(wmDeleteWindowString), wmDeleteWindowString);
         xcb_intern_atom_reply_t* replyDeleteWindow = xcb_intern_atom_reply(m_xcbConnection, cookieDeleteWindow, nullptr);
-        AZ_Error(LinuxXcbErrorWindow, replyDeleteWindow != nullptr, "Unable to query xcb '%s' atom", wmDeleteWindowString);
+        AZ_Error(XcbErrorWindow, replyDeleteWindow != nullptr, "Unable to query xcb '%s' atom", wmDeleteWindowString);
         m_xcbAtomDeleteWindow = replyDeleteWindow->atom;
 
         xcbCheckResult = xcb_change_property_checked(m_xcbConnection, 
@@ -123,9 +119,9 @@ namespace AzFramework
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    void NativeWindowImpl_Linux_xcb::Activate()
+    void XcbNativeWindow::Activate()
     {
-        LinuxXcbEventHandlerBus::Handler::BusConnect();
+        XcbEventHandlerBus::Handler::BusConnect();
 
         if (!m_activated) // nothing to do if window was already activated
         {
@@ -137,7 +133,7 @@ namespace AzFramework
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    void NativeWindowImpl_Linux_xcb::Deactivate()
+    void XcbNativeWindow::Deactivate()
     {
         if (m_activated) // nothing to do if window was already deactivated
         {
@@ -148,17 +144,17 @@ namespace AzFramework
             xcb_unmap_window(m_xcbConnection, m_xcbWindow);
             xcb_flush(m_xcbConnection);
         }
-        LinuxXcbEventHandlerBus::Handler::BusDisconnect();
+        XcbEventHandlerBus::Handler::BusDisconnect();
     }    
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    NativeWindowHandle NativeWindowImpl_Linux_xcb::GetWindowHandle() const
+    NativeWindowHandle XcbNativeWindow::GetWindowHandle() const
     {
         return reinterpret_cast<NativeWindowHandle>(m_xcbWindow);
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    void NativeWindowImpl_Linux_xcb::SetWindowTitle(const AZStd::string& title)
+    void XcbNativeWindow::SetWindowTitle(const AZStd::string& title)
     {
         xcb_void_cookie_t xcbCheckResult;
         xcbCheckResult = xcb_change_property(m_xcbConnection,
@@ -173,7 +169,7 @@ namespace AzFramework
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    void NativeWindowImpl_Linux_xcb::ResizeClientArea(WindowSize clientAreaSize)
+    void XcbNativeWindow::ResizeClientArea(WindowSize clientAreaSize)
     {
         const uint32_t values[] = { clientAreaSize.m_width, clientAreaSize.m_height };
 
@@ -184,7 +180,7 @@ namespace AzFramework
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    uint32_t NativeWindowImpl_Linux_xcb::GetDisplayRefreshRate() const
+    uint32_t XcbNativeWindow::GetDisplayRefreshRate() const
     {
         // [GFX TODO][GHI - 2678]
         // Using 60 for now until proper support is added
@@ -192,7 +188,7 @@ namespace AzFramework
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    bool NativeWindowImpl_Linux_xcb::ValidateXcbResult(xcb_void_cookie_t cookie)
+    bool XcbNativeWindow::ValidateXcbResult(xcb_void_cookie_t cookie)
     {
         bool result = true;
         if (xcb_generic_error_t* error = xcb_request_check(m_xcbConnection, cookie))
@@ -204,7 +200,7 @@ namespace AzFramework
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    void NativeWindowImpl_Linux_xcb::HandleXcbEvent(xcb_generic_event_t* event)
+    void XcbNativeWindow::HandleXcbEvent(xcb_generic_event_t* event)
     {
         switch (event->response_type & s_XcbResponseTypeMask)
         {
@@ -233,7 +229,7 @@ namespace AzFramework
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
-    void NativeWindowImpl_Linux_xcb::WindowSizeChanged(const uint32_t width, const uint32_t height)
+    void XcbNativeWindow::WindowSizeChanged(const uint32_t width, const uint32_t height)
     {
         if (m_width != width || m_height != height)
         {
@@ -246,7 +242,4 @@ namespace AzFramework
             }
         }
     }
-    
-#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-
 } // namespace AzFramework

+ 9 - 10
Code/Framework/AzFramework/Platform/Linux/AzFramework/Windowing/NativeWindow_Linux_xcb.h → Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.h

@@ -5,24 +5,25 @@
  * SPDX-License-Identifier: Apache-2.0 OR MIT
  *
  */
+
 #pragma once
 
-#include <AzFramework/API/ApplicationAPI_Platform.h>
 #include <AzFramework/Application/Application.h>
 #include <AzFramework/Windowing/NativeWindow.h>
+#include <AzFramework/XcbEventHandler.h>
+
 #include <xcb/xcb.h>
 
 namespace AzFramework
 {
-#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-    class NativeWindowImpl_Linux_xcb final
+    class XcbNativeWindow final
         : public NativeWindow::Implementation
-        , public LinuxXcbEventHandlerBus::Handler
+        , public XcbEventHandlerBus::Handler
     {
     public:
-        AZ_CLASS_ALLOCATOR(NativeWindowImpl_Linux_xcb, AZ::SystemAllocator, 0);
-        NativeWindowImpl_Linux_xcb();
-        ~NativeWindowImpl_Linux_xcb() override;
+        AZ_CLASS_ALLOCATOR(XcbNativeWindow, AZ::SystemAllocator, 0);
+        XcbNativeWindow();
+        ~XcbNativeWindow() override;
 
         ////////////////////////////////////////////////////////////////////////////////////////////
         // NativeWindow::Implementation
@@ -37,7 +38,7 @@ namespace AzFramework
         uint32_t GetDisplayRefreshRate() const override;        
 
         ////////////////////////////////////////////////////////////////////////////////////////////
-        // LinuxXcbEventHandlerBus::Handler
+        // XcbEventHandlerBus::Handler
         void HandleXcbEvent(xcb_generic_event_t* event) override;
 
     private:
@@ -49,6 +50,4 @@ namespace AzFramework
         xcb_atom_t          m_xcbAtomProtocols;
         xcb_atom_t          m_xcbAtomDeleteWindow;
     };
-#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-
 } // namespace AzFramework

+ 18 - 0
Code/Framework/AzFramework/Platform/Common/Xcb/azframework_xcb_files.cmake

@@ -0,0 +1,18 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+set(FILES
+    AzFramework/XcbApplication.cpp
+    AzFramework/XcbApplication.h
+    AzFramework/XcbConnectionManager.h
+    AzFramework/XcbInputDeviceKeyboard.cpp
+    AzFramework/XcbInputDeviceKeyboard.h
+    AzFramework/XcbInterface.h
+    AzFramework/XcbNativeWindow.cpp
+    AzFramework/XcbNativeWindow.h
+)

+ 0 - 54
Code/Framework/AzFramework/Platform/Linux/AzFramework/API/ApplicationAPI_Linux.h

@@ -12,10 +12,6 @@
 #include <AzCore/Interface/Interface.h>
 #include <AzCore/EBus/EBus.h>
 
-#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-#include <xcb/xcb.h>
-#endif // LY_COMPILE_DEFINITIONS
-
 namespace AzFramework
 {
     class LinuxLifecycleEvents
@@ -30,54 +26,4 @@ namespace AzFramework
 
         using Bus = AZ::EBus<LinuxLifecycleEvents>;
     };
-
-#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-    class LinuxXcbConnectionManager
-    {
-    public:
-        AZ_RTTI(LinuxXcbConnectionManager, "{1F756E14-8D74-42FD-843C-4863307710DB}");
-
-        virtual ~LinuxXcbConnectionManager() = default;
-
-        virtual xcb_connection_t* GetXcbConnection() const = 0;
-    };
-
-    class LinuxXcbConnectionManagerBusTraits
-        : public AZ::EBusTraits
-    {
-        public:
-            //////////////////////////////////////////////////////////////////////////
-            // EBusTraits overrides
-            static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
-            static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
-            //////////////////////////////////////////////////////////////////////////
-    };
-
-    using LinuxXcbConnectionManagerBus = AZ::EBus<LinuxXcbConnectionManager, LinuxXcbConnectionManagerBusTraits>;
-    using LinuxXcbConnectionManagerInterface = AZ::Interface<LinuxXcbConnectionManager>;
-    
-    class LinuxXcbEventHandler
-    {
-    public:
-        AZ_RTTI(LinuxXcbEventHandler, "{3F756E14-8D74-42FD-843C-4863307710DB}");
-
-        virtual ~LinuxXcbEventHandler() = default;
-
-        virtual void HandleXcbEvent(xcb_generic_event_t* event) = 0;
-    };
-
-    class LinuxXcbEventHandlerBusTraits
-        : public AZ::EBusTraits
-    {
-        public:
-            //////////////////////////////////////////////////////////////////////////
-            // EBusTraits overrides
-            static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
-            static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
-            //////////////////////////////////////////////////////////////////////////
-    };
-
-    using LinuxXcbEventHandlerBus = AZ::EBus<LinuxXcbEventHandler, LinuxXcbEventHandlerBusTraits>;
-
-#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
 } // namespace AzFramework

+ 4 - 2
Code/Framework/AzFramework/Platform/Linux/AzFramework/Application/Application_Linux.cpp

@@ -8,7 +8,9 @@
 
 #include <AzFramework/Application/Application.h>
 
-#include "Application_Linux_xcb.h"
+#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+#include <AzFramework/XcbApplication.h>
+#endif
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 namespace AzFramework
@@ -17,7 +19,7 @@ namespace AzFramework
     Application::Implementation* Application::Implementation::Create()
     {
 #if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-        return aznew ApplicationLinux_xcb();
+        return aznew XcbApplication();
 #elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
         #error "Linux Window Manager Wayland not supported."
         return nullptr;

+ 27 - 0
Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_Linux.cpp

@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+#include <AzFramework/XcbInputDeviceKeyboard.h>
+#endif
+
+namespace AzFramework
+{
+    InputDeviceKeyboard::Implementation* InputDeviceKeyboard::Implementation::Create(InputDeviceKeyboard& inputDevice)
+    {
+#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+        return aznew XcbInputDeviceKeyboard(inputDevice);
+#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
+        #error "Linux Window Manager Wayland not supported."
+        return nullptr;
+#else
+        #error "Linux Window Manager not recognized."
+        return nullptr;
+#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+    }
+} // namespace AzFramework

+ 0 - 293
Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_xcb.cpp

@@ -1,293 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#include <AzCore/std/typetraits/integral_constant.h>
-#include <AzFramework/API/ApplicationAPI_Linux.h>
-#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
-
-#define explicit ExplicitIsACXXKeyword
-#include <xcb/xkb.h>
-#undef explicit
-#include <xkbcommon/xkbcommon-keysyms.h>
-#include <xkbcommon/xkbcommon.h>
-#include <xkbcommon/xkbcommon-x11.h>
-
-namespace AzFramework
-{
-    class InputDeviceKeyboardXcb
-        : public InputDeviceKeyboard::Implementation
-        , public LinuxXcbEventHandlerBus::Handler
-    {
-    public:
-        AZ_CLASS_ALLOCATOR(InputDeviceKeyboardXcb, AZ::SystemAllocator, 0);
-
-        using InputDeviceKeyboard::Implementation::Implementation;
-        InputDeviceKeyboardXcb(InputDeviceKeyboard& inputDevice)
-            : InputDeviceKeyboard::Implementation(inputDevice)
-        {
-            LinuxXcbEventHandlerBus::Handler::BusConnect();
-
-            auto* interface = AzFramework::LinuxXcbConnectionManagerInterface::Get();
-            if (!interface)
-            {
-                AZ_Warning("ApplicationLinux", false, "XCB interface not available");
-                return;
-            }
-
-            auto* connection = AzFramework::LinuxXcbConnectionManagerInterface::Get()->GetXcbConnection();
-            if (!connection)
-            {
-                AZ_Warning("ApplicationLinux", false, "XCB connection not available");
-                return;
-            }
-
-            AZStd::unique_ptr<xcb_xkb_use_extension_reply_t, DeleterForFreeFn<::std::free>> xkbUseExtensionReply{
-                xcb_xkb_use_extension_reply(connection, xcb_xkb_use_extension(connection, 1, 0), nullptr)
-            };
-            if (!xkbUseExtensionReply)
-            {
-                AZ_Warning("ApplicationLinux", false, "Failed to initialize the xkb extension");
-                return;
-            }
-            if (!xkbUseExtensionReply->supported)
-            {
-                AZ_Warning("ApplicationLinux", false, "The X server does not support the xkb extension");
-                return;
-            }
-
-            m_coreDeviceId = xkb_x11_get_core_keyboard_device_id(connection);
-
-            m_xkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
-            m_xkbKeymap.reset(xkb_x11_keymap_new_from_device(m_xkbContext.get(), connection, m_coreDeviceId, XKB_KEYMAP_COMPILE_NO_FLAGS));
-            m_xkbState.reset(xkb_x11_state_new_from_device(m_xkbKeymap.get(), connection, m_coreDeviceId));
-
-            m_initialized = true;
-        }
-
-        bool IsConnected() const override
-        {
-            return m_initialized;
-        }
-
-        bool HasTextEntryStarted() const override
-        {
-            return false;
-        }
-
-        void TextEntryStart(const InputDeviceKeyboard::VirtualKeyboardOptions& options) override
-        {
-        }
-
-        void TextEntryStop() override
-        {
-        }
-
-        void TickInputDevice() override
-        {
-            ProcessRawEventQueues();
-        }
-
-        void HandleXcbEvent(xcb_generic_event_t* event) override
-        {
-            if (!IsConnected())
-            {
-                return;
-            }
-
-            switch (event->response_type & ~0x80)
-            {
-            case XCB_KEY_PRESS:
-            {
-                auto* keyPress = reinterpret_cast<xcb_key_press_event_t*>(event);
-
-                const InputChannelId* key = InputChannelFromKeyEvent(keyPress->detail);
-                if (key)
-                {
-                    QueueRawKeyEvent(*key, true);
-                }
-                break;
-            }
-            case XCB_KEY_RELEASE:
-            {
-                auto* keyRelease = reinterpret_cast<xcb_key_release_event_t*>(event);
-
-                const InputChannelId* key = InputChannelFromKeyEvent(keyRelease->detail);
-                if (key)
-                {
-                    QueueRawKeyEvent(*key, false);
-                }
-                break;
-            }
-            }
-        }
-
-    private:
-        [[nodiscard]] const InputChannelId* InputChannelFromKeyEvent(xcb_keycode_t code) const
-        {
-            const xcb_keysym_t keysym = xkb_state_key_get_one_sym(m_xkbState.get(), code);
-
-            switch(keysym)
-            {
-                case XKB_KEY_0: return &InputDeviceKeyboard::Key::Alphanumeric0;
-                case XKB_KEY_1: return &InputDeviceKeyboard::Key::Alphanumeric1;
-                case XKB_KEY_2: return &InputDeviceKeyboard::Key::Alphanumeric2;
-                case XKB_KEY_3: return &InputDeviceKeyboard::Key::Alphanumeric3;
-                case XKB_KEY_4: return &InputDeviceKeyboard::Key::Alphanumeric4;
-                case XKB_KEY_5: return &InputDeviceKeyboard::Key::Alphanumeric5;
-                case XKB_KEY_6: return &InputDeviceKeyboard::Key::Alphanumeric6;
-                case XKB_KEY_7: return &InputDeviceKeyboard::Key::Alphanumeric7;
-                case XKB_KEY_8: return &InputDeviceKeyboard::Key::Alphanumeric8;
-                case XKB_KEY_9: return &InputDeviceKeyboard::Key::Alphanumeric9;
-                case XKB_KEY_A:
-                case XKB_KEY_a: return &InputDeviceKeyboard::Key::AlphanumericA;
-                case XKB_KEY_B:
-                case XKB_KEY_b: return &InputDeviceKeyboard::Key::AlphanumericB;
-                case XKB_KEY_C:
-                case XKB_KEY_c: return &InputDeviceKeyboard::Key::AlphanumericC;
-                case XKB_KEY_D:
-                case XKB_KEY_d: return &InputDeviceKeyboard::Key::AlphanumericD;
-                case XKB_KEY_E:
-                case XKB_KEY_e: return &InputDeviceKeyboard::Key::AlphanumericE;
-                case XKB_KEY_F:
-                case XKB_KEY_f: return &InputDeviceKeyboard::Key::AlphanumericF;
-                case XKB_KEY_G:
-                case XKB_KEY_g: return &InputDeviceKeyboard::Key::AlphanumericG;
-                case XKB_KEY_H:
-                case XKB_KEY_h: return &InputDeviceKeyboard::Key::AlphanumericH;
-                case XKB_KEY_I:
-                case XKB_KEY_i: return &InputDeviceKeyboard::Key::AlphanumericI;
-                case XKB_KEY_J:
-                case XKB_KEY_j: return &InputDeviceKeyboard::Key::AlphanumericJ;
-                case XKB_KEY_K:
-                case XKB_KEY_k: return &InputDeviceKeyboard::Key::AlphanumericK;
-                case XKB_KEY_L:
-                case XKB_KEY_l: return &InputDeviceKeyboard::Key::AlphanumericL;
-                case XKB_KEY_M:
-                case XKB_KEY_m: return &InputDeviceKeyboard::Key::AlphanumericM;
-                case XKB_KEY_N:
-                case XKB_KEY_n: return &InputDeviceKeyboard::Key::AlphanumericN;
-                case XKB_KEY_O:
-                case XKB_KEY_o: return &InputDeviceKeyboard::Key::AlphanumericO;
-                case XKB_KEY_P:
-                case XKB_KEY_p: return &InputDeviceKeyboard::Key::AlphanumericP;
-                case XKB_KEY_Q:
-                case XKB_KEY_q: return &InputDeviceKeyboard::Key::AlphanumericQ;
-                case XKB_KEY_R:
-                case XKB_KEY_r: return &InputDeviceKeyboard::Key::AlphanumericR;
-                case XKB_KEY_S:
-                case XKB_KEY_s: return &InputDeviceKeyboard::Key::AlphanumericS;
-                case XKB_KEY_T:
-                case XKB_KEY_t: return &InputDeviceKeyboard::Key::AlphanumericT;
-                case XKB_KEY_U:
-                case XKB_KEY_u: return &InputDeviceKeyboard::Key::AlphanumericU;
-                case XKB_KEY_V:
-                case XKB_KEY_v: return &InputDeviceKeyboard::Key::AlphanumericV;
-                case XKB_KEY_W:
-                case XKB_KEY_w: return &InputDeviceKeyboard::Key::AlphanumericW;
-                case XKB_KEY_X:
-                case XKB_KEY_x: return &InputDeviceKeyboard::Key::AlphanumericX;
-                case XKB_KEY_Y:
-                case XKB_KEY_y: return &InputDeviceKeyboard::Key::AlphanumericY;
-                case XKB_KEY_Z:
-                case XKB_KEY_z: return &InputDeviceKeyboard::Key::AlphanumericZ;
-                case XKB_KEY_BackSpace: return &InputDeviceKeyboard::Key::EditBackspace;
-                case XKB_KEY_Caps_Lock: return &InputDeviceKeyboard::Key::EditCapsLock;
-                case XKB_KEY_Return: return &InputDeviceKeyboard::Key::EditEnter;
-                case XKB_KEY_space: return &InputDeviceKeyboard::Key::EditSpace;
-                case XKB_KEY_Tab: return &InputDeviceKeyboard::Key::EditTab;
-                case XKB_KEY_Escape: return &InputDeviceKeyboard::Key::Escape;
-                case XKB_KEY_F1: return &InputDeviceKeyboard::Key::Function01;
-                case XKB_KEY_F2: return &InputDeviceKeyboard::Key::Function02;
-                case XKB_KEY_F3: return &InputDeviceKeyboard::Key::Function03;
-                case XKB_KEY_F4: return &InputDeviceKeyboard::Key::Function04;
-                case XKB_KEY_F5: return &InputDeviceKeyboard::Key::Function05;
-                case XKB_KEY_F6: return &InputDeviceKeyboard::Key::Function06;
-                case XKB_KEY_F7: return &InputDeviceKeyboard::Key::Function07;
-                case XKB_KEY_F8: return &InputDeviceKeyboard::Key::Function08;
-                case XKB_KEY_F9: return &InputDeviceKeyboard::Key::Function09;
-                case XKB_KEY_F10: return &InputDeviceKeyboard::Key::Function10;
-                case XKB_KEY_F11: return &InputDeviceKeyboard::Key::Function11;
-                case XKB_KEY_F12: return &InputDeviceKeyboard::Key::Function12;
-                case XKB_KEY_F13: return &InputDeviceKeyboard::Key::Function13;
-                case XKB_KEY_F14: return &InputDeviceKeyboard::Key::Function14;
-                case XKB_KEY_F15: return &InputDeviceKeyboard::Key::Function15;
-                case XKB_KEY_F16: return &InputDeviceKeyboard::Key::Function16;
-                case XKB_KEY_F17: return &InputDeviceKeyboard::Key::Function17;
-                case XKB_KEY_F18: return &InputDeviceKeyboard::Key::Function18;
-                case XKB_KEY_F19: return &InputDeviceKeyboard::Key::Function19;
-                case XKB_KEY_F20: return &InputDeviceKeyboard::Key::Function20;
-                case XKB_KEY_Alt_L: return &InputDeviceKeyboard::Key::ModifierAltL;
-                case XKB_KEY_Alt_R: return &InputDeviceKeyboard::Key::ModifierAltR;
-                case XKB_KEY_Control_L: return &InputDeviceKeyboard::Key::ModifierCtrlL;
-                case XKB_KEY_Control_R: return &InputDeviceKeyboard::Key::ModifierCtrlR;
-                case XKB_KEY_Shift_L: return &InputDeviceKeyboard::Key::ModifierShiftL;
-                case XKB_KEY_Shift_R: return &InputDeviceKeyboard::Key::ModifierShiftR;
-                case XKB_KEY_Super_L: return &InputDeviceKeyboard::Key::ModifierSuperL;
-                case XKB_KEY_Super_R: return &InputDeviceKeyboard::Key::ModifierSuperR;
-                case XKB_KEY_Down: return &InputDeviceKeyboard::Key::NavigationArrowDown;
-                case XKB_KEY_Left: return &InputDeviceKeyboard::Key::NavigationArrowLeft;
-                case XKB_KEY_Right: return &InputDeviceKeyboard::Key::NavigationArrowRight;
-                case XKB_KEY_Up: return &InputDeviceKeyboard::Key::NavigationArrowUp;
-                case XKB_KEY_Delete: return &InputDeviceKeyboard::Key::NavigationDelete;
-                case XKB_KEY_End: return &InputDeviceKeyboard::Key::NavigationEnd;
-                case XKB_KEY_Home: return &InputDeviceKeyboard::Key::NavigationHome;
-                case XKB_KEY_Insert: return &InputDeviceKeyboard::Key::NavigationInsert;
-                case XKB_KEY_Page_Down: return &InputDeviceKeyboard::Key::NavigationPageDown;
-                case XKB_KEY_Page_Up: return &InputDeviceKeyboard::Key::NavigationPageUp;
-                case XKB_KEY_Num_Lock: return &InputDeviceKeyboard::Key::NumLock;
-                case XKB_KEY_KP_0: return &InputDeviceKeyboard::Key::NumPad0;
-                case XKB_KEY_KP_1: return &InputDeviceKeyboard::Key::NumPad1;
-                case XKB_KEY_KP_2: return &InputDeviceKeyboard::Key::NumPad2;
-                case XKB_KEY_KP_3: return &InputDeviceKeyboard::Key::NumPad3;
-                case XKB_KEY_KP_4: return &InputDeviceKeyboard::Key::NumPad4;
-                case XKB_KEY_KP_5: return &InputDeviceKeyboard::Key::NumPad5;
-                case XKB_KEY_KP_6: return &InputDeviceKeyboard::Key::NumPad6;
-                case XKB_KEY_KP_7: return &InputDeviceKeyboard::Key::NumPad7;
-                case XKB_KEY_KP_8: return &InputDeviceKeyboard::Key::NumPad8;
-                case XKB_KEY_KP_9: return &InputDeviceKeyboard::Key::NumPad9;
-                case XKB_KEY_KP_Add: return &InputDeviceKeyboard::Key::NumPadAdd;
-                case XKB_KEY_KP_Decimal: return &InputDeviceKeyboard::Key::NumPadDecimal;
-                case XKB_KEY_KP_Divide: return &InputDeviceKeyboard::Key::NumPadDivide;
-                case XKB_KEY_KP_Enter: return &InputDeviceKeyboard::Key::NumPadEnter;
-                case XKB_KEY_KP_Multiply: return &InputDeviceKeyboard::Key::NumPadMultiply;
-                case XKB_KEY_KP_Subtract: return &InputDeviceKeyboard::Key::NumPadSubtract;
-                case XKB_KEY_apostrophe: return &InputDeviceKeyboard::Key::PunctuationApostrophe;
-                case XKB_KEY_backslash: return &InputDeviceKeyboard::Key::PunctuationBackslash;
-                case XKB_KEY_bracketleft: return &InputDeviceKeyboard::Key::PunctuationBracketL;
-                case XKB_KEY_bracketright: return &InputDeviceKeyboard::Key::PunctuationBracketR;
-                case XKB_KEY_comma: return &InputDeviceKeyboard::Key::PunctuationComma;
-                case XKB_KEY_equal: return &InputDeviceKeyboard::Key::PunctuationEquals;
-                case XKB_KEY_hyphen: return &InputDeviceKeyboard::Key::PunctuationHyphen;
-                case XKB_KEY_period: return &InputDeviceKeyboard::Key::PunctuationPeriod;
-                case XKB_KEY_semicolon: return &InputDeviceKeyboard::Key::PunctuationSemicolon;
-                case XKB_KEY_slash: return &InputDeviceKeyboard::Key::PunctuationSlash;
-                case XKB_KEY_grave:
-                case XKB_KEY_asciitilde: return &InputDeviceKeyboard::Key::PunctuationTilde;
-                case XKB_KEY_ISO_Group_Shift: return &InputDeviceKeyboard::Key::SupplementaryISO;
-                case XKB_KEY_Pause: return &InputDeviceKeyboard::Key::WindowsSystemPause;
-                case XKB_KEY_Print: return &InputDeviceKeyboard::Key::WindowsSystemPrint;
-                case XKB_KEY_Scroll_Lock: return &InputDeviceKeyboard::Key::WindowsSystemScrollLock;
-                default: return nullptr;
-            }
-        }
-
-        template<auto freeFn>
-        using DeleterForFreeFn = AZStd::integral_constant<decltype(freeFn), freeFn>;
-
-        AZStd::unique_ptr<xkb_context, DeleterForFreeFn<xkb_context_unref>> m_xkbContext;
-        AZStd::unique_ptr<xkb_keymap, DeleterForFreeFn<xkb_keymap_unref>> m_xkbKeymap;
-        AZStd::unique_ptr<xkb_state, DeleterForFreeFn<xkb_state_unref>> m_xkbState;
-        int m_coreDeviceId{-1};
-        bool m_initialized{false};
-    };
-
-    InputDeviceKeyboard::Implementation* InputDeviceKeyboard::Implementation::Create(InputDeviceKeyboard& inputDevice)
-    {
-        return aznew InputDeviceKeyboardXcb(inputDevice);
-    }
-} // namespace AzFramework

+ 4 - 3
Code/Framework/AzFramework/Platform/Linux/AzFramework/Windowing/NativeWindow_Linux.cpp

@@ -6,14 +6,16 @@
  *
  */
 
-#include "NativeWindow_Linux_xcb.h"
+#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+#include <AzFramework/XcbNativeWindow.h>
+#endif
 
 namespace AzFramework
 {
     NativeWindow::Implementation* NativeWindow::Implementation::Create()
     {
 #if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-        return aznew NativeWindowImpl_Linux_xcb();
+        return aznew XcbNativeWindow();
 #elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
         #error "Linux Window Manager Wayland not supported."
         return nullptr;
@@ -22,5 +24,4 @@ namespace AzFramework
         return nullptr;
 #endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
     }
-
 } // namespace AzFramework

+ 8 - 2
Code/Framework/AzFramework/Platform/Linux/platform_linux.cmake

@@ -10,6 +10,14 @@
 # Only 'xcb' and 'wayland' are recognized
 if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb")
 
+    set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
+    set(LY_INCLUDE_DIRECTORIES
+        PUBLIC
+            Platform/Common/Xcb
+    )
+    set(LY_FILES_CMAKE
+        Platform/Common/Xcb/azframework_xcb_files.cmake
+    )
     set(LY_BUILD_DEPENDENCIES
         PRIVATE
             3rdParty::X11::xcb
@@ -18,8 +26,6 @@ if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb")
             3rdParty::X11::xkbcommon_X11
     )
 
-    set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
-
 elseif(PAL_TRAIT_LINUX_WINDOW_MANAGER STREQUAL "wayland")
 
     set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND)

+ 1 - 5
Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake

@@ -12,8 +12,6 @@ set(FILES
     AzFramework/API/ApplicationAPI_Platform.h
     AzFramework/API/ApplicationAPI_Linux.h
     AzFramework/Application/Application_Linux.cpp
-    AzFramework/Application/Application_Linux_xcb.h
-    AzFramework/Application/Application_Linux_xcb.cpp
     AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp
     AzFramework/Process/ProcessWatcher_Linux.cpp
     AzFramework/Process/ProcessCommon.h
@@ -22,10 +20,8 @@ set(FILES
     ../Common/Unimplemented/AzFramework/StreamingInstall/StreamingInstall_Unimplemented.cpp
     ../Common/Default/AzFramework/TargetManagement/TargetManagementComponent_Default.cpp
     AzFramework/Windowing/NativeWindow_Linux.cpp
-    AzFramework/Windowing/NativeWindow_Linux_xcb.h
-    AzFramework/Windowing/NativeWindow_Linux_xcb.cpp
     ../Common/Unimplemented/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad_Unimplemented.cpp
-    AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_xcb.cpp
+    AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_Linux.cpp
     ../Common/Unimplemented/AzFramework/Input/Devices/Motion/InputDeviceMotion_Unimplemented.cpp
     ../Common/Unimplemented/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Unimplemented.cpp
     ../Common/Unimplemented/AzFramework/Input/Devices/Touch/InputDeviceTouch_Unimplemented.cpp

+ 5 - 1
Gems/Atom/RHI/Vulkan/Code/Source/Platform/Linux/RHI/WSISurface_Linux.cpp

@@ -10,6 +10,10 @@
 #include <RHI/Instance.h>
 #include <RHI/WSISurface.h>
 
+#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+#include <AzFramework/XcbConnectionManager.h>
+#endif
+
 namespace AZ
 {
     namespace Vulkan
@@ -21,7 +25,7 @@ namespace AZ
 #if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
 
             xcb_connection_t* xcb_connection = nullptr;
-            if (auto xcbConnectionManager = AzFramework::LinuxXcbConnectionManagerInterface::Get();
+            if (auto xcbConnectionManager = AzFramework::XcbConnectionManagerInterface::Get();
                 xcbConnectionManager != nullptr)
             {
                 xcb_connection = xcbConnectionManager->GetXcbConnection();