wip: add clipboard support
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Clipboard.hpp
|
||||
* SYS_CLIPBOARD_* plain-text clipboard syscalls
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Sched/Scheduler.hpp>
|
||||
#include <Memory/Heap.hpp>
|
||||
#include <CppLib/Spinlock.hpp>
|
||||
|
||||
#include "Syscall.hpp"
|
||||
|
||||
namespace Montauk {
|
||||
|
||||
static constexpr int ClipboardMaxSlots = 32;
|
||||
|
||||
struct ClipboardSlot {
|
||||
bool inUse;
|
||||
char user[32];
|
||||
char* text;
|
||||
uint32_t len;
|
||||
uint64_t serial;
|
||||
};
|
||||
|
||||
static ClipboardSlot g_clipboardSlots[ClipboardMaxSlots];
|
||||
static kcp::Mutex g_clipboardLock;
|
||||
|
||||
static int Sys_ClipboardClear();
|
||||
|
||||
static const char* ClipboardCurrentUser() {
|
||||
auto* proc = Sched::GetCurrentProcessPtr();
|
||||
if (proc == nullptr) return nullptr;
|
||||
return proc->user[0] ? proc->user : "default";
|
||||
}
|
||||
|
||||
static void ClipboardCopyUser(char dst[32], const char* src) {
|
||||
if (src == nullptr || src[0] == '\0') src = "default";
|
||||
int i = 0;
|
||||
for (; i < 31 && src[i]; i++)
|
||||
dst[i] = src[i];
|
||||
dst[i] = '\0';
|
||||
}
|
||||
|
||||
static bool ClipboardUserEquals(const char* a, const char* b) {
|
||||
int i = 0;
|
||||
while (a[i] && b[i]) {
|
||||
if (a[i] != b[i]) return false;
|
||||
i++;
|
||||
}
|
||||
return a[i] == b[i];
|
||||
}
|
||||
|
||||
static uint64_t ClipboardNextSerial(uint64_t serial) {
|
||||
serial++;
|
||||
return serial == 0 ? 1 : serial;
|
||||
}
|
||||
|
||||
static ClipboardSlot* ClipboardFindSlotLocked(const char* user) {
|
||||
for (int i = 0; i < ClipboardMaxSlots; i++) {
|
||||
if (g_clipboardSlots[i].inUse && ClipboardUserEquals(g_clipboardSlots[i].user, user))
|
||||
return &g_clipboardSlots[i];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static ClipboardSlot* ClipboardEnsureSlotLocked(const char* user) {
|
||||
ClipboardSlot* freeSlot = nullptr;
|
||||
for (int i = 0; i < ClipboardMaxSlots; i++) {
|
||||
ClipboardSlot* slot = &g_clipboardSlots[i];
|
||||
if (slot->inUse) {
|
||||
if (ClipboardUserEquals(slot->user, user))
|
||||
return slot;
|
||||
} else if (freeSlot == nullptr) {
|
||||
freeSlot = slot;
|
||||
}
|
||||
}
|
||||
|
||||
if (freeSlot == nullptr) return nullptr;
|
||||
|
||||
freeSlot->inUse = true;
|
||||
ClipboardCopyUser(freeSlot->user, user);
|
||||
freeSlot->text = nullptr;
|
||||
freeSlot->len = 0;
|
||||
freeSlot->serial = 0;
|
||||
return freeSlot;
|
||||
}
|
||||
|
||||
static int Sys_ClipboardSetText(const char* data, uint32_t len) {
|
||||
if (len == 0)
|
||||
return Sys_ClipboardClear();
|
||||
if (data == nullptr || len > CLIPBOARD_MAX_TEXT_BYTES || Memory::g_heap == nullptr)
|
||||
return -1;
|
||||
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
if (data[i] == '\0')
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* currentUser = ClipboardCurrentUser();
|
||||
if (currentUser == nullptr) return -1;
|
||||
|
||||
char user[32];
|
||||
ClipboardCopyUser(user, currentUser);
|
||||
|
||||
char* newText = (char*)Memory::g_heap->Request(len + 1);
|
||||
if (newText == nullptr) return -1;
|
||||
for (uint32_t i = 0; i < len; i++)
|
||||
newText[i] = data[i];
|
||||
newText[len] = '\0';
|
||||
|
||||
char* oldText = nullptr;
|
||||
|
||||
g_clipboardLock.Acquire();
|
||||
ClipboardSlot* slot = ClipboardEnsureSlotLocked(user);
|
||||
if (slot == nullptr) {
|
||||
g_clipboardLock.Release();
|
||||
Memory::g_heap->Free(newText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
oldText = slot->text;
|
||||
slot->text = newText;
|
||||
slot->len = len;
|
||||
slot->serial = ClipboardNextSerial(slot->serial);
|
||||
g_clipboardLock.Release();
|
||||
|
||||
if (oldText != nullptr)
|
||||
Memory::g_heap->Free(oldText);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Sys_ClipboardGetInfo(ClipboardInfo* out) {
|
||||
if (out == nullptr) return -1;
|
||||
|
||||
out->textBytes = 0;
|
||||
out->_pad = 0;
|
||||
out->serial = 0;
|
||||
|
||||
const char* currentUser = ClipboardCurrentUser();
|
||||
if (currentUser == nullptr) return -1;
|
||||
|
||||
char user[32];
|
||||
ClipboardCopyUser(user, currentUser);
|
||||
|
||||
g_clipboardLock.Acquire();
|
||||
ClipboardSlot* slot = ClipboardFindSlotLocked(user);
|
||||
if (slot != nullptr) {
|
||||
out->textBytes = slot->len;
|
||||
out->serial = slot->serial;
|
||||
}
|
||||
g_clipboardLock.Release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Sys_ClipboardGetText(char* buffer, uint32_t bufferLen, uint32_t* outLen, uint64_t* outSerial) {
|
||||
if (outLen == nullptr) return -1;
|
||||
|
||||
*outLen = 0;
|
||||
if (outSerial != nullptr) *outSerial = 0;
|
||||
|
||||
const char* currentUser = ClipboardCurrentUser();
|
||||
if (currentUser == nullptr) return -1;
|
||||
|
||||
char user[32];
|
||||
ClipboardCopyUser(user, currentUser);
|
||||
|
||||
g_clipboardLock.Acquire();
|
||||
ClipboardSlot* slot = ClipboardFindSlotLocked(user);
|
||||
if (slot == nullptr || slot->len == 0) {
|
||||
if (slot != nullptr && outSerial != nullptr)
|
||||
*outSerial = slot->serial;
|
||||
g_clipboardLock.Release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
*outLen = slot->len;
|
||||
if (outSerial != nullptr) *outSerial = slot->serial;
|
||||
if (buffer == nullptr || bufferLen < slot->len) {
|
||||
g_clipboardLock.Release();
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < slot->len; i++)
|
||||
buffer[i] = slot->text[i];
|
||||
g_clipboardLock.Release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Sys_ClipboardClear() {
|
||||
const char* currentUser = ClipboardCurrentUser();
|
||||
if (currentUser == nullptr) return -1;
|
||||
|
||||
char user[32];
|
||||
ClipboardCopyUser(user, currentUser);
|
||||
|
||||
char* oldText = nullptr;
|
||||
|
||||
g_clipboardLock.Acquire();
|
||||
ClipboardSlot* slot = ClipboardEnsureSlotLocked(user);
|
||||
if (slot == nullptr) {
|
||||
g_clipboardLock.Release();
|
||||
return -1;
|
||||
}
|
||||
|
||||
oldText = slot->text;
|
||||
slot->text = nullptr;
|
||||
slot->len = 0;
|
||||
slot->serial = ClipboardNextSerial(slot->serial);
|
||||
g_clipboardLock.Release();
|
||||
|
||||
if (oldText != nullptr)
|
||||
Memory::g_heap->Free(oldText);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "IpcSyscall.hpp" // SYS_DUPHANDLE, SYS_WAIT_HANDLE, SYS_STREAM_CREATE, SYS_STREAM_READ, SYS_STREAM_WRITE, SYS_MAILBOX_CREATE, SYS_MAILBOX_SEND, SYS_MAILBOX_RECV, SYS_WAITSET_CREATE, SYS_WAITSET_ADD, SYS_WAITSET_REMOVE, SYS_WAITSET_WAIT, SYS_PROC_OPEN, SYS_SURFACE_CREATE, SYS_SURFACE_MAP, SYS_SURFACE_RESIZE
|
||||
#include "LibSyscall.hpp" // SYS_LOAD_LIB, SYS_UNLOAD_LIB, SYS_DLSYM
|
||||
#include "CrashReportSyscall.hpp" // SYS_CRASH_REPORT
|
||||
#include "Clipboard.hpp" // SYS_CLIPBOARD_*
|
||||
|
||||
// Assembly entry point
|
||||
extern "C" void SyscallEntry();
|
||||
@@ -422,6 +423,22 @@ namespace Montauk {
|
||||
return (int64_t)Sys_GetLibBase(frame->arg1);
|
||||
case SYS_CRASH_REPORT:
|
||||
return Sys_CrashReport((CrashReportInfo*)frame->arg1);
|
||||
case SYS_CLIPBOARD_SET_TEXT:
|
||||
if (frame->arg2 > 0 && !ValidUserPtr(frame->arg1)) return -1;
|
||||
return Sys_ClipboardSetText((const char*)frame->arg1, (uint32_t)frame->arg2);
|
||||
case SYS_CLIPBOARD_GET_INFO:
|
||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||
return Sys_ClipboardGetInfo((ClipboardInfo*)frame->arg1);
|
||||
case SYS_CLIPBOARD_GET_TEXT:
|
||||
if (frame->arg2 > 0 && !ValidUserPtr(frame->arg1)) return -1;
|
||||
if (!ValidUserPtr(frame->arg3)) return -1;
|
||||
if (frame->arg4 != 0 && !IsUserPtr(frame->arg4)) return -1;
|
||||
return Sys_ClipboardGetText(IsUserPtr(frame->arg1) ? (char*)frame->arg1 : nullptr,
|
||||
(uint32_t)frame->arg2,
|
||||
(uint32_t*)frame->arg3,
|
||||
IsUserPtr(frame->arg4) ? (uint64_t*)frame->arg4 : nullptr);
|
||||
case SYS_CLIPBOARD_CLEAR:
|
||||
return Sys_ClipboardClear();
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -214,6 +214,12 @@ namespace Montauk {
|
||||
|
||||
/* CrashReport.hpp */
|
||||
static constexpr uint64_t SYS_CRASH_REPORT = 118;
|
||||
static constexpr uint64_t SYS_CLIPBOARD_SET_TEXT = 119;
|
||||
static constexpr uint64_t SYS_CLIPBOARD_GET_INFO = 120;
|
||||
static constexpr uint64_t SYS_CLIPBOARD_GET_TEXT = 121;
|
||||
static constexpr uint64_t SYS_CLIPBOARD_CLEAR = 122;
|
||||
|
||||
static constexpr uint32_t CLIPBOARD_MAX_TEXT_BYTES = 256 * 1024;
|
||||
|
||||
static constexpr uint32_t IPC_SIGNAL_READABLE = 1u << 0;
|
||||
static constexpr uint32_t IPC_SIGNAL_WRITABLE = 1u << 1;
|
||||
@@ -278,6 +284,12 @@ namespace Montauk {
|
||||
uint32_t signals;
|
||||
};
|
||||
|
||||
struct ClipboardInfo {
|
||||
uint32_t textBytes;
|
||||
uint32_t _pad;
|
||||
uint64_t serial;
|
||||
};
|
||||
|
||||
// Window server shared types
|
||||
struct WinEvent {
|
||||
uint8_t type; // 0=key, 1=mouse, 2=resize, 3=close, 4=scale
|
||||
|
||||
Reference in New Issue
Block a user