Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ boption(SCREENCOPY " Screencopy" ON REQUIRES WAYLAND)
boption(SCREENCOPY_ICC " Image Copy Capture" ON REQUIRES WAYLAND)
boption(SCREENCOPY_WLR " Wlroots Screencopy" ON REQUIRES WAYLAND)
boption(SCREENCOPY_HYPRLAND_TOPLEVEL " Hyprland Toplevel Export" ON REQUIRES WAYLAND)
boption(INPUT_METHOD " Input Method" ON REQUIRES WAYLAND)
boption(X11 "X11" ON)
boption(I3 "I3/Sway" ON)
boption(I3_IPC " I3/Sway IPC" ON REQUIRES I3)
Expand Down
5 changes: 5 additions & 0 deletions src/wayland/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ if (HYPRLAND)
add_subdirectory(hyprland)
endif()

if (INPUT_METHOD)
add_subdirectory(input_method)
list(APPEND WAYLAND_MODULES Quickshell.Wayland._InputMethod)
endif()

# widgets for qmenu
target_link_libraries(quickshell-wayland PRIVATE
Qt::Quick Qt::Widgets Qt::WaylandClient Qt::WaylandClientPrivate
Expand Down
38 changes: 38 additions & 0 deletions src/wayland/input_method/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
set(INPUT_METHOD_PRINT_KETS OFF)

qt_add_library(quickshell-wayland-input-method STATIC
input_method.cpp
keyboard_grab.cpp
virtual_keyboard.cpp
key_map_state.cpp
manager.cpp
qml.cpp
qml_helpers.cpp
c_helpers.cpp
)

target_compile_definitions(quickshell-wayland-input-method PRIVATE INPUT_METHOD_PRINT=0)

qt_add_qml_module(quickshell-wayland-input-method
URI Quickshell.Wayland._InputMethod
VERSION 0.1
DEPENDENCIES QtQml
)

qs_add_module_deps_light(quickshell-wayland-input-method
Quickshell Quickshell.Wayland
)

install_qml_module(quickshell-wayland-input-method)

wl_proto(zwp-input-method input-method-unstable-v2 "${CMAKE_CURRENT_SOURCE_DIR}")
wl_proto(zwp-virtual-keyboard virtual-keyboard-unstable-v1 "${CMAKE_CURRENT_SOURCE_DIR}")

target_link_libraries(quickshell-wayland-input-method PRIVATE
Qt::Quick Qt::WaylandClient Qt::WaylandClientPrivate wayland-client
zwp-input-method zwp-virtual-keyboard
)

qs_module_pch(quickshell-wayland-input-method SET large)

target_link_libraries(quickshell PRIVATE quickshell-wayland-input-methodplugin)
72 changes: 72 additions & 0 deletions src/wayland/input_method/c_helpers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include "c_helpers.hpp"
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <utility>

#include <qdebug.h>
#include <qlogging.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <unistd.h>

namespace qs::wayland::input_method::impl {

void FreeDeleter::operator()(const char* p) const {
std::free(const_cast<std::remove_const_t<char>*>(p)); // NOLINT
}

SharedMemory::SharedMemory(const char* shmName, int oFlag, size_t size)
: mShmName(shmName)
, mSize(size)
, fd(shm_open(this->mShmName, oFlag, 0))
, map(nullptr) {
if (this->fd == -1) {
perror("");
qDebug() << "Virtual keyboard failed to open shared memory";
return;
}
if (ftruncate(this->fd, static_cast<int>(size)) == -1) {
this->fd = -1;
perror("");
qDebug() << "Virtual keyboard failed to resize shared memory to" << size;
return;
}
this->map = static_cast<char*>(mmap(nullptr, this->mSize, PROT_WRITE, MAP_SHARED, this->fd, 0));
if (this->map == MAP_FAILED) {
perror("");
qDebug() << "Virtual keyboard failed to open shared memory";
return;
}
}
SharedMemory::~SharedMemory() {
if (this->fd != -1) {
close(this->fd);
shm_unlink(this->mShmName);
}
if (this->map != nullptr) {
munmap(this->map, this->mSize);
}
}
SharedMemory::SharedMemory(SharedMemory&& other) noexcept
: mShmName(std::exchange(other.mShmName, nullptr))
, mSize(std::exchange(other.mSize, 0))
, fd(std::exchange(other.fd, -1))
, map(std::exchange(other.map, nullptr)) {}
SharedMemory& SharedMemory::operator=(SharedMemory&& other) noexcept {
this->mShmName = std::exchange(other.mShmName, nullptr);
this->mSize = std::exchange(other.mSize, 0);
this->fd = std::exchange(other.fd, -1);
this->map = std::exchange(other.map, nullptr);
return *this;
}

SharedMemory::operator bool() const { return fd != -1 && map != MAP_FAILED; }
[[nodiscard]] int SharedMemory::get() const { return fd; }

void SharedMemory::write(const char* string) {
if (!this->map) return;
strcpy(this->map, string);
}

} // namespace qs::wayland::input_method::impl
37 changes: 37 additions & 0 deletions src/wayland/input_method/c_helpers.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once

#include <memory>

#include <sys/mman.h>

namespace qs::wayland::input_method::impl {

struct FreeDeleter {
void operator()(const char* p) const;
};
// Dont use this for literals, only c strings that were allocated
using uniqueCString = std::unique_ptr<const char, FreeDeleter>;

// this is a bit half baked but works for what I need it for
class SharedMemory {
public:
SharedMemory(const char* shmName, int oFlag, size_t size);
~SharedMemory();
SharedMemory(const SharedMemory&) = delete;
SharedMemory(SharedMemory&& other) noexcept;
SharedMemory& operator=(const SharedMemory&) = delete;
SharedMemory& operator=(SharedMemory&& other) noexcept;

[[nodiscard]] operator bool() const;
[[nodiscard]] int get() const;

void write(const char* string);

private:
const char* mShmName;
size_t mSize;
int fd;
char* map = nullptr;
};

} // namespace qs::wayland::input_method::impl
Loading
Loading