Compare commits

...

5 Commits

Author SHA1 Message Date
3aaf1c5d84
apps: Rename mouse to input, read keyboard packets as well
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-02 17:20:26 +02:00
4794d0dfef
kernel: Add a keyboard device for graphical session 2023-08-02 17:20:13 +02:00
9c1e275f34
kernel: Make /dev/mouse read-write only for root 2023-08-02 17:19:37 +02:00
6593f9241b
libc: Add wrapper for poll() 2023-08-02 17:19:16 +02:00
df4227eab8
kernel: Make the poll() system call actually work 2023-08-02 17:18:38 +02:00
18 changed files with 421 additions and 47 deletions

View File

@ -44,4 +44,4 @@ luna_app(gol.cpp gol)
luna_app(buffer-test.cpp buffer-test) luna_app(buffer-test.cpp buffer-test)
luna_app(socket-test.cpp socket-test) luna_app(socket-test.cpp socket-test)
luna_app(socket-client.cpp socket-client) luna_app(socket-client.cpp socket-client)
luna_app(mouse.cpp mouse) luna_app(input.cpp input)

69
apps/input.cpp Normal file
View File

@ -0,0 +1,69 @@
#include <errno.h>
#include <luna/String.h>
#include <moon/Keyboard.h>
#include <moon/Mouse.h>
#include <os/File.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <unistd.h>
Result<void> process_mouse_packet(const moon::MousePacket& packet)
{
bool right = packet.buttons & moon::MouseButton::Right;
bool left = packet.buttons & moon::MouseButton::Left;
bool middle = packet.buttons & moon::MouseButton::Middle;
Vector<StringView> buttons;
if (right) TRY(buttons.try_append("RIGHT"_sv));
if (left) TRY(buttons.try_append("LEFT"_sv));
if (middle) TRY(buttons.try_append("MIDDLE"_sv));
String button_string;
if (!buttons.size()) button_string = TRY(String::from_cstring("NONE"));
else
button_string = TRY(String::join(buttons, " | "_sv));
os::println("Mouse packet: xdelta=%d, ydelta=%d, buttons=(%s)", packet.xdelta, packet.ydelta,
button_string.chars());
return {};
}
Result<int> luna_main(int, char**)
{
auto mouse = TRY(os::File::open("/dev/mouse", os::File::ReadOnly));
mouse->set_buffer(os::File::NotBuffered);
auto keyboard = TRY(os::File::open("/dev/kbd", os::File::ReadOnly));
keyboard->set_buffer(os::File::NotBuffered);
ioctl(STDIN_FILENO, TTYSETGFX, 1);
while (1)
{
struct pollfd fds[] = {
{ .fd = mouse->fd(), .events = POLLIN, .revents = 0 },
{ .fd = keyboard->fd(), .events = POLLIN, .revents = 0 },
};
int rc = poll(fds, 2, 1000);
if (!rc) continue;
if (rc < 0) { os::println("poll: error: %s", strerror(errno)); }
if (fds[0].revents & POLLIN)
{
moon::MousePacket packet;
TRY(mouse->read_typed(packet));
TRY(process_mouse_packet(packet));
}
if (fds[1].revents & POLLIN)
{
moon::KeyboardPacket packet;
TRY(keyboard->read_typed(packet));
os::println("Keyboard packet: %s key %u", packet.released ? "released" : "pressed", packet.key);
}
}
return 0;
}

View File

@ -1,32 +0,0 @@
#include <luna/String.h>
#include <moon/Mouse.h>
#include <os/File.h>
Result<int> luna_main(int, char**)
{
auto mouse = TRY(os::File::open("/dev/mouse", os::File::ReadOnly));
mouse->set_buffer(os::File::NotBuffered);
while (1)
{
moon::MousePacket packet;
TRY(mouse->read_typed(packet));
bool right = packet.buttons & moon::MouseButton::Right;
bool left = packet.buttons & moon::MouseButton::Left;
bool middle = packet.buttons & moon::MouseButton::Middle;
Vector<StringView> buttons;
if (right) TRY(buttons.try_append("RIGHT"_sv));
if (left) TRY(buttons.try_append("LEFT"_sv));
if (middle) TRY(buttons.try_append("MIDDLE"_sv));
String button_string;
if (!buttons.size()) button_string = TRY(String::from_cstring("NONE"));
else
button_string = TRY(String::join(buttons, " | "_sv));
os::println("Mouse packet: xdelta=%d, ydelta=%d, buttons=(%s)", packet.xdelta, packet.ydelta,
button_string.chars());
}
}

