Files
xbanan/xbanan/banan-os/banan-os.cpp
Oskari Alaranta d0606a1939 Remove banan-os's LibInput dependency
Platforms now define their own keymaps
2026-06-03 19:50:45 +03:00

346 lines
12 KiB
C++

#include "../Events.h"
#include "../Keymap.h"
#include "../Platform.h"
#include <BAN/Vector.h>
#include <LibGUI/Window.h>
struct BananWindow final : public PlatformWindow
{
~BananWindow()
{
if (window)
unregister_event_fd(window->server_fd());
}
BAN::UniqPtr<LibGUI::Window> window;
};
struct BananCursor final : public PlatformCursor
{
BAN::Vector<uint32_t> pixels;
uint32_t width;
uint32_t height;
int32_t origin_x;
int32_t origin_y;
};
static BAN::ErrorOr<void> bananos_initialize_keymap();
static bool bananos_initialize(uint32_t* display_w, uint32_t* display_h)
{
auto attributes = LibGUI::Window::default_attributes;
attributes.shown = false;
auto dummy_or_error = LibGUI::Window::create(0, 0, ""_sv, attributes);
if (dummy_or_error.is_error())
{
dwarnln("Could not get display size: {}", dummy_or_error.error());
return false;
}
*display_w = dummy_or_error.value()->width();
*display_h = dummy_or_error.value()->height();
if (auto ret = bananos_initialize_keymap(); ret.is_error())
{
dwarnln("Could not initialize keymap: {}", ret.error());
return false;
}
return true;
}
static void bananos_poll_events(void* window)
{
auto& banan_window = *static_cast<BananWindow*>(window);
banan_window.window->poll_events();
}
static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> bananos_create_window(PlatformWindow* parent, WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height)
{
(void)parent;
(void)type;
(void)x;
(void)y;
auto window = TRY(BAN::UniqPtr<BananWindow>::create());
auto attributes = LibGUI::Window::default_attributes;
attributes.shown = true;
attributes.title_bar = false;
attributes.resizable = true;
auto gui_window = TRY(LibGUI::Window::create(width, height, ""_sv, attributes));
auto* winp = gui_window.ptr();
gui_window->set_close_window_event_callback([wid] {
on_window_close_event(wid);
});
gui_window->set_resize_window_event_callback([wid, winp]() {
on_window_resize_event(wid, winp->width(), winp->height());
});
gui_window->set_window_focus_event_callback([wid](auto event) {
on_window_focus_event(wid, event.focused);
});
gui_window->set_window_fullscreen_event_callback([wid](auto event) {
on_window_fullscreen_event(wid, event.fullscreen);
});
gui_window->set_mouse_move_event_callback([wid](auto event) {
on_mouse_move_event(wid, event.x, event.y);
});
gui_window->set_mouse_button_event_callback([wid](auto event) {
uint8_t xbutton = 0;
switch (event.button)
{
case LibInput::MouseButton::Left: xbutton = 1; break;
case LibInput::MouseButton::Middle: xbutton = 2; break;
case LibInput::MouseButton::Right: xbutton = 3; break;
case LibInput::MouseButton::Extra1: xbutton = 8; break;
case LibInput::MouseButton::Extra2: xbutton = 9; break;
}
if (xbutton)
on_mouse_button_event(wid, xbutton, event.pressed);
});
gui_window->set_mouse_scroll_event_callback([wid](auto event) {
on_mouse_button_event(wid, event.scroll > 0 ? 4 : 5, true);
on_mouse_button_event(wid, event.scroll > 0 ? 4 : 5, false);
});
gui_window->set_key_event_callback([wid](auto event) {
const uint8_t xmod =
(event.shift() ? (1 << 0) : 0) |
(event.caps_lock() ? (1 << 1) : 0) |
(event.ctrl() ? (1 << 2) : 0) |
(event.alt() ? (1 << 3) : 0) |
(event.num_lock() ? (1 << 4) : 0) |
// level5 shift
// super
(event.ralt() ? (1 << 7) : 0); // FIXME: altgr
on_key_event(wid, event.scancode, xmod, event.pressed());
});
window->window = BAN::move(gui_window);
register_event_fd(window->window->server_fd(), window.ptr());
return BAN::UniqPtr<PlatformWindow>(BAN::move(window));
}
static void bananos_request_resize(PlatformWindow* window, uint32_t width, uint32_t height)
{
auto& banan_window = *static_cast<BananWindow*>(window);
banan_window.window->request_resize(width, height);
}
static void bananos_invalidate(PlatformWindow* window, const uint32_t* pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height)
{
auto& banan_window = *static_cast<BananWindow*>(window);
const uint32_t win_width = banan_window.window->width();
auto* out_pixels = banan_window.window->texture().pixels().data();
for (uint32_t y_off = 0; y_off < height; y_off++)
for (uint32_t x_off = 0; x_off < width; x_off++)
out_pixels[(y + y_off) * win_width + (x + x_off)] = pixels[(y + y_off) * win_width + (x + x_off)];
banan_window.window->invalidate(x, y, width, height);
}
static void bananos_request_fullscreen(PlatformWindow* window, bool fullscreen)
{
auto& banan_window = *static_cast<BananWindow*>(window);
banan_window.window->set_fullscreen(fullscreen);
}
static BAN::ErrorOr<BAN::UniqPtr<PlatformCursor>> bananos_create_bitmap_cursor(const uint32_t* pixels, uint32_t width, uint32_t height, int32_t origin_x, int32_t origin_y)
{
auto cursor = TRY(BAN::UniqPtr<BananCursor>::create());
cursor->width = width;
cursor->height = height;
cursor->origin_x = origin_x;
cursor->origin_y = origin_y;
TRY(cursor->pixels.resize(width * height));
memcpy(cursor->pixels.data(), pixels, cursor->pixels.size() * 4);
return BAN::UniqPtr<PlatformCursor>(BAN::move(cursor));
}
static void bananos_set_cursor(PlatformWindow* window, PlatformCursor* cursor)
{
if (window == nullptr)
return;
auto& banan_window = *static_cast<BananWindow*>(window);
if (cursor == nullptr)
banan_window.window->set_cursor(0, 0, {}, 0, 0);
else
{
auto& banan_cursor = *static_cast<BananCursor*>(cursor);
banan_window.window->set_cursor(banan_cursor.width, banan_cursor.height, banan_cursor.pixels.span(), banan_cursor.origin_x, banan_cursor.origin_y);
}
}
PlatformOps g_platform_ops = {
.initialize = bananos_initialize,
.poll_events = bananos_poll_events,
.create_window = bananos_create_window,
.invalidate = bananos_invalidate,
.request_resize = bananos_request_resize,
.request_reposition = nullptr,
.request_fullscreen = bananos_request_fullscreen,
.warp_pointer = nullptr,
.query_pointer = nullptr,
.set_pointer_grab = nullptr,
.create_system_cursor = nullptr,
.create_bitmap_cursor = bananos_create_bitmap_cursor,
.set_cursor = bananos_set_cursor,
};
#include <LibInput/KeyboardLayout.h>
#include <LibInput/KeyEvent.h>
static uint32_t bananos_key_to_x_keysym(LibInput::Key, bool upper);
static BAN::ErrorOr<void> bananos_initialize_keymap()
{
// FIXME: get this from somewhere (gui command? enviroment? tmp file?)
const auto keymap_path = "./us.keymap"_sv;
TRY(LibInput::KeyboardLayout::initialize());
auto& keyboard_layout = LibInput::KeyboardLayout::get();
TRY(keyboard_layout.load_from_file(keymap_path));
const BAN::Span<const LibInput::Key> banan_keymaps[] {
keyboard_layout.keymap_normal(),
keyboard_layout.keymap_shift(),
keyboard_layout.keymap_altgr(),
keyboard_layout.keymap_altgr(), // add shift+altgr map?
};
for (size_t scancode = 0; scancode < g_keymap_size; scancode++)
for (size_t layer = 0; layer < g_keymap_layers; layer++)
if (const auto banan_key = banan_keymaps[layer][scancode]; banan_key != LibInput::Key::None)
g_keymap[scancode][layer] = bananos_key_to_x_keysym(banan_key, layer % 2);
using LibInput::keycode_normal;
using LibInput::keycode_numpad;
g_modifier_map[0][0] = keycode_normal(3, 0) + g_keymap_min_keycode; // lshift
g_modifier_map[0][1] = keycode_normal(3, 12) + g_keymap_min_keycode; // rshift
g_modifier_map[1][0] = keycode_normal(2, 0) + g_keymap_min_keycode; // caps lock
g_modifier_map[2][0] = keycode_normal(4, 0) + g_keymap_min_keycode; // lctrl
g_modifier_map[2][1] = keycode_normal(4, 6) + g_keymap_min_keycode; // rctrl
g_modifier_map[3][0] = keycode_normal(4, 2) + g_keymap_min_keycode; // lalt
g_modifier_map[3][1] = keycode_normal(4, 5) + g_keymap_min_keycode; // ralt
g_modifier_map[4][0] = keycode_numpad(0, 0) + g_keymap_min_keycode; // num lock
//g_modifier_map[5][0] = level5 shift;
g_modifier_map[6][0] = keycode_normal(4, 1) + g_keymap_min_keycode; // lsuper
g_modifier_map[6][1] = keycode_normal(4, 4) + g_keymap_min_keycode; // rsuper
g_modifier_map[7][0] = keycode_normal(4, 5) + g_keymap_min_keycode; // FIXME: altgr
return {};
}
#include <BAN/UTF8.h>
#include <X11/keysym.h>
#include <X11/XF86keysym.h>
#include <wctype.h>
static uint32_t bananos_key_to_x_keysym(LibInput::Key key, bool upper)
{
using namespace LibInput;
if (const char* utf8 = key_to_utf8(key, upper ? KeyEvent::LShift : 0))
{
const uint32_t codepoint = BAN::UTF8::to_codepoint(utf8);
if (codepoint != BAN::UTF8::invalid && iswprint(codepoint))
{
if ((codepoint >= 0x20 && codepoint <= 0x7E) || (codepoint >= 0xA0 && codepoint <= 0xFF))
return codepoint;
return 0x01000000 | codepoint;
}
}
switch (key)
{
case Key::F1: return XK_F1;
case Key::F2: return XK_F2;
case Key::F3: return XK_F3;
case Key::F4: return XK_F4;
case Key::F5: return XK_F5;
case Key::F6: return XK_F6;
case Key::F7: return XK_F7;
case Key::F8: return XK_F8;
case Key::F9: return XK_F9;
case Key::F10: return XK_F10;
case Key::F11: return XK_F11;
case Key::F12: return XK_F12;
case Key::Insert: return XK_Insert;
case Key::PrintScreen: return XK_Print;
case Key::Delete: return XK_Delete;
case Key::Home: return XK_Home;
case Key::End: return XK_End;
case Key::PageUp: return XK_Page_Up;
case Key::PageDown: return XK_Page_Down;
case Key::Enter: return XK_Return;
case Key::Backspace: return XK_BackSpace;
case Key::Escape: return XK_Escape;
case Key::Tab: return XK_Tab;
case Key::CapsLock: return XK_Caps_Lock;
case Key::LeftShift: return XK_Shift_L;
case Key::LeftCtrl: return XK_Control_L;
case Key::Super: return XK_Super_L;
case Key::LeftAlt: return XK_Alt_L;
case Key::RightAlt: return XK_Alt_R;
case Key::RightCtrl: return XK_Control_R;
case Key::RightShift: return XK_Shift_R;
case Key::ArrowUp: return XK_Up;
case Key::ArrowDown: return XK_Down;
case Key::ArrowLeft: return XK_Left;
case Key::ArrowRight: return XK_Right;
case Key::NumLock: return XK_Num_Lock;
case Key::ScrollLock: return XK_Scroll_Lock;
case Key::Numpad0: return XK_KP_0;
case Key::Numpad1: return XK_KP_1;
case Key::Numpad2: return XK_KP_2;
case Key::Numpad3: return XK_KP_3;
case Key::Numpad4: return XK_KP_4;
case Key::Numpad5: return XK_KP_5;
case Key::Numpad6: return XK_KP_6;
case Key::Numpad7: return XK_KP_7;
case Key::Numpad8: return XK_KP_8;
case Key::Numpad9: return XK_KP_9;
case Key::NumpadPlus: return XK_KP_Add;
case Key::NumpadMinus: return XK_KP_Subtract;
case Key::NumpadMultiply: return XK_KP_Multiply;
case Key::NumpadDivide: return XK_KP_Divide;
case Key::NumpadEnter: return XK_KP_Enter;
case Key::NumpadDecimal: return XK_KP_Decimal;
case Key::VolumeMute: return XF86XK_AudioMute;
case Key::VolumeUp: return XF86XK_AudioRaiseVolume;
case Key::VolumeDown: return XF86XK_AudioLowerVolume;
case Key::Calculator: return XF86XK_Calculator;
case Key::MediaPlayPause: return XF86XK_AudioPlay;
case Key::MediaStop: return XF86XK_AudioStop;
case Key::MediaPrevious: return XF86XK_AudioPrev;
case Key::MediaNext: return XF86XK_AudioNext;
default: break;
}
static_assert(static_cast<size_t>(Key::Count) == 145, "update keymap");
return 0;
}