mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-11-12 14:57:20 +00:00
[client] windows: add native display and input
This commit is contained in:
@@ -313,6 +313,16 @@ endif()
|
||||
add_subdirectory("${PROJECT_TOP}/repos/gui" "${CMAKE_BINARY_DIR}/gui"
|
||||
EXCLUDE_FROM_ALL)
|
||||
|
||||
get_target_property(LG_GUI_INTERFACE_COMPILE_DEFINITIONS
|
||||
lg_gui INTERFACE_COMPILE_DEFINITIONS)
|
||||
if(LG_GUI_INTERFACE_COMPILE_DEFINITIONS)
|
||||
list(FILTER LG_GUI_INTERFACE_COMPILE_DEFINITIONS EXCLUDE
|
||||
REGEX "^IMGUI_IMPL_API=")
|
||||
set_property(TARGET lg_gui PROPERTY INTERFACE_COMPILE_DEFINITIONS
|
||||
${LG_GUI_INTERFACE_COMPILE_DEFINITIONS})
|
||||
endif()
|
||||
unset(LG_GUI_INTERFACE_COMPILE_DEFINITIONS)
|
||||
|
||||
target_sources(lg_gui PRIVATE
|
||||
"${PROJECT_TOP}/repos/gui/cimgui/imgui/imgui_demo.cpp"
|
||||
"${PROJECT_TOP}/repos/gui/cimplot/implot/implot_demo.cpp"
|
||||
|
||||
35
client/displayservers/Windows/CMakeLists.txt
Normal file
35
client/displayservers/Windows/CMakeLists.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(displayserver_Windows LANGUAGES C)
|
||||
|
||||
add_library(displayserver_Windows STATIC
|
||||
input_event.c
|
||||
window_size.c
|
||||
windows.c
|
||||
)
|
||||
|
||||
target_compile_definitions(displayserver_Windows PRIVATE
|
||||
WINVER=0x0A00
|
||||
_WIN32_WINNT=0x0A00
|
||||
WIN32_LEAN_AND_MEAN
|
||||
NOMINMAX
|
||||
UNICODE
|
||||
_UNICODE
|
||||
)
|
||||
|
||||
target_include_directories(displayserver_Windows
|
||||
PRIVATE
|
||||
.
|
||||
../../src
|
||||
)
|
||||
|
||||
target_link_libraries(displayserver_Windows
|
||||
lg_common
|
||||
user32
|
||||
gdi32
|
||||
)
|
||||
|
||||
if(ENABLE_EGL)
|
||||
target_link_libraries(displayserver_Windows
|
||||
lg_egl_provider
|
||||
)
|
||||
endif()
|
||||
399
client/displayservers/Windows/input_event.c
Normal file
399
client/displayservers/Windows/input_event.c
Normal file
@@ -0,0 +1,399 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "input_event.h"
|
||||
|
||||
#include "../../src/kb.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
enum ModifierKey
|
||||
{
|
||||
MODIFIER_KEY_LEFT = 1U << 0,
|
||||
MODIFIER_KEY_RIGHT = 1U << 1,
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(double) == sizeof(uint64_t), "Unexpected double size");
|
||||
|
||||
static bool validCoordinate(double value)
|
||||
{
|
||||
uint64_t bits;
|
||||
memcpy(&bits, &value, sizeof(bits));
|
||||
return (bits & UINT64_C(0x7FF0000000000000)) !=
|
||||
UINT64_C(0x7FF0000000000000);
|
||||
}
|
||||
|
||||
static bool finishPointerLeave(WindowsInput * input)
|
||||
{
|
||||
if (!input->entered || !input->leavePending || input->buttons ||
|
||||
input->pointerGrabbed)
|
||||
return false;
|
||||
|
||||
input->entered = false;
|
||||
input->leavePending = false;
|
||||
input->sink->enter(input->opaque, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void updateKeyState(WindowsInput * input, int key, bool pressed)
|
||||
{
|
||||
uint8_t * modifier = NULL;
|
||||
uint8_t mask = 0;
|
||||
bool * lock = NULL;
|
||||
bool * lockDown = NULL;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case LG_KEY_LEFTCTRL:
|
||||
modifier = &input->ctrlKeys;
|
||||
mask = MODIFIER_KEY_LEFT;
|
||||
break;
|
||||
|
||||
case LG_KEY_RIGHTCTRL:
|
||||
modifier = &input->ctrlKeys;
|
||||
mask = MODIFIER_KEY_RIGHT;
|
||||
break;
|
||||
|
||||
case LG_KEY_LEFTSHIFT:
|
||||
modifier = &input->shiftKeys;
|
||||
mask = MODIFIER_KEY_LEFT;
|
||||
break;
|
||||
|
||||
case LG_KEY_RIGHTSHIFT:
|
||||
modifier = &input->shiftKeys;
|
||||
mask = MODIFIER_KEY_RIGHT;
|
||||
break;
|
||||
|
||||
case LG_KEY_LEFTALT:
|
||||
modifier = &input->altKeys;
|
||||
mask = MODIFIER_KEY_LEFT;
|
||||
break;
|
||||
|
||||
case LG_KEY_RIGHTALT:
|
||||
modifier = &input->altKeys;
|
||||
mask = MODIFIER_KEY_RIGHT;
|
||||
break;
|
||||
|
||||
case LG_KEY_LEFTMETA:
|
||||
modifier = &input->superKeys;
|
||||
mask = MODIFIER_KEY_LEFT;
|
||||
break;
|
||||
|
||||
case LG_KEY_RIGHTMETA:
|
||||
modifier = &input->superKeys;
|
||||
mask = MODIFIER_KEY_RIGHT;
|
||||
break;
|
||||
|
||||
case LG_KEY_NUMLOCK:
|
||||
lock = &input->numLock;
|
||||
lockDown = &input->numLockPressed;
|
||||
break;
|
||||
|
||||
case LG_KEY_CAPSLOCK:
|
||||
lock = &input->capsLock;
|
||||
lockDown = &input->capsLockPressed;
|
||||
break;
|
||||
|
||||
case LG_KEY_SCROLLLOCK:
|
||||
lock = &input->scrollLock;
|
||||
lockDown = &input->scrollLockPressed;
|
||||
break;
|
||||
}
|
||||
|
||||
if (modifier)
|
||||
{
|
||||
if (pressed)
|
||||
*modifier |= mask;
|
||||
else
|
||||
*modifier &= ~mask;
|
||||
}
|
||||
|
||||
if (lock)
|
||||
{
|
||||
if (pressed && !*lockDown)
|
||||
*lock = !*lock;
|
||||
*lockDown = pressed;
|
||||
}
|
||||
}
|
||||
|
||||
static bool modifierKey(int key)
|
||||
{
|
||||
return key == LG_KEY_LEFTCTRL || key == LG_KEY_RIGHTCTRL ||
|
||||
key == LG_KEY_LEFTSHIFT || key == LG_KEY_RIGHTSHIFT ||
|
||||
key == LG_KEY_LEFTALT || key == LG_KEY_RIGHTALT ||
|
||||
key == LG_KEY_LEFTMETA || key == LG_KEY_RIGHTMETA;
|
||||
}
|
||||
|
||||
void windowsInputInit(WindowsInput * input, const LG_DSInputSink * sink,
|
||||
void * opaque)
|
||||
{
|
||||
memset(input, 0, sizeof(*input));
|
||||
input->sink = sink;
|
||||
input->opaque = opaque;
|
||||
}
|
||||
|
||||
void windowsInputSetPointerGrabbed(WindowsInput * input, bool grabbed)
|
||||
{
|
||||
if (input->pointerGrabbed == grabbed)
|
||||
return;
|
||||
|
||||
input->pointerGrabbed = grabbed;
|
||||
if (!grabbed)
|
||||
finishPointerLeave(input);
|
||||
}
|
||||
|
||||
bool windowsInputIsPointerGrabbed(const WindowsInput * input)
|
||||
{
|
||||
return input->pointerGrabbed;
|
||||
}
|
||||
|
||||
void windowsInputSetKeyboardGrabbed(WindowsInput * input, bool grabbed)
|
||||
{
|
||||
input->keyboardGrabbed = grabbed;
|
||||
}
|
||||
|
||||
bool windowsInputIsKeyboardGrabbed(const WindowsInput * input)
|
||||
{
|
||||
return input->keyboardGrabbed;
|
||||
}
|
||||
|
||||
bool windowsInputFocus(WindowsInput * input, bool focused)
|
||||
{
|
||||
if (input->focused == focused)
|
||||
return false;
|
||||
|
||||
input->focused = focused;
|
||||
if (!focused)
|
||||
{
|
||||
input->ctrlKeys = 0;
|
||||
input->shiftKeys = 0;
|
||||
input->altKeys = 0;
|
||||
input->superKeys = 0;
|
||||
input->numLockPressed = false;
|
||||
input->capsLockPressed = false;
|
||||
input->scrollLockPressed = false;
|
||||
input->printScreenKey = LG_KEY_RESERVED;
|
||||
}
|
||||
|
||||
input->sink->focus(input->opaque, focused);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool windowsInputPointerEnter(WindowsInput * input, double x, double y)
|
||||
{
|
||||
if (!validCoordinate(x) || !validCoordinate(y))
|
||||
return false;
|
||||
|
||||
input->leavePending = false;
|
||||
if (input->entered)
|
||||
return false;
|
||||
|
||||
input->entered = true;
|
||||
input->sink->enter(input->opaque, true);
|
||||
input->sink->position(input->opaque, x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool windowsInputPointerLeave(WindowsInput * input)
|
||||
{
|
||||
if (!input->entered)
|
||||
return false;
|
||||
|
||||
input->leavePending = true;
|
||||
return finishPointerLeave(input);
|
||||
}
|
||||
|
||||
void windowsInputPointerMotion(WindowsInput * input, double x, double y)
|
||||
{
|
||||
if (!input->entered || input->leavePending || input->pointerGrabbed ||
|
||||
!validCoordinate(x) || !validCoordinate(y))
|
||||
return;
|
||||
|
||||
input->sink->position(input->opaque, x, y);
|
||||
}
|
||||
|
||||
void windowsInputRelativeMotion(WindowsInput * input, double x, double y)
|
||||
{
|
||||
if (!input->entered || !input->pointerGrabbed ||
|
||||
!validCoordinate(x) || !validCoordinate(y))
|
||||
return;
|
||||
|
||||
input->sink->relative(input->opaque, x, y, x, y);
|
||||
}
|
||||
|
||||
bool windowsInputPointerButton(WindowsInput * input, unsigned int button,
|
||||
bool pressed)
|
||||
{
|
||||
if ((!input->entered && !input->pointerGrabbed) ||
|
||||
button == 0 || button >= 32)
|
||||
return false;
|
||||
|
||||
const uint32_t mask = UINT32_C(1) << button;
|
||||
if (((input->buttons & mask) != 0) == pressed)
|
||||
return false;
|
||||
|
||||
if (pressed)
|
||||
input->buttons |= mask;
|
||||
else
|
||||
input->buttons &= ~mask;
|
||||
|
||||
input->sink->button(input->opaque, button, pressed);
|
||||
if (!pressed)
|
||||
finishPointerLeave(input);
|
||||
return true;
|
||||
}
|
||||
|
||||
void windowsInputReleaseButtons(WindowsInput * input)
|
||||
{
|
||||
const uint32_t buttons = input->buttons;
|
||||
input->buttons = 0;
|
||||
|
||||
for (unsigned int button = 1; button < 32; ++button)
|
||||
if (buttons & (UINT32_C(1) << button))
|
||||
input->sink->button(input->opaque, button, false);
|
||||
|
||||
finishPointerLeave(input);
|
||||
}
|
||||
|
||||
void windowsInputPointerWheel(WindowsInput * input, double motion)
|
||||
{
|
||||
if ((!input->entered && !input->pointerGrabbed) ||
|
||||
!validCoordinate(motion) || motion == 0.0)
|
||||
return;
|
||||
|
||||
input->wheel += motion;
|
||||
while (input->wheel >= 1.0)
|
||||
{
|
||||
input->sink->button(input->opaque, 4, true);
|
||||
input->sink->button(input->opaque, 4, false);
|
||||
input->wheel -= 1.0;
|
||||
}
|
||||
|
||||
while (input->wheel <= -1.0)
|
||||
{
|
||||
input->sink->button(input->opaque, 5, true);
|
||||
input->sink->button(input->opaque, 5, false);
|
||||
input->wheel += 1.0;
|
||||
}
|
||||
|
||||
input->sink->wheel(input->opaque, -motion);
|
||||
}
|
||||
|
||||
int windowsInputMapScanCode(uint8_t scanCode, bool extended)
|
||||
{
|
||||
const uint32_t ps2 = scanCode |
|
||||
(extended ? UINT32_C(0xE000) : UINT32_C(0));
|
||||
if (!ps2)
|
||||
return LG_KEY_RESERVED;
|
||||
|
||||
for (int key = 1; key < LG_KEY_MAX; ++key)
|
||||
if (lg_keycode_to_ps2[key] == ps2)
|
||||
return key;
|
||||
|
||||
return LG_KEY_RESERVED;
|
||||
}
|
||||
|
||||
int windowsInputMapPrintScreen(bool altDown)
|
||||
{
|
||||
return altDown ? LG_KEY_SYSRQ : LG_KEY_PRINT;
|
||||
}
|
||||
|
||||
int windowsInputMapPrintScreenEvent(WindowsInput * input,
|
||||
bool altDown, bool pressed)
|
||||
{
|
||||
if (pressed)
|
||||
{
|
||||
if (input->printScreenKey == LG_KEY_RESERVED)
|
||||
input->printScreenKey = windowsInputMapPrintScreen(altDown);
|
||||
|
||||
return input->printScreenKey;
|
||||
}
|
||||
|
||||
const int key = input->printScreenKey == LG_KEY_RESERVED ?
|
||||
windowsInputMapPrintScreen(altDown) : input->printScreenKey;
|
||||
input->printScreenKey = LG_KEY_RESERVED;
|
||||
return key;
|
||||
}
|
||||
|
||||
bool windowsInputKeyCode(WindowsInput * input, int key, bool pressed,
|
||||
bool grabbedEvent)
|
||||
{
|
||||
if (!input->focused || grabbedEvent != input->keyboardGrabbed ||
|
||||
key <= LG_KEY_RESERVED || key >= LG_KEY_MAX)
|
||||
return false;
|
||||
|
||||
updateKeyState(input, key, pressed);
|
||||
input->sink->key(input->opaque, key, pressed);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool windowsInputKey(WindowsInput * input, uint8_t scanCode, bool extended,
|
||||
bool pressed, bool grabbedEvent)
|
||||
{
|
||||
return windowsInputKeyCode(input,
|
||||
windowsInputMapScanCode(scanCode, extended), pressed, grabbedEvent);
|
||||
}
|
||||
|
||||
size_t windowsInputSyncHeldKeys(WindowsInput * input,
|
||||
const int * keys, size_t count, bool grabbedEvent)
|
||||
{
|
||||
if (!keys)
|
||||
return 0;
|
||||
|
||||
size_t synced = 0;
|
||||
for (unsigned int pass = 0; pass < 2; ++pass)
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
const bool modifier = modifierKey(keys[i]);
|
||||
if (modifier != (pass == 0))
|
||||
continue;
|
||||
|
||||
if (windowsInputKeyCode(input, keys[i], true, grabbedEvent))
|
||||
++synced;
|
||||
}
|
||||
|
||||
return synced;
|
||||
}
|
||||
|
||||
void windowsInputText(WindowsInput * input, const char * text)
|
||||
{
|
||||
if (input->focused && !input->keyboardGrabbed && text && *text)
|
||||
input->sink->text(input->opaque, text);
|
||||
}
|
||||
|
||||
void windowsInputState(WindowsInput * input,
|
||||
bool ctrl, bool shift, bool alt, bool super,
|
||||
bool numLock, bool capsLock, bool scrollLock)
|
||||
{
|
||||
input->numLock = numLock;
|
||||
input->capsLock = capsLock;
|
||||
input->scrollLock = scrollLock;
|
||||
input->sink->modifiers(input->opaque, ctrl, shift, alt, super);
|
||||
input->sink->leds(input->opaque, numLock, capsLock, scrollLock);
|
||||
}
|
||||
|
||||
void windowsInputTrackedState(WindowsInput * input)
|
||||
{
|
||||
input->sink->modifiers(input->opaque,
|
||||
input->ctrlKeys != 0, input->shiftKeys != 0,
|
||||
input->altKeys != 0, input->superKeys != 0);
|
||||
input->sink->leds(input->opaque,
|
||||
input->numLock, input->capsLock, input->scrollLock);
|
||||
}
|
||||
91
client/displayservers/Windows/input_event.h
Normal file
91
client/displayservers/Windows/input_event.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _H_LG_WINDOWS_INPUT_EVENT_
|
||||
#define _H_LG_WINDOWS_INPUT_EVENT_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "input/keycodes.h"
|
||||
|
||||
#include "../input.h"
|
||||
|
||||
typedef struct WindowsInput
|
||||
{
|
||||
const LG_DSInputSink * sink;
|
||||
void * opaque;
|
||||
uint32_t buttons;
|
||||
double wheel;
|
||||
uint8_t ctrlKeys;
|
||||
uint8_t shiftKeys;
|
||||
uint8_t altKeys;
|
||||
uint8_t superKeys;
|
||||
int printScreenKey;
|
||||
bool entered;
|
||||
bool leavePending;
|
||||
bool focused;
|
||||
bool pointerGrabbed;
|
||||
bool keyboardGrabbed;
|
||||
bool numLock;
|
||||
bool capsLock;
|
||||
bool scrollLock;
|
||||
bool numLockPressed;
|
||||
bool capsLockPressed;
|
||||
bool scrollLockPressed;
|
||||
}
|
||||
WindowsInput;
|
||||
|
||||
void windowsInputInit(WindowsInput * input, const LG_DSInputSink * sink,
|
||||
void * opaque);
|
||||
|
||||
void windowsInputSetPointerGrabbed(WindowsInput * input, bool grabbed);
|
||||
bool windowsInputIsPointerGrabbed(const WindowsInput * input);
|
||||
void windowsInputSetKeyboardGrabbed(WindowsInput * input, bool grabbed);
|
||||
bool windowsInputIsKeyboardGrabbed(const WindowsInput * input);
|
||||
|
||||
bool windowsInputFocus(WindowsInput * input, bool focused);
|
||||
bool windowsInputPointerEnter(WindowsInput * input, double x, double y);
|
||||
bool windowsInputPointerLeave(WindowsInput * input);
|
||||
void windowsInputPointerMotion(WindowsInput * input, double x, double y);
|
||||
void windowsInputRelativeMotion(WindowsInput * input, double x, double y);
|
||||
bool windowsInputPointerButton(WindowsInput * input, unsigned int button,
|
||||
bool pressed);
|
||||
void windowsInputReleaseButtons(WindowsInput * input);
|
||||
void windowsInputPointerWheel(WindowsInput * input, double motion);
|
||||
|
||||
int windowsInputMapScanCode(uint8_t scanCode, bool extended);
|
||||
int windowsInputMapPrintScreen(bool altDown);
|
||||
int windowsInputMapPrintScreenEvent(WindowsInput * input,
|
||||
bool altDown, bool pressed);
|
||||
bool windowsInputKeyCode(WindowsInput * input, int key, bool pressed,
|
||||
bool grabbedEvent);
|
||||
bool windowsInputKey(WindowsInput * input, uint8_t scanCode, bool extended,
|
||||
bool pressed, bool grabbedEvent);
|
||||
size_t windowsInputSyncHeldKeys(WindowsInput * input,
|
||||
const int * keys, size_t count, bool grabbedEvent);
|
||||
void windowsInputText(WindowsInput * input, const char * text);
|
||||
void windowsInputState(WindowsInput * input,
|
||||
bool ctrl, bool shift, bool alt, bool super,
|
||||
bool numLock, bool capsLock, bool scrollLock);
|
||||
void windowsInputTrackedState(WindowsInput * input);
|
||||
|
||||
#endif
|
||||
33
client/displayservers/Windows/platform.h
Normal file
33
client/displayservers/Windows/platform.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _H_LG_WINDOWS_PLATFORM_
|
||||
#define _H_LG_WINDOWS_PLATFORM_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <windows.h>
|
||||
|
||||
typedef bool (*WindowsMessageHandler)(void * opaque, HWND window,
|
||||
UINT message, WPARAM wParam, LPARAM lParam, LRESULT * result);
|
||||
|
||||
HWND windowsGetWindow(void);
|
||||
void windowsSetMessageHandler(WindowsMessageHandler handler, void * opaque);
|
||||
|
||||
#endif
|
||||
50
client/displayservers/Windows/window_size.c
Normal file
50
client/displayservers/Windows/window_size.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "window_size.h"
|
||||
|
||||
void windowsWindowSizeInit(WindowsWindowSize * state,
|
||||
int width, int height)
|
||||
{
|
||||
state->width = width;
|
||||
state->height = height;
|
||||
state->pending = false;
|
||||
}
|
||||
|
||||
bool windowsWindowSizeRequest(WindowsWindowSize * state,
|
||||
int width, int height, bool defer)
|
||||
{
|
||||
state->width = width;
|
||||
state->height = height;
|
||||
state->pending = defer;
|
||||
return !defer;
|
||||
}
|
||||
|
||||
bool windowsWindowSizeTakePending(WindowsWindowSize * state,
|
||||
bool defer, int * width, int * height)
|
||||
{
|
||||
if (!state->pending || defer)
|
||||
return false;
|
||||
|
||||
*width = state->width;
|
||||
*height = state->height;
|
||||
state->pending = false;
|
||||
return true;
|
||||
}
|
||||
41
client/displayservers/Windows/window_size.h
Normal file
41
client/displayservers/Windows/window_size.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _H_LG_WINDOWS_WINDOW_SIZE_
|
||||
#define _H_LG_WINDOWS_WINDOW_SIZE_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct WindowsWindowSize
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
bool pending;
|
||||
}
|
||||
WindowsWindowSize;
|
||||
|
||||
void windowsWindowSizeInit(WindowsWindowSize * state,
|
||||
int width, int height);
|
||||
bool windowsWindowSizeRequest(WindowsWindowSize * state,
|
||||
int width, int height, bool defer);
|
||||
bool windowsWindowSizeTakePending(WindowsWindowSize * state,
|
||||
bool defer, int * width, int * height);
|
||||
|
||||
#endif
|
||||
1847
client/displayservers/Windows/windows.c
Normal file
1847
client/displayservers/Windows/windows.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -93,6 +93,7 @@ void app_handleKeyboardModifiers(bool ctrl, bool shift, bool alt, bool super);
|
||||
void app_handleKeyboardLEDs(bool numLock, bool capsLock, bool scrollLock);
|
||||
void app_handleEnterEvent(bool entered);
|
||||
void app_handleGrabEvent(bool active);
|
||||
void app_handleCaptureLost(void);
|
||||
void app_handleFocusEvent(bool focused);
|
||||
void app_handleCloseEvent(void);
|
||||
void app_handleRenderEvent(const uint64_t timeUs);
|
||||
|
||||
@@ -30,16 +30,16 @@
|
||||
|
||||
struct EGLDynProcs
|
||||
{
|
||||
PFNEGLGETPLATFORMDISPLAYPROC eglGetPlatformDisplay;
|
||||
PFNEGLGETPLATFORMDISPLAYPROC eglGetPlatformDisplayEXT;
|
||||
PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC eglSwapBuffersWithDamageKHR;
|
||||
PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC eglSwapBuffersWithDamageEXT;
|
||||
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
|
||||
PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallback;
|
||||
PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallbackKHR;
|
||||
PFNGLBUFFERSTORAGEEXTPROC glBufferStorageEXT;
|
||||
PFNEGLCREATEIMAGEPROC eglCreateImage;
|
||||
PFNEGLDESTROYIMAGEPROC eglDestroyImage;
|
||||
PFNEGLGETPLATFORMDISPLAYPROC eglGetPlatformDisplay;
|
||||
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
|
||||
PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC eglSwapBuffersWithDamageKHR;
|
||||
PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC eglSwapBuffersWithDamageEXT;
|
||||
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
|
||||
PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallback;
|
||||
PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallbackKHR;
|
||||
PFNGLBUFFERSTORAGEEXTPROC glBufferStorageEXT;
|
||||
PFNEGLCREATEIMAGEPROC eglCreateImage;
|
||||
PFNEGLDESTROYIMAGEPROC eglDestroyImage;
|
||||
};
|
||||
|
||||
extern struct EGLDynProcs g_egl_dynProcs;
|
||||
|
||||
@@ -689,6 +689,11 @@ void app_handleGrabEvent(bool active)
|
||||
core_handleGrabEvent(active);
|
||||
}
|
||||
|
||||
void app_handleCaptureLost(void)
|
||||
{
|
||||
core_handleCaptureLost();
|
||||
}
|
||||
|
||||
void app_updateWindowPos(int x, int y)
|
||||
{
|
||||
g_state.windowPos.x = x;
|
||||
|
||||
@@ -306,6 +306,12 @@ void core_handleGrabEvent(bool active)
|
||||
core_handleMouseAbsolute();
|
||||
}
|
||||
|
||||
void core_handleCaptureLost(void)
|
||||
{
|
||||
if (g_cursor.grab)
|
||||
core_setGrabQuiet(false);
|
||||
}
|
||||
|
||||
void core_setGrab(bool enable)
|
||||
{
|
||||
core_setGrabQuiet(enable);
|
||||
|
||||
@@ -29,6 +29,7 @@ void core_updateKeyboardGrab(void);
|
||||
void core_invalidatePointer(bool detectInView);
|
||||
void core_setCursorInView(bool enable);
|
||||
void core_handleGrabEvent(bool active);
|
||||
void core_handleCaptureLost(void);
|
||||
void core_setGrab(bool enable);
|
||||
void core_setGrabQuiet(bool enable);
|
||||
bool core_warpPointer(int x, int y, bool exiting);
|
||||
|
||||
@@ -22,37 +22,49 @@
|
||||
|
||||
#include "egl_dynprocs.h"
|
||||
|
||||
struct EGLDynProcs g_egl_dynProcs = {0};
|
||||
struct EGLDynProcs g_egl_dynProcs = { 0 };
|
||||
|
||||
void egl_dynProcsInit(void)
|
||||
{
|
||||
g_egl_dynProcs.eglGetPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYPROC)
|
||||
g_egl_dynProcs.eglGetPlatformDisplay =
|
||||
(PFNEGLGETPLATFORMDISPLAYPROC)
|
||||
eglGetProcAddress("eglGetPlatformDisplay");
|
||||
g_egl_dynProcs.eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYPROC)
|
||||
g_egl_dynProcs.eglGetPlatformDisplayEXT =
|
||||
(PFNEGLGETPLATFORMDISPLAYEXTPROC)
|
||||
eglGetProcAddress("eglGetPlatformDisplayEXT");
|
||||
g_egl_dynProcs.glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)
|
||||
g_egl_dynProcs.glEGLImageTargetTexture2DOES =
|
||||
(PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)
|
||||
eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
||||
g_egl_dynProcs.eglSwapBuffersWithDamageKHR = (PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC)
|
||||
g_egl_dynProcs.eglSwapBuffersWithDamageKHR =
|
||||
(PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC)
|
||||
eglGetProcAddress("eglSwapBuffersWithDamageKHR");
|
||||
g_egl_dynProcs.eglSwapBuffersWithDamageEXT = (PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)
|
||||
g_egl_dynProcs.eglSwapBuffersWithDamageEXT =
|
||||
(PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)
|
||||
eglGetProcAddress("eglSwapBuffersWithDamageEXT");
|
||||
g_egl_dynProcs.glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKKHRPROC)
|
||||
g_egl_dynProcs.glDebugMessageCallback =
|
||||
(PFNGLDEBUGMESSAGECALLBACKKHRPROC)
|
||||
eglGetProcAddress("glDebugMessageCallback");
|
||||
g_egl_dynProcs.glDebugMessageCallbackKHR = (PFNGLDEBUGMESSAGECALLBACKKHRPROC)
|
||||
g_egl_dynProcs.glDebugMessageCallbackKHR =
|
||||
(PFNGLDEBUGMESSAGECALLBACKKHRPROC)
|
||||
eglGetProcAddress("glDebugMessageCallbackKHR");
|
||||
g_egl_dynProcs.glBufferStorageEXT = (PFNGLBUFFERSTORAGEEXTPROC)
|
||||
g_egl_dynProcs.glBufferStorageEXT =
|
||||
(PFNGLBUFFERSTORAGEEXTPROC)
|
||||
eglGetProcAddress("glBufferStorageEXT");
|
||||
g_egl_dynProcs.eglCreateImage = (PFNEGLCREATEIMAGEPROC)
|
||||
g_egl_dynProcs.eglCreateImage =
|
||||
(PFNEGLCREATEIMAGEPROC)
|
||||
eglGetProcAddress("eglCreateImage");
|
||||
g_egl_dynProcs.eglDestroyImage = (PFNEGLDESTROYIMAGEPROC)
|
||||
g_egl_dynProcs.eglDestroyImage =
|
||||
(PFNEGLDESTROYIMAGEPROC)
|
||||
eglGetProcAddress("eglDestroyImage");
|
||||
|
||||
if (!g_egl_dynProcs.eglCreateImage)
|
||||
g_egl_dynProcs.eglCreateImage = (PFNEGLCREATEIMAGEPROC)
|
||||
g_egl_dynProcs.eglCreateImage =
|
||||
(PFNEGLCREATEIMAGEPROC)
|
||||
eglGetProcAddress("eglCreateImageKHR");
|
||||
if (!g_egl_dynProcs.eglDestroyImage)
|
||||
g_egl_dynProcs.eglDestroyImage = (PFNEGLDESTROYIMAGEPROC)
|
||||
g_egl_dynProcs.eglDestroyImage =
|
||||
(PFNEGLDESTROYIMAGEPROC)
|
||||
eglGetProcAddress("eglDestroyImageKHR");
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -429,6 +429,28 @@ foreach(name IN ITEMS pointer-routing keyboard-routing held-keys)
|
||||
)
|
||||
endforeach()
|
||||
|
||||
add_executable(windows-input-tests
|
||||
windows_input_test.c
|
||||
../displayservers/Windows/input_event.c
|
||||
../displayservers/Windows/window_size.c
|
||||
../src/kb.c
|
||||
)
|
||||
target_compile_definitions(windows-input-tests PRIVATE
|
||||
CIMGUI_DEFINE_ENUMS_AND_STRUCTS=1
|
||||
)
|
||||
target_include_directories(windows-input-tests PRIVATE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../displayservers"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../src"
|
||||
"${PROJECT_TOP}/repos/gui/cimgui"
|
||||
"${PROJECT_TOP}/repos/gui/cimgui/imgui"
|
||||
)
|
||||
add_test(NAME windows-input-tests
|
||||
COMMAND windows-input-tests
|
||||
)
|
||||
set_tests_properties(windows-input-tests PROPERTIES
|
||||
TIMEOUT 10
|
||||
)
|
||||
|
||||
add_executable(mouse-tests
|
||||
mouse_test.c
|
||||
../src/core.c
|
||||
@@ -459,6 +481,7 @@ set(MOUSE_CASES
|
||||
capture-pending
|
||||
capture-revoked
|
||||
capture-release
|
||||
capture-lost
|
||||
capture-align
|
||||
x11-capture-exit
|
||||
capture-fallback
|
||||
|
||||
@@ -783,6 +783,32 @@ static void testCapRelease(void)
|
||||
CHECK(count(EV_MOTION) == 1);
|
||||
}
|
||||
|
||||
static void testCapLost(void)
|
||||
{
|
||||
reset();
|
||||
setLocal(50, 50);
|
||||
g_params.captureInputOnly = true;
|
||||
g_params.grabKeyboard = true;
|
||||
core_setGrabQuiet(true);
|
||||
|
||||
m.lock.on = true;
|
||||
CHECK(g_cursor.grab);
|
||||
CHECK(m.lock.req);
|
||||
CHECK(m.keyboardGrabbed);
|
||||
|
||||
m.count = 0;
|
||||
core_handleCaptureLost();
|
||||
CHECK(!g_cursor.grab);
|
||||
CHECK(!m.lock.req);
|
||||
CHECK(!m.keyboardGrabbed);
|
||||
CHECK(count(EV_UNCAPTURE) == 1);
|
||||
CHECK(count(EV_KEY_UNGRAB) == 1);
|
||||
|
||||
core_handleCaptureLost();
|
||||
CHECK(count(EV_UNCAPTURE) == 1);
|
||||
CHECK(count(EV_KEY_UNGRAB) == 1);
|
||||
}
|
||||
|
||||
static void testCapAlign(void)
|
||||
{
|
||||
reset();
|
||||
@@ -1098,6 +1124,7 @@ static const struct Test tests[] = {
|
||||
{ "capture-pending" , testCapWait },
|
||||
{ "capture-revoked" , testCapRevoke },
|
||||
{ "capture-release" , testCapRelease },
|
||||
{ "capture-lost" , testCapLost },
|
||||
{ "capture-align" , testCapAlign },
|
||||
{ "x11-capture-exit", testX11CapExit },
|
||||
{ "capture-fallback", testCapFallback },
|
||||
|
||||
575
client/tests/windows_input_test.c
Normal file
575
client/tests/windows_input_test.c
Normal file
@@ -0,0 +1,575 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Windows/input_event.h"
|
||||
#include "Windows/window_size.h"
|
||||
#include "input/keycodes.h"
|
||||
#include "test.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
enum TraceType
|
||||
{
|
||||
TRACE_POSITION,
|
||||
TRACE_RELATIVE,
|
||||
TRACE_BUTTON,
|
||||
TRACE_WHEEL,
|
||||
TRACE_KEY,
|
||||
TRACE_TEXT,
|
||||
TRACE_MODIFIERS,
|
||||
TRACE_LEDS,
|
||||
TRACE_ENTER,
|
||||
TRACE_FOCUS,
|
||||
};
|
||||
|
||||
struct Trace
|
||||
{
|
||||
enum TraceType type;
|
||||
int value;
|
||||
double x;
|
||||
double y;
|
||||
bool state;
|
||||
char text[16];
|
||||
};
|
||||
|
||||
#define TRACE_CAPACITY 256
|
||||
|
||||
struct Fixture
|
||||
{
|
||||
WindowsInput input;
|
||||
struct Trace trace[TRACE_CAPACITY];
|
||||
size_t count;
|
||||
};
|
||||
|
||||
static struct Trace * push(struct Fixture * fixture, enum TraceType type)
|
||||
{
|
||||
CHECK(fixture->count < TRACE_CAPACITY);
|
||||
struct Trace * trace = &fixture->trace[fixture->count++];
|
||||
memset(trace, 0, sizeof(*trace));
|
||||
trace->type = type;
|
||||
return trace;
|
||||
}
|
||||
|
||||
static void position(void * opaque, double x, double y)
|
||||
{
|
||||
struct Trace * trace = push(opaque, TRACE_POSITION);
|
||||
trace->x = x;
|
||||
trace->y = y;
|
||||
}
|
||||
|
||||
static void relative(void * opaque, double x, double y,
|
||||
double rawX, double rawY)
|
||||
{
|
||||
struct Trace * trace = push(opaque, TRACE_RELATIVE);
|
||||
trace->x = x;
|
||||
trace->y = y;
|
||||
CHECK(x == rawX);
|
||||
CHECK(y == rawY);
|
||||
}
|
||||
|
||||
static void button(void * opaque, unsigned int button, bool pressed)
|
||||
{
|
||||
struct Trace * trace = push(opaque, TRACE_BUTTON);
|
||||
trace->value = button;
|
||||
trace->state = pressed;
|
||||
}
|
||||
|
||||
static void wheel(void * opaque, double motion)
|
||||
{
|
||||
struct Trace * trace = push(opaque, TRACE_WHEEL);
|
||||
trace->x = motion;
|
||||
}
|
||||
|
||||
static void key(void * opaque, int scancode, bool pressed)
|
||||
{
|
||||
struct Trace * trace = push(opaque, TRACE_KEY);
|
||||
trace->value = scancode;
|
||||
trace->state = pressed;
|
||||
}
|
||||
|
||||
static void textInput(void * opaque, const char * text)
|
||||
{
|
||||
struct Trace * trace = push(opaque, TRACE_TEXT);
|
||||
snprintf(trace->text, sizeof(trace->text), "%s", text);
|
||||
}
|
||||
|
||||
static void modifiers(void * opaque, bool ctrl, bool shift,
|
||||
bool alt, bool super)
|
||||
{
|
||||
struct Trace * trace = push(opaque, TRACE_MODIFIERS);
|
||||
trace->value = ctrl | shift << 1 | alt << 2 | super << 3;
|
||||
}
|
||||
|
||||
static void leds(void * opaque, bool numLock, bool capsLock,
|
||||
bool scrollLock)
|
||||
{
|
||||
struct Trace * trace = push(opaque, TRACE_LEDS);
|
||||
trace->value = numLock | capsLock << 1 | scrollLock << 2;
|
||||
}
|
||||
|
||||
static void enter(void * opaque, bool entered)
|
||||
{
|
||||
struct Trace * trace = push(opaque, TRACE_ENTER);
|
||||
trace->state = entered;
|
||||
}
|
||||
|
||||
static void focus(void * opaque, bool focused)
|
||||
{
|
||||
struct Trace * trace = push(opaque, TRACE_FOCUS);
|
||||
trace->state = focused;
|
||||
}
|
||||
|
||||
static const LG_DSInputSink sink =
|
||||
{
|
||||
.position = position,
|
||||
.relative = relative,
|
||||
.button = button,
|
||||
.wheel = wheel,
|
||||
.key = key,
|
||||
.text = textInput,
|
||||
.modifiers = modifiers,
|
||||
.leds = leds,
|
||||
.enter = enter,
|
||||
.focus = focus,
|
||||
};
|
||||
|
||||
static void init(struct Fixture * fixture)
|
||||
{
|
||||
memset(fixture, 0, sizeof(*fixture));
|
||||
windowsInputInit(&fixture->input, &sink, fixture);
|
||||
}
|
||||
|
||||
static double doubleFromBits(uint64_t bits)
|
||||
{
|
||||
double value;
|
||||
_Static_assert(sizeof(value) == sizeof(bits), "Unexpected double size");
|
||||
memcpy(&value, &bits, sizeof(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
static void testScanCodes(void)
|
||||
{
|
||||
CHECK(windowsInputMapScanCode(0x1E, false) == LG_KEY_A);
|
||||
CHECK(windowsInputMapScanCode(0x1D, false) == LG_KEY_LEFTCTRL);
|
||||
CHECK(windowsInputMapScanCode(0x1D, true ) == LG_KEY_RIGHTCTRL);
|
||||
CHECK(windowsInputMapScanCode(0x5B, true ) == LG_KEY_LEFTMETA);
|
||||
CHECK(windowsInputMapScanCode(0x53, true ) == LG_KEY_DELETE);
|
||||
CHECK(windowsInputMapScanCode(0x00, false) == LG_KEY_RESERVED);
|
||||
CHECK(windowsInputMapScanCode(0xFF, false) == LG_KEY_RESERVED);
|
||||
CHECK(windowsInputMapPrintScreen(false) == LG_KEY_PRINT);
|
||||
CHECK(windowsInputMapPrintScreen(true ) == LG_KEY_SYSRQ);
|
||||
}
|
||||
|
||||
static void testKeyboardRouting(void)
|
||||
{
|
||||
struct Fixture fixture;
|
||||
init(&fixture);
|
||||
|
||||
windowsInputText(&fixture.input, "ignored");
|
||||
CHECK(!windowsInputKey(&fixture.input, 0x1E, false, true, false));
|
||||
CHECK(windowsInputFocus(&fixture.input, true));
|
||||
CHECK(!windowsInputFocus(&fixture.input, true));
|
||||
CHECK(windowsInputKey(&fixture.input, 0x1E, false, true, false));
|
||||
windowsInputText(&fixture.input, "a");
|
||||
windowsInputSetKeyboardGrabbed(&fixture.input, true);
|
||||
CHECK(!windowsInputKey(&fixture.input, 0x1E, false, false, false));
|
||||
CHECK(windowsInputKey(&fixture.input, 0x1E, false, false, true));
|
||||
windowsInputText(&fixture.input, "ignored");
|
||||
windowsInputState(&fixture.input, true, false, true, false,
|
||||
true, false, true);
|
||||
|
||||
CHECK(fixture.count == 6);
|
||||
CHECK(fixture.trace[0].type == TRACE_FOCUS);
|
||||
CHECK(fixture.trace[0].state == true);
|
||||
CHECK(fixture.trace[1].type == TRACE_KEY);
|
||||
CHECK(fixture.trace[1].value == LG_KEY_A);
|
||||
CHECK(fixture.trace[1].state == true);
|
||||
CHECK(fixture.trace[2].type == TRACE_TEXT);
|
||||
CHECK(strcmp(fixture.trace[2].text, "a") == 0);
|
||||
CHECK(fixture.trace[3].type == TRACE_KEY);
|
||||
CHECK(fixture.trace[3].value == LG_KEY_A);
|
||||
CHECK(fixture.trace[3].state == false);
|
||||
CHECK(fixture.trace[4].type == TRACE_MODIFIERS);
|
||||
CHECK(fixture.trace[4].value == 5);
|
||||
CHECK(fixture.trace[5].type == TRACE_LEDS);
|
||||
CHECK(fixture.trace[5].value == 5);
|
||||
}
|
||||
|
||||
static void testPrintScreenLatch(void)
|
||||
{
|
||||
struct Fixture fixture;
|
||||
init(&fixture);
|
||||
|
||||
CHECK(windowsInputMapPrintScreenEvent(
|
||||
&fixture.input, true, true) == LG_KEY_SYSRQ);
|
||||
CHECK(windowsInputMapPrintScreenEvent(
|
||||
&fixture.input, false, true) == LG_KEY_SYSRQ);
|
||||
CHECK(windowsInputMapPrintScreenEvent(
|
||||
&fixture.input, false, false) == LG_KEY_SYSRQ);
|
||||
CHECK(windowsInputMapPrintScreenEvent(
|
||||
&fixture.input, false, true) == LG_KEY_PRINT);
|
||||
CHECK(windowsInputMapPrintScreenEvent(
|
||||
&fixture.input, true, false) == LG_KEY_PRINT);
|
||||
|
||||
CHECK(windowsInputFocus(&fixture.input, true));
|
||||
CHECK(windowsInputMapPrintScreenEvent(
|
||||
&fixture.input, true, true) == LG_KEY_SYSRQ);
|
||||
CHECK(windowsInputFocus(&fixture.input, false));
|
||||
CHECK(windowsInputMapPrintScreenEvent(
|
||||
&fixture.input, false, false) == LG_KEY_PRINT);
|
||||
}
|
||||
|
||||
static void testHeldKeys(void)
|
||||
{
|
||||
struct Fixture fixture;
|
||||
init(&fixture);
|
||||
|
||||
const int keys[] =
|
||||
{
|
||||
LG_KEY_A,
|
||||
LG_KEY_RESERVED,
|
||||
LG_KEY_LEFTSHIFT,
|
||||
LG_KEY_MAX,
|
||||
};
|
||||
|
||||
CHECK(windowsInputSyncHeldKeys(&fixture.input,
|
||||
keys, sizeof(keys) / sizeof(*keys), false) == 0);
|
||||
CHECK(windowsInputFocus(&fixture.input, true));
|
||||
CHECK(windowsInputSyncHeldKeys(&fixture.input,
|
||||
keys, sizeof(keys) / sizeof(*keys), false) == 2);
|
||||
windowsInputTrackedState(&fixture.input);
|
||||
|
||||
windowsInputSetKeyboardGrabbed(&fixture.input, true);
|
||||
CHECK(windowsInputSyncHeldKeys(&fixture.input, keys, 1, false) == 0);
|
||||
CHECK(windowsInputSyncHeldKeys(&fixture.input, keys, 1, true ) == 1);
|
||||
CHECK(windowsInputSyncHeldKeys(&fixture.input, NULL, 1, true) == 0);
|
||||
|
||||
CHECK(fixture.count == 6);
|
||||
CHECK(fixture.trace[0].type == TRACE_FOCUS);
|
||||
CHECK(fixture.trace[1].type == TRACE_KEY);
|
||||
CHECK(fixture.trace[1].value == LG_KEY_LEFTSHIFT);
|
||||
CHECK(fixture.trace[2].type == TRACE_KEY);
|
||||
CHECK(fixture.trace[2].value == LG_KEY_A);
|
||||
CHECK(fixture.trace[3].type == TRACE_MODIFIERS);
|
||||
CHECK(fixture.trace[3].value == 2);
|
||||
CHECK(fixture.trace[4].type == TRACE_LEDS);
|
||||
CHECK(fixture.trace[5].type == TRACE_KEY);
|
||||
CHECK(fixture.trace[5].value == LG_KEY_A);
|
||||
}
|
||||
|
||||
static void testHeldKeyModifierOrder(void)
|
||||
{
|
||||
struct Fixture fixture;
|
||||
init(&fixture);
|
||||
|
||||
const int keys[] =
|
||||
{
|
||||
LG_KEY_SYSRQ,
|
||||
LG_KEY_LEFTALT,
|
||||
};
|
||||
|
||||
CHECK(windowsInputFocus(&fixture.input, true));
|
||||
CHECK(windowsInputSyncHeldKeys(&fixture.input,
|
||||
keys, sizeof(keys) / sizeof(*keys), false) == 2);
|
||||
CHECK(fixture.count == 3);
|
||||
CHECK(fixture.trace[1].type == TRACE_KEY);
|
||||
CHECK(fixture.trace[1].value == LG_KEY_LEFTALT);
|
||||
CHECK(fixture.trace[2].type == TRACE_KEY);
|
||||
CHECK(fixture.trace[2].value == LG_KEY_SYSRQ);
|
||||
}
|
||||
|
||||
static void testKeyboardStateTransitions(void)
|
||||
{
|
||||
struct Fixture fixture;
|
||||
init(&fixture);
|
||||
|
||||
CHECK(windowsInputFocus(&fixture.input, true));
|
||||
windowsInputSetKeyboardGrabbed(&fixture.input, true);
|
||||
windowsInputState(&fixture.input, false, false, false, false,
|
||||
true, false, false);
|
||||
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_LEFTCTRL, true, true));
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_RIGHTCTRL, true, true));
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_LEFTCTRL, false, true));
|
||||
windowsInputTrackedState(&fixture.input);
|
||||
CHECK(fixture.trace[6].type == TRACE_MODIFIERS);
|
||||
CHECK(fixture.trace[6].value == 1);
|
||||
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_RIGHTCTRL, false, true));
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_CAPSLOCK, true, true));
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_CAPSLOCK, true, true));
|
||||
windowsInputTrackedState(&fixture.input);
|
||||
CHECK(fixture.trace[12].type == TRACE_LEDS);
|
||||
CHECK(fixture.trace[12].value == 3);
|
||||
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_CAPSLOCK, false, true));
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_CAPSLOCK, true, true));
|
||||
windowsInputTrackedState(&fixture.input);
|
||||
CHECK(fixture.trace[16].type == TRACE_LEDS);
|
||||
CHECK(fixture.trace[16].value == 1);
|
||||
|
||||
CHECK(windowsInputFocus(&fixture.input, false));
|
||||
CHECK(windowsInputFocus(&fixture.input, true));
|
||||
windowsInputTrackedState(&fixture.input);
|
||||
CHECK(fixture.trace[19].type == TRACE_MODIFIERS);
|
||||
CHECK(fixture.trace[19].value == 0);
|
||||
|
||||
CHECK(fixture.input.numLock);
|
||||
CHECK(!fixture.input.capsLock);
|
||||
CHECK(!fixture.input.scrollLock);
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_NUMLOCK, true, true));
|
||||
CHECK(!fixture.input.numLock);
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_NUMLOCK, true, true));
|
||||
CHECK(!fixture.input.numLock);
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_NUMLOCK, false, true));
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_NUMLOCK, true, true));
|
||||
CHECK(fixture.input.numLock);
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_SCROLLLOCK, true, true));
|
||||
CHECK(fixture.input.scrollLock);
|
||||
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_LEFTSHIFT, true, true));
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_RIGHTALT, true, true));
|
||||
CHECK(windowsInputKeyCode(
|
||||
&fixture.input, LG_KEY_LEFTMETA, true, true));
|
||||
windowsInputTrackedState(&fixture.input);
|
||||
CHECK(fixture.count == 31);
|
||||
CHECK(fixture.trace[29].type == TRACE_MODIFIERS);
|
||||
CHECK(fixture.trace[29].value == 14);
|
||||
CHECK(fixture.trace[30].type == TRACE_LEDS);
|
||||
CHECK(fixture.trace[30].value == 5);
|
||||
}
|
||||
|
||||
static void testPointerRouting(void)
|
||||
{
|
||||
struct Fixture fixture;
|
||||
init(&fixture);
|
||||
|
||||
CHECK(windowsInputPointerEnter(&fixture.input, 10.0, 20.0));
|
||||
windowsInputPointerMotion(&fixture.input, 12.0, 24.0);
|
||||
CHECK(windowsInputPointerButton(&fixture.input, 1, true));
|
||||
CHECK(windowsInputPointerButton(&fixture.input, 1, false));
|
||||
windowsInputPointerWheel(&fixture.input, 0.5);
|
||||
windowsInputPointerWheel(&fixture.input, 0.5);
|
||||
windowsInputSetPointerGrabbed(&fixture.input, true);
|
||||
windowsInputPointerMotion(&fixture.input, 14.0, 28.0);
|
||||
windowsInputRelativeMotion(&fixture.input, 2.0, -3.0);
|
||||
CHECK(!windowsInputPointerLeave(&fixture.input));
|
||||
windowsInputSetPointerGrabbed(&fixture.input, false);
|
||||
CHECK(!fixture.input.entered);
|
||||
|
||||
CHECK(fixture.count == 11);
|
||||
CHECK(fixture.trace[0].type == TRACE_ENTER);
|
||||
CHECK(fixture.trace[1].type == TRACE_POSITION);
|
||||
CHECK(fixture.trace[2].type == TRACE_POSITION);
|
||||
CHECK(fixture.trace[3].type == TRACE_BUTTON);
|
||||
CHECK(fixture.trace[3].state == true);
|
||||
CHECK(fixture.trace[4].type == TRACE_BUTTON);
|
||||
CHECK(fixture.trace[4].state == false);
|
||||
CHECK(fixture.trace[5].type == TRACE_WHEEL);
|
||||
CHECK(fixture.trace[5].x == -0.5);
|
||||
CHECK(fixture.trace[6].type == TRACE_BUTTON);
|
||||
CHECK(fixture.trace[6].value == 4);
|
||||
CHECK(fixture.trace[6].state == true);
|
||||
CHECK(fixture.trace[7].type == TRACE_BUTTON);
|
||||
CHECK(fixture.trace[7].value == 4);
|
||||
CHECK(fixture.trace[7].state == false);
|
||||
CHECK(fixture.trace[8].type == TRACE_WHEEL);
|
||||
CHECK(fixture.trace[8].x == -0.5);
|
||||
CHECK(fixture.trace[9].type == TRACE_RELATIVE);
|
||||
CHECK(fixture.trace[10].type == TRACE_ENTER);
|
||||
CHECK(fixture.trace[10].state == false);
|
||||
}
|
||||
|
||||
static void testPointerLeaveAndCaptureLoss(void)
|
||||
{
|
||||
struct Fixture fixture;
|
||||
init(&fixture);
|
||||
|
||||
CHECK(windowsInputPointerEnter(&fixture.input, 1.0, 2.0));
|
||||
CHECK(windowsInputPointerButton(&fixture.input, 1, true));
|
||||
CHECK(windowsInputPointerButton(&fixture.input, 3, true));
|
||||
CHECK(!windowsInputPointerLeave(&fixture.input));
|
||||
CHECK(fixture.input.leavePending);
|
||||
windowsInputReleaseButtons(&fixture.input);
|
||||
CHECK(fixture.input.buttons == 0);
|
||||
CHECK(!fixture.input.entered);
|
||||
CHECK(!fixture.input.leavePending);
|
||||
|
||||
CHECK(fixture.count == 7);
|
||||
CHECK(fixture.trace[4].type == TRACE_BUTTON);
|
||||
CHECK(fixture.trace[4].value == 1);
|
||||
CHECK(fixture.trace[4].state == false);
|
||||
CHECK(fixture.trace[5].type == TRACE_BUTTON);
|
||||
CHECK(fixture.trace[5].value == 3);
|
||||
CHECK(fixture.trace[5].state == false);
|
||||
CHECK(fixture.trace[6].type == TRACE_ENTER);
|
||||
CHECK(fixture.trace[6].state == false);
|
||||
|
||||
CHECK(windowsInputPointerEnter(&fixture.input, 3.0, 4.0));
|
||||
windowsInputSetPointerGrabbed(&fixture.input, true);
|
||||
CHECK(!windowsInputPointerLeave(&fixture.input));
|
||||
CHECK(fixture.input.leavePending);
|
||||
windowsInputSetPointerGrabbed(&fixture.input, false);
|
||||
CHECK(!fixture.input.entered);
|
||||
|
||||
CHECK(windowsInputPointerEnter(&fixture.input, 5.0, 6.0));
|
||||
CHECK(windowsInputPointerButton(&fixture.input, 1, true));
|
||||
CHECK(!windowsInputPointerLeave(&fixture.input));
|
||||
CHECK(!windowsInputPointerEnter(&fixture.input, 7.0, 8.0));
|
||||
CHECK(!fixture.input.leavePending);
|
||||
CHECK(windowsInputPointerButton(&fixture.input, 1, false));
|
||||
CHECK(fixture.input.entered);
|
||||
}
|
||||
|
||||
static size_t countTrace(const struct Fixture * fixture,
|
||||
enum TraceType type, int value, bool state)
|
||||
{
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < fixture->count; ++i)
|
||||
{
|
||||
const struct Trace * trace = &fixture->trace[i];
|
||||
if (trace->type == type && trace->value == value &&
|
||||
trace->state == state)
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void testPointerWheel(void)
|
||||
{
|
||||
struct Fixture fixture;
|
||||
init(&fixture);
|
||||
|
||||
CHECK(windowsInputPointerEnter(&fixture.input, 0.0, 0.0));
|
||||
windowsInputPointerWheel(&fixture.input, 2.25);
|
||||
windowsInputPointerWheel(&fixture.input, 0.75);
|
||||
windowsInputPointerWheel(&fixture.input, -2.5);
|
||||
windowsInputPointerWheel(&fixture.input, -0.5);
|
||||
|
||||
CHECK(fixture.input.wheel == 0.0);
|
||||
CHECK(countTrace(&fixture, TRACE_BUTTON, 4, true ) == 3);
|
||||
CHECK(countTrace(&fixture, TRACE_BUTTON, 4, false) == 3);
|
||||
CHECK(countTrace(&fixture, TRACE_BUTTON, 5, true ) == 3);
|
||||
CHECK(countTrace(&fixture, TRACE_BUTTON, 5, false) == 3);
|
||||
CHECK(countTrace(&fixture, TRACE_WHEEL, 0, false) == 4);
|
||||
|
||||
const size_t count = fixture.count;
|
||||
const double nan = doubleFromBits(UINT64_C(0x7FF8000000000000));
|
||||
const double infinity = doubleFromBits(UINT64_C(0x7FF0000000000000));
|
||||
windowsInputPointerWheel(&fixture.input, 0.0);
|
||||
windowsInputPointerWheel(&fixture.input, nan);
|
||||
windowsInputPointerWheel(&fixture.input, infinity);
|
||||
CHECK(fixture.count == count);
|
||||
}
|
||||
|
||||
static void testInvalidPointerInput(void)
|
||||
{
|
||||
struct Fixture fixture;
|
||||
init(&fixture);
|
||||
|
||||
const double nan = doubleFromBits(UINT64_C(0x7FF8000000000000));
|
||||
const double infinity = doubleFromBits(UINT64_C(0x7FF0000000000000));
|
||||
CHECK(!windowsInputPointerEnter(&fixture.input, nan, 0.0));
|
||||
CHECK(!windowsInputPointerEnter(&fixture.input, 0.0, infinity));
|
||||
CHECK(!windowsInputPointerButton(&fixture.input, 0, true));
|
||||
CHECK(!windowsInputPointerButton(&fixture.input, 32, true));
|
||||
CHECK(windowsInputPointerEnter(&fixture.input, 1.0, 1.0));
|
||||
CHECK(windowsInputPointerButton(&fixture.input, 1, true));
|
||||
CHECK(!windowsInputPointerButton(&fixture.input, 1, true));
|
||||
CHECK(windowsInputPointerButton(&fixture.input, 1, false));
|
||||
CHECK(!windowsInputPointerButton(&fixture.input, 1, false));
|
||||
|
||||
const size_t count = fixture.count;
|
||||
windowsInputPointerMotion(&fixture.input, nan, 1.0);
|
||||
windowsInputPointerMotion(&fixture.input, 1.0, infinity);
|
||||
windowsInputRelativeMotion(&fixture.input, nan, 1.0);
|
||||
CHECK(fixture.count == count);
|
||||
|
||||
windowsInputText(&fixture.input, NULL);
|
||||
windowsInputText(&fixture.input, "");
|
||||
CHECK(fixture.count == count);
|
||||
}
|
||||
|
||||
static void testWindowSizePolicy(void)
|
||||
{
|
||||
WindowsWindowSize state;
|
||||
windowsWindowSizeInit(&state, 800, 600);
|
||||
CHECK(state.width == 800);
|
||||
CHECK(state.height == 600);
|
||||
CHECK(!state.pending);
|
||||
|
||||
CHECK(!windowsWindowSizeRequest(&state, 1024, 768, true));
|
||||
CHECK(state.width == 1024);
|
||||
CHECK(state.height == 768);
|
||||
CHECK(state.pending);
|
||||
|
||||
int width = -1;
|
||||
int height = -1;
|
||||
CHECK(!windowsWindowSizeTakePending(
|
||||
&state, true, &width, &height));
|
||||
CHECK(width == -1);
|
||||
CHECK(height == -1);
|
||||
CHECK(state.pending);
|
||||
|
||||
CHECK(!windowsWindowSizeRequest(&state, 1280, 720, true));
|
||||
CHECK(windowsWindowSizeTakePending(
|
||||
&state, false, &width, &height));
|
||||
CHECK(width == 1280);
|
||||
CHECK(height == 720);
|
||||
CHECK(!state.pending);
|
||||
|
||||
CHECK(windowsWindowSizeRequest(&state, 640, 480, false));
|
||||
CHECK(!state.pending);
|
||||
CHECK(!windowsWindowSizeTakePending(
|
||||
&state, false, &width, &height));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
testScanCodes();
|
||||
testKeyboardRouting();
|
||||
testPrintScreenLatch();
|
||||
testHeldKeys();
|
||||
testHeldKeyModifierOrder();
|
||||
testKeyboardStateTransitions();
|
||||
testPointerRouting();
|
||||
testPointerLeaveAndCaptureLoss();
|
||||
testPointerWheel();
|
||||
testInvalidPointerInput();
|
||||
testWindowSizePolicy();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user