wind+libui: Add support for keyboard events
This commit is contained in:
parent
65b7518e50
commit
d3cc4d109b
@ -24,6 +24,7 @@ namespace ui
|
||||
Result<EventResult> handle_mouse_leave() override;
|
||||
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
||||
Result<EventResult> handle_mouse_up(Point position, int buttons) override;
|
||||
Result<EventResult> handle_key_event(const ui::KeyEventRequest& request) override;
|
||||
Result<void> draw(Canvas& canvas) override;
|
||||
|
||||
private:
|
||||
|
@ -24,6 +24,7 @@ namespace ui
|
||||
Result<EventResult> handle_mouse_leave() override;
|
||||
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
||||
Result<EventResult> handle_mouse_up(Point position, int buttons) override;
|
||||
Result<EventResult> handle_key_event(const ui::KeyEventRequest& request) override;
|
||||
Result<void> draw(Canvas& canvas) override;
|
||||
|
||||
private:
|
||||
|
14
libui/include/ui/Key.h
Normal file
14
libui/include/ui/Key.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <moon/Keyboard.h>
|
||||
|
||||
namespace ui
|
||||
{
|
||||
enum Modifier
|
||||
{
|
||||
Mod_Shift = (1 << 0),
|
||||
Mod_Alt = (1 << 1),
|
||||
Mod_Super = (1 << 2),
|
||||
Mod_AltGr = (1 << 3),
|
||||
Mod_Ctrl = (1 << 4)
|
||||
};
|
||||
}
|
@ -34,6 +34,7 @@ namespace ui
|
||||
Result<EventResult> handle_mouse_leave() override;
|
||||
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
||||
Result<EventResult> handle_mouse_up(Point position, int buttons) override;
|
||||
Result<EventResult> handle_key_event(const ui::KeyEventRequest& request) override;
|
||||
|
||||
Result<void> draw(Canvas& canvas) override;
|
||||
|
||||
@ -55,6 +56,7 @@ namespace ui
|
||||
Result<EventResult> handle_mouse_leave() override;
|
||||
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
||||
Result<EventResult> handle_mouse_up(Point position, int buttons) override;
|
||||
Result<EventResult> handle_key_event(const ui::KeyEventRequest& request) override;
|
||||
|
||||
Result<void> draw(Canvas& canvas) override;
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <ui/Canvas.h>
|
||||
#include <ui/Point.h>
|
||||
#include <ui/Rect.h>
|
||||
#include <ui/ipc/Client.h>
|
||||
|
||||
namespace ui
|
||||
{
|
||||
@ -50,6 +51,12 @@ namespace ui
|
||||
return EventResult::DidNotHandle;
|
||||
}
|
||||
|
||||
virtual Result<EventResult> handle_key_event(const ui::KeyEventRequest& request)
|
||||
{
|
||||
ignore(request);
|
||||
return EventResult::DidNotHandle;
|
||||
}
|
||||
|
||||
virtual Result<void> draw(Canvas& canvas);
|
||||
|
||||
void set_window(Window* window, Rect rect, Badge<Window>)
|
||||
|
@ -49,6 +49,7 @@ namespace ui
|
||||
Result<ui::EventResult> handle_mouse_leave();
|
||||
Result<ui::EventResult> handle_mouse_move(ui::Point position);
|
||||
Result<ui::EventResult> handle_mouse_buttons(ui::Point position, int buttons);
|
||||
Result<ui::EventResult> handle_key_event(const ui::KeyEventRequest& request);
|
||||
|
||||
int id() const
|
||||
{
|
||||
|
@ -9,7 +9,9 @@
|
||||
|
||||
#pragma once
|
||||
#include <os/IPC.h>
|
||||
#include <ui/Key.h>
|
||||
#include <ui/Point.h>
|
||||
#include <ui/Rect.h>
|
||||
|
||||
namespace ui
|
||||
{
|
||||
@ -20,7 +22,8 @@ namespace ui
|
||||
WINDOW_CLOSE_REQUEST_ID,
|
||||
MOUSE_EVENT_REQUEST_ID,
|
||||
MOUSE_LEAVE_REQUEST_ID,
|
||||
GET_SCREEN_RECT_RESPONSE_ID
|
||||
GET_SCREEN_RECT_RESPONSE_ID,
|
||||
KEY_EVENT_REQUEST_ID,
|
||||
};
|
||||
|
||||
struct CreateWindowResponse
|
||||
@ -60,4 +63,18 @@ namespace ui
|
||||
|
||||
Rect rect;
|
||||
};
|
||||
|
||||
struct KeyEventRequest
|
||||
{
|
||||
static constexpr u8 ID = KEY_EVENT_REQUEST_ID;
|
||||
|
||||
int window;
|
||||
|
||||
bool pressed;
|
||||
|
||||
char letter;
|
||||
char key;
|
||||
moon::KeyCode code;
|
||||
int modifiers;
|
||||
};
|
||||
}
|
||||
|
@ -132,6 +132,14 @@ namespace ui
|
||||
window->draw();
|
||||
return {};
|
||||
}
|
||||
case KEY_EVENT_REQUEST_ID: {
|
||||
KeyEventRequest request;
|
||||
READ_MESSAGE(request);
|
||||
auto* window = find_window(request.window);
|
||||
if (window->handle_key_event(request).value_or(ui::EventResult::DidNotHandle) == ui::EventResult::DidHandle)
|
||||
window->draw();
|
||||
return {};
|
||||
}
|
||||
default: fail("Unexpected IPC request from server!");
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,11 @@ namespace ui
|
||||
return m_child->handle_mouse_up(position, buttons);
|
||||
}
|
||||
|
||||
Result<EventResult> Button::handle_key_event(const ui::KeyEventRequest& request)
|
||||
{
|
||||
return m_child->handle_key_event(request);
|
||||
}
|
||||
|
||||
Result<void> Button::draw(Canvas& canvas)
|
||||
{
|
||||
return m_child->draw(canvas);
|
||||
|
@ -47,6 +47,11 @@ namespace ui
|
||||
return ui::EventResult::DidNotHandle;
|
||||
}
|
||||
|
||||
Result<EventResult> Container::handle_key_event(const ui::KeyEventRequest& request)
|
||||
{
|
||||
return m_widget->handle_key_event(request);
|
||||
}
|
||||
|
||||
Result<void> Container::draw(Canvas& canvas)
|
||||
{
|
||||
auto rect = ui::Rect { m_widget->rect().pos.x - m_rect.pos.x, m_widget->rect().pos.y - m_rect.pos.y,
|
||||
|
@ -64,6 +64,19 @@ namespace ui
|
||||
return ui::EventResult::DidNotHandle;
|
||||
}
|
||||
|
||||
Result<EventResult> HorizontalLayout::handle_key_event(const ui::KeyEventRequest& request)
|
||||
{
|
||||
EventResult result = ui::EventResult::DidNotHandle;
|
||||
|
||||
for (auto widget : m_widgets)
|
||||
{
|
||||
auto rc = TRY(widget->handle_key_event(request));
|
||||
if (rc == ui::EventResult::DidHandle) result = rc;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result<void> HorizontalLayout::draw(Canvas& canvas)
|
||||
{
|
||||
for (auto widget : m_widgets)
|
||||
@ -159,6 +172,19 @@ namespace ui
|
||||
return ui::EventResult::DidNotHandle;
|
||||
}
|
||||
|
||||
Result<EventResult> VerticalLayout::handle_key_event(const ui::KeyEventRequest& request)
|
||||
{
|
||||
EventResult result = ui::EventResult::DidNotHandle;
|
||||
|
||||
for (auto widget : m_widgets)
|
||||
{
|
||||
auto rc = TRY(widget->handle_key_event(request));
|
||||
if (rc == ui::EventResult::DidHandle) result = rc;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result<void> VerticalLayout::draw(Canvas& canvas)
|
||||
{
|
||||
for (auto widget : m_widgets)
|
||||
|
@ -114,4 +114,10 @@ namespace ui
|
||||
m_old_mouse_buttons = buttons;
|
||||
return result;
|
||||
}
|
||||
|
||||
Result<ui::EventResult> Window::handle_key_event(const ui::KeyEventRequest& request)
|
||||
{
|
||||
if (!m_main_widget) return ui::EventResult::DidNotHandle;
|
||||
return m_main_widget->handle_key_event(request);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ set(SOURCES
|
||||
Window.cpp
|
||||
IPC.cpp
|
||||
IPC.h
|
||||
Keyboard.cpp
|
||||
Keyboard.h
|
||||
Client.h
|
||||
)
|
||||
|
||||
|
305
wind/Keyboard.cpp
Normal file
305
wind/Keyboard.cpp
Normal file
@ -0,0 +1,305 @@
|
||||
#include "Keyboard.h"
|
||||
#include <luna/CType.h>
|
||||
|
||||
static const char table[] = {
|
||||
// Function keys
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
// System keys
|
||||
'\x1b',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
// Modifier keys
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0', // or AltGr on some keyboards
|
||||
'\0',
|
||||
'\0',
|
||||
// Navigation keys
|
||||
'\t',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
// Editing keys
|
||||
'\b',
|
||||
'\n',
|
||||
'\0',
|
||||
'\x7f',
|
||||
'\n',
|
||||
// Lock keys
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
// Keypad keys
|
||||
'0',
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'.',
|
||||
'+',
|
||||
'-',
|
||||
'*',
|
||||
'/',
|
||||
// Character keys (depending on keyboard layout), examples in US QWERTY
|
||||
'`', // `
|
||||
'1', // 1
|
||||
'2', // 2
|
||||
'3', // 3
|
||||
'4', // 4
|
||||
'5', // 5
|
||||
'6', // 6
|
||||
'7', // 7
|
||||
'8', // 8
|
||||
'9', // 9
|
||||
'0', // 0
|
||||
'-', // -
|
||||
'=', // =
|
||||
'q', // Q
|
||||
'w', // W
|
||||
'e', // E
|
||||
'r', // R
|
||||
't', // T
|
||||
'y', // Y
|
||||
'u', // U
|
||||
'i', // I
|
||||
'o', // O
|
||||
'p', // P
|
||||
'[', // [
|
||||
']', // ]
|
||||
'a', // A
|
||||
's', // S
|
||||
'd', // D
|
||||
'f', // F
|
||||
'g', // G
|
||||
'h', // H
|
||||
'j', // J
|
||||
'k', // K
|
||||
'l', // L
|
||||
';', // ;
|
||||
'\'', // '
|
||||
'#', // #
|
||||
'\\', // Backslash
|
||||
'z', // Z
|
||||
'x', // X
|
||||
'c', // C
|
||||
'v', // V
|
||||
'b', // B
|
||||
'n', // N
|
||||
'm', // M
|
||||
',', // ,
|
||||
'.', // .
|
||||
'/', // /
|
||||
' ', // Space
|
||||
// Unknown key
|
||||
'\0',
|
||||
};
|
||||
|
||||
static const char shift_table[] = {
|
||||
// Function keys
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
// System keys
|
||||
'\x1b',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
// Modifier keys
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0', // or AltGr on some keyboards
|
||||
'\0',
|
||||
'\0',
|
||||
// Navigation keys
|
||||
'\t',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
// Editing keys
|
||||
'\b',
|
||||
'\n',
|
||||
'\0',
|
||||
'\x7f',
|
||||
'\n',
|
||||
// Lock keys
|
||||
'\0',
|
||||
'\0',
|
||||
'\0',
|
||||
// Keypad keys
|
||||
'0',
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'.',
|
||||
'+',
|
||||
'-',
|
||||
'*',
|
||||
'/',
|
||||
// Character keys (depending on keyboard layout), examples in US QWERTY
|
||||
'~', // `
|
||||
'!',
|
||||
'@',
|
||||
'#',
|
||||
'$',
|
||||
'%',
|
||||
'^',
|
||||
'&',
|
||||
'*',
|
||||
'(',
|
||||
')',
|
||||
'_',
|
||||
'+',
|
||||
'Q',
|
||||
'W',
|
||||
'E',
|
||||
'R',
|
||||
'T',
|
||||
'Y',
|
||||
'U',
|
||||
'I',
|
||||
'O',
|
||||
'P',
|
||||
'{',
|
||||
'}',
|
||||
'A',
|
||||
'S',
|
||||
'D',
|
||||
'F',
|
||||
'G',
|
||||
'H',
|
||||
'J',
|
||||
'K',
|
||||
'L',
|
||||
':',
|
||||
'"',
|
||||
' ', // #
|
||||
'|', // Backslash
|
||||
'Z',
|
||||
'X',
|
||||
'C',
|
||||
'V',
|
||||
'B',
|
||||
'N',
|
||||
'M',
|
||||
'<',
|
||||
'>',
|
||||
'?',
|
||||
' ', // Space
|
||||
// Unknown key
|
||||
'\0',
|
||||
};
|
||||
|
||||
namespace wind::Keyboard
|
||||
{
|
||||
static bool g_caps_lock = false;
|
||||
static bool g_right_shift = false;
|
||||
static bool g_left_shift = false;
|
||||
static bool g_right_control = false;
|
||||
static bool g_left_control = false;
|
||||
static bool g_altgr = false;
|
||||
static bool g_alt = false;
|
||||
static bool g_super = false;
|
||||
|
||||
ui::KeyEventRequest decode_keyboard_event(moon::KeyCode code, bool released)
|
||||
{
|
||||
ui::KeyEventRequest request;
|
||||
request.code = code;
|
||||
request.pressed = !released;
|
||||
request.modifiers = 0;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case moon::K_CapsLock:
|
||||
if (!released) { g_caps_lock = !g_caps_lock; }
|
||||
break;
|
||||
case moon::K_RightShift: g_right_shift = !released; break;
|
||||
case moon::K_LeftShift: g_left_shift = !released; break;
|
||||
case moon::K_RightControl: g_right_control = !released; break;
|
||||
case moon::K_LeftControl: g_left_control = !released; break;
|
||||
case moon::K_RightAlt: g_altgr = !released; break;
|
||||
case moon::K_LeftAlt: g_alt = !released; break;
|
||||
case moon::K_Super: g_super = !released; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if ((g_caps_lock && !(g_left_shift || g_right_shift)) || (g_left_shift || g_right_shift))
|
||||
{
|
||||
request.modifiers |= ui::Mod_Shift;
|
||||
}
|
||||
|
||||
if (g_right_control || g_left_control) request.modifiers |= ui::Mod_Ctrl;
|
||||
|
||||
if (g_alt) request.modifiers |= ui::Mod_Alt;
|
||||
if (g_altgr) request.modifiers |= ui::Mod_AltGr;
|
||||
if (g_super) request.modifiers |= ui::Mod_Super;
|
||||
|
||||
request.key = table[code];
|
||||
|
||||
if (request.modifiers & ui::Mod_Ctrl)
|
||||
{
|
||||
char letter;
|
||||
if (request.modifiers & ui::Mod_Shift) letter = shift_table[code];
|
||||
else
|
||||
letter = table[code];
|
||||
if (_islower(letter)) letter = (char)_toupper(letter);
|
||||
if (_isupper(letter)) letter = 0x40;
|
||||
if (letter == '@') letter = 0x40;
|
||||
if (letter > 'Z' && letter < '`') letter = 0x40;
|
||||
if (letter == '?') letter = 0x7f;
|
||||
request.letter = letter;
|
||||
return request;
|
||||
}
|
||||
|
||||
if (request.modifiers & ui::Mod_Shift) request.letter = shift_table[code];
|
||||
else
|
||||
request.letter = table[code];
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
10
wind/Keyboard.h
Normal file
10
wind/Keyboard.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <ui/ipc/Client.h>
|
||||
|
||||
namespace wind
|
||||
{
|
||||
namespace Keyboard
|
||||
{
|
||||
ui::KeyEventRequest decode_keyboard_event(moon::KeyCode code, bool released);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
#define CLIENT_IMPLEMENTATION
|
||||
#include "Client.h"
|
||||
#include "IPC.h"
|
||||
#include "Keyboard.h"
|
||||
#include "Mouse.h"
|
||||
#include "Screen.h"
|
||||
#include "Window.h"
|
||||
@ -155,8 +156,14 @@ Result<int> luna_main(int argc, char** argv)
|
||||
{
|
||||
moon::KeyboardPacket packet;
|
||||
TRY(keyboard->read_typed(packet));
|
||||
os::println("%s key %d", packet.released ? "Released" : "Pressed", packet.key);
|
||||
if (!packet.released && packet.key == moon::K_Tab) debug(clients);
|
||||
auto request = wind::Keyboard::decode_keyboard_event((moon::KeyCode)packet.key, packet.released);
|
||||
if (g_windows.last().has_value())
|
||||
{
|
||||
auto* window = g_windows.last().value();
|
||||
request.window = window->id;
|
||||
os::IPC::send_async(window->client->conn, request);
|
||||
}
|
||||
}
|
||||
for (usize i = 0; i < clients.size(); i++)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user