View File

@ -61,6 +61,7 @@ set(SOURCES
src/fs/devices/FramebufferDevice.cpp src/fs/devices/FramebufferDevice.cpp
src/fs/devices/UARTDevice.cpp src/fs/devices/UARTDevice.cpp
src/fs/devices/MouseDevice.cpp src/fs/devices/MouseDevice.cpp
src/fs/devices/KeyboardDevice.cpp
src/fs/InitRD.cpp src/fs/InitRD.cpp
src/binfmt/ELF.cpp src/binfmt/ELF.cpp
src/binfmt/BinaryFormat.cpp src/binfmt/BinaryFormat.cpp

131
kernel/src/api/Keyboard.h Normal file
View File

@ -0,0 +1,131 @@
#pragma once
#include <luna/Types.h>
namespace moon
{
enum KeyCode : u8
{
// Function keys
K_F1,
K_F2,
K_F3,
K_F4,
K_F5,
K_F6,
K_F7,
K_F8,
K_F9,
K_F10,
K_F11,
K_F12,
// System keys
K_Esc,
K_PrtScr,
K_Pause,
K_Super,
K_Menu,
// Modifier keys
K_LeftShift,
K_RightShift,
K_LeftAlt,
K_RightAlt, // or AltGr on some keyboards
K_LeftControl,
K_RightControl,
// Navigation keys
K_Tab,
K_Home,
K_End,
K_PageUp,
K_PageDown,
K_RightArrow,
K_LeftArrow,
K_UpArrow,
K_DownArrow,
// Editing keys
K_Backspace,
K_Enter,
K_Insert,
K_Delete,
K_KeypadEnter,
// Lock keys
K_ScrollLock,
K_CapsLock,
K_NumLock,
// Keypad keys
K_Keypad0,
K_Keypad1,
K_Keypad2,
K_Keypad3,
K_Keypad4,
K_Keypad5,
K_Keypad6,
K_Keypad7,
K_Keypad8,
K_Keypad9,
K_KeypadDot,
K_KeypadPlus,
K_KeypadMinus,
K_KeypadMul,
K_KeypadDiv,
// Character keys (depending on keyboard layout), examples in US QWERTY
K_CH00, // `
K_CH01, // 1
K_CH02, // 2
K_CH03, // 3
K_CH04, // 4
K_CH05, // 5
K_CH06, // 6
K_CH07, // 7
K_CH08, // 8
K_CH09, // 9
K_CH10, // 0
K_CH11, // -
K_CH12, // =
K_CH13, // Q
K_CH14, // W
K_CH15, // E
K_CH16, // R
K_CH17, // T
K_CH18, // Y
K_CH19, // U
K_CH20, // I
K_CH21, // O
K_CH22, // P
K_CH23, // [
K_CH24, // ]
K_CH25, // A
K_CH26, // S
K_CH27, // D
K_CH28, // F
K_CH29, // G
K_CH30, // H
K_CH31, // J
K_CH32, // K
K_CH33, // L
K_CH34, // ;
K_CH35, // '
K_CH36, // #
K_CH37, // Backslash
K_CH38, // Z
K_CH39, // X
K_CH40, // C
K_CH41, // V
K_CH42, // B
K_CH43, // N
K_CH44, // M
K_CH45, // ,
K_CH46, // .
K_CH47, // /
K_CH48, // Space
// Unknown key
K_Unknown,
};
struct [[gnu::packed]] KeyboardPacket
{
u8 key;
bool released;
};
static_assert(sizeof(KeyboardPacket) == 2);
}

View File

@ -1,9 +1,10 @@
#pragma once #pragma once
#include "api/Keyboard.h"
#include <luna/Option.h> #include <luna/Option.h>
namespace Keyboard namespace Keyboard
{ {
struct KeyboardState struct TTYKeyboardState
{ {
bool ignore_next { false }; bool ignore_next { false };
bool left_shift { false }; bool left_shift { false };
@ -12,5 +13,12 @@ namespace Keyboard
bool capslock { false }; bool capslock { false };
}; };
Option<char> decode_scancode_tty(u8 scancode, KeyboardState& state); struct KeyboardState
{
bool ignore_next { false };
};
Option<char> decode_scancode_tty(u8 scancode, TTYKeyboardState& state);
Option<moon::KeyboardPacket> decode_scancode(u8 scancode, KeyboardState& state);
} }

View File

@ -113,7 +113,71 @@ constexpr char shifted_key_table[] = {
'.', // keypad . '.', // keypad .
}; };
static bool is_shifted(const Keyboard::KeyboardState& state) using namespace moon;
constexpr KeyCode keycode_table[] = {
K_Unknown, K_Esc,
K_CH01, // 1
K_CH02, // 2
K_CH03, // 3
K_CH04, // 4
K_CH05, // 5
K_CH06, // 6
K_CH07, // 7
K_CH08, // 8
K_CH09, // 9
K_CH10, // 0
K_CH11, // -
K_CH12, // =
K_Backspace, K_Tab,
K_CH13, // Q
K_CH14, // W
K_CH15, // E
K_CH16, // R
K_CH17, // T
K_CH18, // Y
K_CH19, // U
K_CH20, // I
K_CH21, // O
K_CH22, // P
K_CH23, // [
K_CH24, // ]
K_Enter, K_LeftControl,
K_CH25, // A
K_CH26, // S
K_CH27, // D
K_CH28, // F
K_CH29, // G
K_CH30, // H
K_CH31, // J
K_CH32, // K
K_CH33, // L
K_CH34, // ;
K_CH35, // '
K_CH00, // `
K_LeftShift,
K_CH36, // #
K_CH38, // Z
K_CH39, // X
K_CH40, // C
K_CH41, // V
K_CH42, // B
K_CH43, // N
K_CH44, // M
K_CH45, // ,
K_CH46, // .
K_CH47, // /
K_RightShift, K_KeypadMul, K_LeftAlt,
K_CH48, // Space
K_CapsLock, K_F1, K_F2, K_F3, K_F4, K_F5, K_F6,
K_F7, K_F8, K_F9, K_F10, K_NumLock, K_ScrollLock, K_Keypad7,
K_Keypad8, K_Keypad9, K_KeypadMinus, K_Keypad4, K_Keypad5, K_Keypad6, K_KeypadPlus,
K_Keypad1, K_Keypad2, K_Keypad3, K_Keypad0, K_KeypadDot, K_Unknown, K_Unknown,
K_CH37, // Backslash
K_F11, K_F12,
};
static bool is_shifted(const Keyboard::TTYKeyboardState& state)
{ {
if (state.capslock) return !(state.left_shift || state.right_shift); if (state.capslock) return !(state.left_shift || state.right_shift);
return state.left_shift || state.right_shift; return state.left_shift || state.right_shift;
@ -121,7 +185,7 @@ static bool is_shifted(const Keyboard::KeyboardState& state)
namespace Keyboard namespace Keyboard
{ {
Option<char> decode_scancode_tty(u8 scancode, KeyboardState& state) Option<char> decode_scancode_tty(u8 scancode, TTYKeyboardState& state)
{ {
if (state.ignore_next) if (state.ignore_next)
{ {
@ -184,4 +248,24 @@ namespace Keyboard
if (is_shifted(state)) return shifted_key_table[scancode]; if (is_shifted(state)) return shifted_key_table[scancode];
return key_table[scancode]; return key_table[scancode];
} }
Option<KeyboardPacket> decode_scancode(u8 scancode, KeyboardState& state)
{
if (state.ignore_next)
{
state.ignore_next = false;
return {};
}
// FIXME: Support extended scancodes.
if (scancode == EXTENDED_KEY_CODE)
{
state.ignore_next = true;
return {};
}
bool released = is_key_released(scancode);
return KeyboardPacket { keycode_table[scancode], released };
}
} }

View File

@ -1,6 +1,7 @@
#include "fs/devices/ConsoleDevice.h" #include "fs/devices/ConsoleDevice.h"
#include "Log.h" #include "Log.h"
#include "fs/devices/DeviceRegistry.h" #include "fs/devices/DeviceRegistry.h"
#include "fs/devices/KeyboardDevice.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "thread/Scheduler.h" #include "thread/Scheduler.h"
#include "video/TextConsole.h" #include "video/TextConsole.h"
@ -61,7 +62,7 @@ Result<usize> ConsoleDevice::write(const u8* buf, usize, usize length)
{ {
if (m_settings.c_lflag & TOSTOP) TRY(handle_background_process_group(true, SIGTTOU)); if (m_settings.c_lflag & TOSTOP) TRY(handle_background_process_group(true, SIGTTOU));
if (s_is_in_graphical_mode) return length; // if (s_is_in_graphical_mode) return length;
TextConsole::write((const char*)buf, length); TextConsole::write((const char*)buf, length);
return length; return length;
@ -74,7 +75,14 @@ bool ConsoleDevice::will_block_if_read() const
void ConsoleDevice::did_press_or_release_key(u8 scancode) void ConsoleDevice::did_press_or_release_key(u8 scancode)
{ {
for (const auto& device : m_console_devices) { device->process_key_event(scancode); } if (!s_is_in_graphical_mode)
for (const auto& device : m_console_devices) { device->process_key_event(scancode); }
else
{
static Keyboard::KeyboardState state = {};
auto packet = Keyboard::decode_scancode(scancode, state);
if (packet.has_value()) KeyboardDevice::add_keyboard_event(packet.release_value());
}
} }
void ConsoleDevice::process_key_event(u8 scancode) void ConsoleDevice::process_key_event(u8 scancode)

View File

@ -37,7 +37,7 @@ class ConsoleDevice : public Device
mutable Buffer m_input_buffer; mutable Buffer m_input_buffer;
Option<pid_t> m_foreground_process_group {}; Option<pid_t> m_foreground_process_group {};
Vector<u8> m_line_buffer; Vector<u8> m_line_buffer;
mutable Keyboard::KeyboardState m_kb_state; mutable Keyboard::TTYKeyboardState m_kb_state;
static Vector<SharedPtr<ConsoleDevice>> m_console_devices; static Vector<SharedPtr<ConsoleDevice>> m_console_devices;
static bool s_is_in_graphical_mode; static bool s_is_in_graphical_mode;

View File

@ -4,6 +4,7 @@
#include "fs/devices/ConsoleDevice.h" #include "fs/devices/ConsoleDevice.h"
#include "fs/devices/FramebufferDevice.h" #include "fs/devices/FramebufferDevice.h"
#include "fs/devices/FullDevice.h" #include "fs/devices/FullDevice.h"
#include "fs/devices/KeyboardDevice.h"
#include "fs/devices/MouseDevice.h" #include "fs/devices/MouseDevice.h"
#include "fs/devices/NullDevice.h" #include "fs/devices/NullDevice.h"
#include "fs/devices/UARTDevice.h" #include "fs/devices/UARTDevice.h"
@ -72,6 +73,7 @@ namespace DeviceRegistry
FramebufferDevice::create(); FramebufferDevice::create();
UARTDevice::create(); UARTDevice::create();
MouseDevice::create(); MouseDevice::create();
KeyboardDevice::create();
return {}; return {};
} }

View File

@ -0,0 +1,34 @@
#include "fs/devices/KeyboardDevice.h"
SharedPtr<KeyboardDevice> KeyboardDevice::s_keyboard_device = {};
Result<void> KeyboardDevice::create()
{
auto device = TRY(make_shared<KeyboardDevice>());
s_keyboard_device = device;
return DeviceRegistry::register_special_device(DeviceRegistry::Input, 1, device, 0600);
}
Result<usize> KeyboardDevice::read(u8* buf, usize, usize length) const
{
length = m_packet_buffer.dequeue_data(buf, length);
return length;
}
Result<usize> KeyboardDevice::write(const u8* buf, usize, usize length)
{
TRY(m_packet_buffer.append_data(buf, length));
return length;
}
void KeyboardDevice::add_keyboard_event(const moon::KeyboardPacket& packet)
{
if (s_keyboard_device) s_keyboard_device->write((const u8*)&packet, 0, sizeof(packet));
}
bool KeyboardDevice::will_block_if_read() const
{
return !m_packet_buffer.size();
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "api/Keyboard.h"
#include "fs/devices/DeviceRegistry.h"
#include <luna/Buffer.h>
class KeyboardDevice : public Device
{
public:
// Initializer for DeviceRegistry.
static Result<void> create();
Result<usize> read(u8*, usize, usize) const override;
Result<usize> write(const u8*, usize, usize) override;
static void add_keyboard_event(const moon::KeyboardPacket& packet);
bool will_block_if_read() const override;
StringView device_path() const override
{
return "kbd";
}
virtual ~KeyboardDevice() = default;
private:
mutable Buffer m_packet_buffer;
static SharedPtr<KeyboardDevice> s_keyboard_device;
};

View File

@ -6,7 +6,7 @@ Result<void> MouseDevice::create()
{ {
auto device = TRY(make_shared<MouseDevice>()); auto device = TRY(make_shared<MouseDevice>());
s_mouse_device = device; s_mouse_device = device;
return DeviceRegistry::register_special_device(DeviceRegistry::Input, 0, device); return DeviceRegistry::register_special_device(DeviceRegistry::Input, 0, device, 0600);
} }
Result<usize> MouseDevice::read(u8* buf, usize, usize length) const Result<usize> MouseDevice::read(u8* buf, usize, usize length) const

View File

@ -1,3 +1,4 @@
#include "Log.h"
#include "fs/VFS.h" #include "fs/VFS.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
@ -24,6 +25,7 @@ Result<u64> sys_poll(Registers* regs, SyscallArgs args)
auto maybe_inode = current->resolve_fd(fd); auto maybe_inode = current->resolve_fd(fd);
if (maybe_inode.has_error()) if (maybe_inode.has_error())
{ {
kwarnln("poll: fd %lu (%d) is not valid, storing POLLNVAL", i, fd);
kfds[i].revents |= POLLNVAL; kfds[i].revents |= POLLNVAL;
TRY(inodes.try_append({})); TRY(inodes.try_append({}));
} }
@ -32,7 +34,7 @@ Result<u64> sys_poll(Registers* regs, SyscallArgs args)
} }
bool infinite = timeout < 0; bool infinite = timeout < 0;
int fds_with_events; nfds_t fds_with_events;
do { do {
fds_with_events = 0; fds_with_events = 0;
@ -51,7 +53,7 @@ Result<u64> sys_poll(Registers* regs, SyscallArgs args)
if (!fds_with_events && (timeout > 0 || infinite)) if (!fds_with_events && (timeout > 0 || infinite))
{ {
kernel_sleep(10); kernel_sleep(10);
timeout -= (int)current->sleep_ticks_left; timeout -= (10 - (int)current->sleep_ticks_left);
if (current->interrupted) if (current->interrupted)
{ {
guard.deactivate(); guard.deactivate();
@ -62,7 +64,9 @@ Result<u64> sys_poll(Registers* regs, SyscallArgs args)
} }
continue; continue;
} }
} while (false);
break;
} while (1);
MemoryManager::copy_to_user(fds, kfds, nfds * sizeof(pollfd)); MemoryManager::copy_to_user(fds, kfds, nfds * sizeof(pollfd));

View File

@ -32,6 +32,7 @@ set(SOURCES
src/sys/pstat.cpp src/sys/pstat.cpp
src/sys/resource.cpp src/sys/resource.cpp
src/sys/socket.cpp src/sys/socket.cpp
src/sys/poll.cpp
) )
if(${LUNA_ARCH} STREQUAL "x86_64") if(${LUNA_ARCH} STREQUAL "x86_64")

View File

@ -5,9 +5,9 @@
#include <bits/fixed-size-types.h> #include <bits/fixed-size-types.h>
#define POLLIN 0 #define POLLIN (1 << 0)
#define POLLERR 1 #define POLLERR (1 << 1)
#define POLLNVAL 2 #define POLLNVAL (1 << 2)
typedef __u64_t nfds_t; typedef __u64_t nfds_t;

20
libc/include/sys/poll.h Normal file
View File

@ -0,0 +1,20 @@
/* sys/poll.h: Wait for events on multiple file descriptors. */
#ifndef _SYS_POLL_H
#define _SYS_POLL_H
#include <bits/poll.h>
#ifdef __cplusplus
extern "C"
{
#endif
/* Wait for events on multiple file descriptors. */
int poll(struct pollfd* fds, nfds_t nfds, int timeout);
#ifdef __cplusplus
}
#endif
#endif

13
libc/src/sys/poll.cpp Normal file
View File

@ -0,0 +1,13 @@
#include <bits/errno-return.h>
#include <sys/poll.h>
#include <sys/syscall.h>
#include <unistd.h>
extern "C"
{
int poll(struct pollfd* fds, nfds_t nfds, int timeout)
{
long rc = syscall(SYS_poll, fds, nfds, timeout);
__errno_return(rc, int);
}
}