/* Copyright (c) 2025 The Khronos Group Inc.
 * Copyright (c) 2025 Valve Corporation
 * Copyright (c) 2025 LunarG, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#if defined(DEBUG_CAPTURE_KEYBOARD)
#include "keyboard.h"

#if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR)
#include <X11/keysym.h>
#endif

#if defined(VK_USE_PLATFORM_XLIB_KHR)
#include <X11/Xlib.h>
#include <X11/XKBlib.h>
#endif

#if defined(VK_USE_PLATFORM_XCB_KHR)
#include <xcb/xcb.h>
#include <xcb/xcb_keysyms.h>
#include <stdlib.h>
#endif

#if defined(VK_USE_PLATFORM_WIN32_KHR)
#include <windows.h>
#endif

static bool previous_key_state = true;

static bool GetKeyState(void* xlib_display, void* xcb_connection) {
    bool result = false;

#if defined(VK_USE_PLATFORM_XLIB_KHR)
    if (xlib_display) {
        char keys_return[32];
        Display* dpy = (Display*)xlib_display;
        XQueryKeymap(dpy, keys_return);

        KeyCode keycode = XKeysymToKeycode(dpy, XK_F1);
        int byte = keycode / 8;
        int bit = keycode % 8;

        return (keys_return[byte] & (1 << bit)) != 0;
    }
#endif
#if defined(VK_USE_PLATFORM_XCB_KHR)
    if (xcb_connection) {
        xcb_connection_t* connection = (xcb_connection_t*)xcb_connection;
        xcb_key_symbols_t* symbols = xcb_key_symbols_alloc(connection);

        xcb_query_keymap_cookie_t cookie = xcb_query_keymap(connection);
        xcb_query_keymap_reply_t* reply = xcb_query_keymap_reply(connection, cookie, NULL);
        if (reply) {
            xcb_keycode_t* keycodes = xcb_key_symbols_get_keycode(symbols, XK_F1);
            if (keycodes) {
                for (int i = 0; keycodes[i] != XCB_NO_SYMBOL; ++i) {
                    int byte = keycodes[i] / 8;
                    int bit = keycodes[i] % 8;
                    if (reply->keys[byte] & (1 << bit)) {
                        result = true;
                        break;
                    }
                }
                free(keycodes);
            }
            free(reply);
        }
        xcb_key_symbols_free(symbols);
    }
#endif

#if defined(VK_USE_PLATFORM_WIN32_KHR)
    (void)xlib_display;
    (void)xcb_connection;
    result |= (GetAsyncKeyState(VK_F1) != 0);
#endif

    return result;
}

bool IsDebugKeyPressed(void* xlib_display, void* xcb_connection) {
    // Return true when  transitions from false to true
    const bool hotkey_state = GetKeyState(xlib_display, xcb_connection);
    const bool hotkey_pressed = hotkey_state && !previous_key_state;
    previous_key_state = hotkey_state;
    return hotkey_pressed;
}
#endif