Skip to content

Commit

Permalink
rm2fb: Support pen and touch emulated inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
timower committed May 25, 2024
1 parent a4c438c commit 8a0a599
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 49 deletions.
3 changes: 1 addition & 2 deletions libs/rMlib/Input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,6 @@ handeDevice(InputManager& mgr, udev_device& dev) {
}

const auto* action = udev_device_get_action(&dev);
std::cout << "action: " << (action == nullptr ? "null" : action) << "\n";

if (action == nullptr || action == std::string_view("add")) {
mgr.open(devnode);
return;
Expand Down Expand Up @@ -351,6 +349,7 @@ InputManager::open(std::string_view input) {
auto device = makeDevice(
std::move(fd), std::move(dev), std::string(input), baseTransform);
auto* devicePtr = device.get();
std::cout << "Got device: " << device->getName() << "\n";
devices.emplace(devicePtr->path, std::move(device));
return devicePtr;
}
Expand Down
57 changes: 50 additions & 7 deletions libs/rm2fb/InputDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

#include <iostream>

namespace {
constexpr auto screen_width = 1404;
constexpr auto screen_height = 1872;
} // namespace

void
UinputDeleter::operator()(libevdev_uinput* device) {
libevdev_uinput_destroy(device);
Expand Down Expand Up @@ -119,6 +124,8 @@ makeTouchDevice() {
info.maximum = 255;
libevdev_enable_event_code(dev, EV_ABS, ABS_MT_PRESSURE, &info);

libevdev_enable_property(dev, INPUT_PROP_DIRECT);

libevdev_uinput* uidev = nullptr;
auto err = libevdev_uinput_create_from_device(
dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &uidev);
Expand All @@ -139,7 +146,6 @@ makeButtonDevice() {

libevdev_set_name(dev, "30371337.snvs:snvs-powerkey");
libevdev_enable_event_type(dev, EV_SYN);

libevdev_enable_event_type(dev, EV_KEY);
libevdev_enable_event_code(dev, EV_KEY, KEY_POWER, nullptr);

Expand Down Expand Up @@ -169,24 +175,61 @@ makeAllDevices() {
}

void
sendInput(const Input& input, libevdev_uinput& wacomDevice) {
sendPen(const Input& input, libevdev_uinput& wacomDevice) {
constexpr auto wacom_width = 15725;
constexpr auto wacom_height = 20967;

constexpr auto screen_width = 1404;
constexpr auto screen_height = 1872;

auto x = int(float(input.x) * wacom_width / screen_width);
auto y = int(wacom_height - float(input.y) * wacom_height / screen_height);

libevdev_uinput_write_event(&wacomDevice, EV_ABS, ABS_X, y);
libevdev_uinput_write_event(&wacomDevice, EV_ABS, ABS_Y, x);

if (input.type != 0) {
const auto value = input.type == 1 ? 1 : 0;
if (input.type != Input::Move) {
const auto value = input.type == Input::Down ? 1 : 0;
libevdev_uinput_write_event(&wacomDevice, EV_KEY, BTN_TOOL_PEN, value);
libevdev_uinput_write_event(&wacomDevice, EV_KEY, BTN_TOUCH, value);
}

libevdev_uinput_write_event(&wacomDevice, EV_SYN, SYN_REPORT, 0);
}

void
sendTouch(const Input& input, libevdev_uinput& touchDevice) {
constexpr auto fake_slot = 1;
constexpr auto fake_id = 123;

switch (input.type) {
case Input::Move:
break;
case Input::Down:
libevdev_uinput_write_event(&touchDevice, EV_ABS, ABS_MT_SLOT, fake_slot);
libevdev_uinput_write_event(
&touchDevice, EV_ABS, ABS_MT_TRACKING_ID, fake_id);
libevdev_uinput_write_event(&touchDevice, EV_ABS, ABS_MT_PRESSURE, 110);
libevdev_uinput_write_event(&touchDevice, EV_ABS, ABS_MT_TOUCH_MAJOR, 26);
libevdev_uinput_write_event(&touchDevice, EV_ABS, ABS_MT_TOUCH_MINOR, 26);
libevdev_uinput_write_event(&touchDevice, EV_ABS, ABS_MT_ORIENTATION, 4);

break;
case Input::Up:
libevdev_uinput_write_event(&touchDevice, EV_ABS, ABS_MT_PRESSURE, 0);
libevdev_uinput_write_event(&touchDevice, EV_ABS, ABS_MT_TRACKING_ID, -1);
libevdev_uinput_write_event(&touchDevice, EV_ABS, ABS_MT_SLOT, 0);
break;
}

libevdev_uinput_write_event(&touchDevice, EV_ABS, ABS_MT_POSITION_X, input.x);
libevdev_uinput_write_event(
&touchDevice, EV_ABS, ABS_MT_POSITION_Y, screen_height - input.y);

libevdev_uinput_write_event(&touchDevice, EV_SYN, SYN_REPORT, 0);
}

void
sendButton(bool down, libevdev_uinput& buttonDevice) {
const auto value = down ? 1 : 0;
libevdev_uinput_write_event(&buttonDevice, EV_KEY, KEY_POWER, value);

libevdev_uinput_write_event(&buttonDevice, EV_SYN, SYN_REPORT, 0);
}
8 changes: 7 additions & 1 deletion libs/rm2fb/InputDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,10 @@ AllUinputDevices
makeAllDevices();

void
sendInput(const Input& input, libevdev_uinput& wacomDevice);
sendPen(const Input& input, libevdev_uinput& wacomDevice);

void
sendTouch(const Input& input, libevdev_uinput& touchDevice);

void
sendButton(bool down, libevdev_uinput& buttonDevice);
15 changes: 10 additions & 5 deletions libs/rm2fb/Message.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,21 @@ operator<<(std::ostream& stream, const UpdateParams& msg) {
}

struct Input {
int32_t x;
int32_t y;
int32_t type; // 1 = down, 2 = up
int32_t x = 0;
int32_t y = 0;
enum Action { Move, Down, Up } type = Move;
bool touch = false; // True for touch, false for pen
};

static_assert(sizeof(Input) == 3 * 4, "Input message has unexpected size");
static_assert(sizeof(Input) == 4 * 4, "Input message has unexpected size");

struct GetUpdate {};

using ClientMsg = std::variant<Input, GetUpdate>;
struct PowerButton {
bool down;
};

using ClientMsg = std::variant<Input, GetUpdate, PowerButton>;

template<typename... T>
unistdpp::Result<void>
Expand Down
62 changes: 41 additions & 21 deletions libs/rm2fb/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,44 @@ readControlMessage(ControlSocket& serverSock, Fn&& fn) {
});
}

void
handleMsg(const SharedFB& fb,
unistdpp::FD& fd,
const AllUinputDevices& devs,
GetUpdate msg) {
doTCPUpdate(fd,
fb,
{ .y1 = 0,
.x1 = 0,
.y2 = fb_height - 1,
.x2 = fb_width - 1,
.flags = 0,
.waveform = 0 });
}

void
handleMsg(const SharedFB& fb,
unistdpp::FD& fd,
const AllUinputDevices& devs,
const Input& msg) {
if (!msg.touch && devs.wacom) {
sendPen(msg, *devs.wacom);
}
if (msg.touch && devs.touch) {
sendTouch(msg, *devs.touch);
}
}

void
handleMsg(const SharedFB& fb,
unistdpp::FD& fd,
const AllUinputDevices& devs,
const PowerButton& msg) {
if (devs.button) {
sendButton(msg.down, *devs.button);
}
}

int
serverMain(int argc, char* argv[], char** envp) { // NOLINT
setupExitHandler();
Expand All @@ -183,13 +221,7 @@ serverMain(int argc, char* argv[], char** envp) { // NOLINT
auto systemdSockets = getSystemdSockets();

// Make uinput devices
AllUinputDevices devices;
if (inQemu) {
devices = makeAllDevices();
} else {
// Only make the wacom device, used for faking input from tcp clients.
devices.wacom = makeWacomDevice();
}
auto devices = makeAllDevices();

auto serverSock = [&] {
if (systemdSockets.controlSock.has_value()) {
Expand Down Expand Up @@ -320,20 +352,8 @@ serverMain(int argc, char* argv[], char** envp) { // NOLINT
auto& clientSock = tcpClients[idx - fixedFdNum];
recvMessage<ClientMsg>(clientSock)
.map([&](const auto& msg) {
if (std::holds_alternative<GetUpdate>(msg)) {
doTCPUpdate(tcpClients.back(),
fb,
{ .y1 = 0,
.x1 = 0,
.y2 = fb_height - 1,
.x2 = fb_width - 1,
.flags = 0,
.waveform = 0 });
return;
}
if (devices.wacom) {
sendInput(std::get<Input>(msg), *devices.wacom);
}
std::visit([&](auto msg) { handleMsg(fb, clientSock, devices, msg); },
msg);
})
.or_else([&](auto err) {
std::cerr << "Reading input: " << to_string(err) << "\n";
Expand Down
4 changes: 2 additions & 2 deletions libs/unistdpp/include/unistdpp/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ fatalOnError(const tl::expected<T, E>& error, std::string_view msg = "") {
if (!error.has_value()) {
using namespace std;
std::cerr << "FATAL: " << msg << to_string(error.error()) << std::endl;
std::abort();
std::exit(EXIT_FAILURE);
}

return *error;
Expand All @@ -62,7 +62,7 @@ fatalOnError(tl::expected<T, E>&& error, std::string_view msg = "") {
if (!error.has_value()) {
using namespace std;
std::cerr << "FATAL: " << msg << to_string(error.error()) << std::endl;
std::abort();
std::exit(EXIT_FAILURE);
}

if constexpr (std::is_void_v<T>) {
Expand Down
11 changes: 6 additions & 5 deletions tools/rm2fb-emu/rm2fb-emu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ using namespace rmlib::input;

namespace {

int
Input::Action
getType(const PenEvent& touchEv) {
if (touchEv.isDown()) {
return 1;
return Input::Down;
}
if (touchEv.isUp()) {
return 2;
return Input::Up;
}
return 0;
return Input::Move;
}

struct UpdateMsg {
Expand Down Expand Up @@ -197,7 +197,8 @@ class Rm2fbState : public StateBase<Rm2fb> {
std::cout << "Touch @ " << ev.location << "\n";
}

ClientMsg input = Input{ ev.location.x, ev.location.y, type };
ClientMsg input =
Input{ ev.location.x, ev.location.y, type, /* touch */ true };
auto res = sendMessage(socket, input);
if (!res) {
std::cerr << "Error writing: " << to_string(res.error()) << "\n";
Expand Down
44 changes: 38 additions & 6 deletions tools/rm2fb-emu/rm2fb-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,23 +53,53 @@ doScreenshot(unistdpp::FD& sock, std::vector<std::string_view> args) {
return true;
}

bool
doInput(unistdpp::FD& sock, int x, int y, bool touch) {
auto input = Input{
.x = x,
.y = y,
.type = Input::Down,
.touch = touch,
};

fatalOnError(sendMessage(sock, ClientMsg(input)));
usleep(tap_wait);

input.type = Input::Up;
fatalOnError(sendMessage(sock, ClientMsg(input)));
usleep(tap_wait);

return true;
}

bool
doTouch(unistdpp::FD& sock, std::vector<std::string_view> args) {
if (args.size() != 2) {
std::cerr << "Touch requires 2 args, x and y\n";
return false;
}

auto input = Input{
.x = atoi(args[0].data()),
.y = atoi(args[1].data()),
.type = 1,
};
return doInput(sock, atoi(args[0].data()), atoi(args[1].data()), true);
}

bool
doPen(unistdpp::FD& sock, std::vector<std::string_view> args) {
if (args.size() != 2) {
std::cerr << "Touch requires 2 args, x and y\n";
return false;
}

return doInput(sock, atoi(args[0].data()), atoi(args[1].data()), false);
}

bool
doPower(unistdpp::FD& sock, std::vector<std::string_view> args) {
auto input = PowerButton{ .down = true };

fatalOnError(sendMessage(sock, ClientMsg(input)));
usleep(tap_wait);

input.type = 2;
input.down = false;
fatalOnError(sendMessage(sock, ClientMsg(input)));
usleep(tap_wait);

Expand All @@ -80,6 +110,8 @@ const std::unordered_map<std::string_view, decltype(&doScreenshot)> actions = {
{
{ "screenshot", doScreenshot },
{ "touch", doTouch },
{ "pen", doPen },
{ "power", doPower },
}
};
} // namespace
Expand Down

0 comments on commit 8a0a599

Please sign in to comment.