From ed80a972b6d34f998f97c006da28cfe47b643393 Mon Sep 17 00:00:00 2001 From: Timothy Werquin Date: Wed, 20 Jan 2021 21:12:04 +0100 Subject: [PATCH] Yaft: tty mouse support --- apps/yaft/ctrlseq/csi.h | 4 ++ apps/yaft/fb/common.cpp | 22 ++++----- apps/yaft/keyboard.cpp | 105 ++++++++++++++++++++++++++++------------ apps/yaft/keyboard.h | 7 +-- apps/yaft/terminal.h | 2 + apps/yaft/yaft.h | 3 ++ 6 files changed, 97 insertions(+), 46 deletions(-) mode change 100644 => 100755 apps/yaft/fb/common.cpp mode change 100644 => 100755 apps/yaft/terminal.h mode change 100644 => 100755 apps/yaft/yaft.h diff --git a/apps/yaft/ctrlseq/csi.h b/apps/yaft/ctrlseq/csi.h index 73bd62f..2d4add8 100755 --- a/apps/yaft/ctrlseq/csi.h +++ b/apps/yaft/ctrlseq/csi.h @@ -429,6 +429,8 @@ set_mode(struct terminal_t* term, struct parm_t* parm) { term->mode |= MODE_CURSOR; } else if (mode == 8901) { term->mode |= MODE_VWBS; + } else if (mode == 1000) { + term->mode |= MODE_MOUSE; } else { printf("UNKNOWN MODE: %d\n", mode); } @@ -457,6 +459,8 @@ reset_mode(struct terminal_t* term, struct parm_t* parm) { term->mode &= ~MODE_CURSOR; } else if (mode == 8901) { term->mode &= ~MODE_VWBS; + } else if (mode == 1000) { + term->mode &= ~MODE_MOUSE; } } } diff --git a/apps/yaft/fb/common.cpp b/apps/yaft/fb/common.cpp old mode 100644 new mode 100755 index f888452..500bda9 --- a/apps/yaft/fb/common.cpp +++ b/apps/yaft/fb/common.cpp @@ -20,10 +20,7 @@ color2pixel(uint32_t color) { } static inline void -draw_sixel(rmlib::fb::FrameBuffer& fb, - int margin_top, - int col, - uint8_t* pixmap) { +draw_sixel(rmlib::fb::FrameBuffer& fb, int y_start, int col, uint8_t* pixmap) { int h, w, src_offset, dst_offset; uint32_t pixel, color = 0; @@ -32,7 +29,7 @@ draw_sixel(rmlib::fb::FrameBuffer& fb, src_offset = BYTES_PER_PIXEL * (h * CELL_WIDTH + w); memcpy(&color, pixmap + src_offset, BYTES_PER_PIXEL); - dst_offset = (margin_top + h) * fb.canvas.lineSize() + + dst_offset = (y_start + h) * fb.canvas.lineSize() + (col * CELL_WIDTH + w) * fb.canvas.components; pixel = color2pixel(color); memcpy(fb.canvas.memory + dst_offset, &pixel, fb.canvas.components); @@ -42,13 +39,13 @@ draw_sixel(rmlib::fb::FrameBuffer& fb, static inline void draw_line(rmlib::fb::FrameBuffer& fb, struct terminal_t* term, int line) { - int pos, bdf_padding, glyph_width, margin_right, margin_top; + int pos, bdf_padding, glyph_width, margin_right, y_start; int col, w, h; uint32_t pixel; struct color_pair_t color_pair; struct cell_t* cellp; - margin_top = (term->height - term->lines * CELL_HEIGHT) + line * CELL_HEIGHT; + y_start = term->marginTop + line * CELL_HEIGHT; for (col = term->cols - 1; col >= 0; col--) { margin_right = (term->cols - 1 - col) * CELL_WIDTH; @@ -58,7 +55,7 @@ draw_line(rmlib::fb::FrameBuffer& fb, struct terminal_t* term, int line) { /* draw sixel pixmap */ if (cellp->has_pixmap) { - draw_sixel(fb, margin_top, col, cellp->pixmap); + draw_sixel(fb, y_start, col, cellp->pixmap); continue; } @@ -91,7 +88,7 @@ draw_line(rmlib::fb::FrameBuffer& fb, struct terminal_t* term, int line) { for (w = 0; w < CELL_WIDTH; w++) { pos = (term->width - 1 - margin_right - w) * fb.canvas.components + - (margin_top + h) * fb.canvas.lineSize(); + (y_start + h) * fb.canvas.lineSize(); /* set color palette */ if (cellp->glyphp->bitmap[h] & (0x01 << (bdf_padding + w))) @@ -106,10 +103,9 @@ draw_line(rmlib::fb::FrameBuffer& fb, struct terminal_t* term, int line) { } /* actual display update (bit blit) */ - fb.doUpdate( - { { 0, margin_top }, { fb.canvas.width, margin_top + CELL_HEIGHT } }, - rmlib::fb::Waveform::DU, - rmlib::fb::UpdateFlags::None); + fb.doUpdate({ { 0, y_start }, { fb.canvas.width, y_start + CELL_HEIGHT } }, + rmlib::fb::Waveform::DU, + rmlib::fb::UpdateFlags::None); /* TODO: page flip if fb_fix_screeninfo.ypanstep > 0, we can use hardware panning. diff --git a/apps/yaft/keyboard.cpp b/apps/yaft/keyboard.cpp index d1853a6..2b26b51 100755 --- a/apps/yaft/keyboard.cpp +++ b/apps/yaft/keyboard.cpp @@ -248,17 +248,16 @@ Keyboard::init(rmlib::fb::FrameBuffer& fb, terminal_t& term) { } auto inputs = device::getInputPaths(*dev); - auto fd = input.open(inputs.touchPath.data(), inputs.touchTransform); - if (!fd.has_value()) { + const auto touchFd = + input.open(inputs.touchPath.data(), inputs.touchTransform); + if (!touchFd.has_value()) { return false; } - this->touchFd = *fd; - fd = input.open(inputs.penPath.data(), inputs.penTransform); - if (!fd.has_value()) { + const auto penFd = input.open(inputs.penPath.data(), inputs.penTransform); + if (!penFd.has_value()) { return false; } - this->penFd = *fd; // Setup the keymap. int y = startHeight; @@ -287,6 +286,10 @@ Keyboard::init(rmlib::fb::FrameBuffer& fb, terminal_t& term) { rowNum++; } + int marginLeft = term.width - term.cols * CELL_WIDTH; + this->screenRect = + Rect{ { marginLeft, term.marginTop }, { term.width - 1, term.height - 1 } }; + return true; } @@ -393,32 +396,68 @@ Keyboard::sendKeyDown(const Key& key) const { } } +namespace { +template +struct event_traits; + +template<> +struct event_traits { + constexpr static auto up_type = TouchEvent::Up; + constexpr static auto down_type = TouchEvent::Down; + + constexpr static auto getSlot(const TouchEvent& ev) { return ev.slot; } +}; + +template<> +struct event_traits { + constexpr static auto up_type = PenEvent::TouchUp; + constexpr static auto down_type = PenEvent::TouchDown; + + constexpr static auto getSlot(const PenEvent& ev) { return pen_slot; } +}; + template void -handleEvent(Keyboard& kb, const Event& ev) { - constexpr auto down_type = [] { - if constexpr (std::is_same_v) { - return TouchEvent::Down; - } else { - return PenEvent::TouchDown; - } - }(); - constexpr auto up_type = [] { - if constexpr (std::is_same_v) { - return TouchEvent::Up; - } else { - return PenEvent::TouchUp; +handleScreenEvent(Keyboard& kb, const Event& ev) { + if ((kb.term->mode & MODE_MOUSE) == 0) { + return; + } + + const auto slot = event_traits::getSlot(ev); + + const auto loc = ev.location - kb.screenRect.topLeft; + char cx = 33 + (loc.x / CELL_WIDTH); + char cy = 33 + (loc.y / CELL_HEIGHT); + char buf[] = { esc_char, '[', 'M', 32, cx, cy }; + + if (ev.type == event_traits::down_type) { + if (kb.mouseSlot != -1) { + return; } - }(); - const auto slot = [&] { - if constexpr (std::is_same_v) { - return ev.slot; - } else { - return pen_slot; + + kb.mouseSlot = slot; + + // Send mouse down code + buf[3] += 0; // mouse button 1 + write(kb.term->fd, buf, 6); + + } else if (ev.type == event_traits::up_type) { + if (kb.mouseSlot != slot) { + return; } - }(); - if (ev.type == down_type) { + kb.mouseSlot = -1; + + // Send mouse up code + buf[3] += 3; // mouse release + write(kb.term->fd, buf, 6); + } +} + +template +void +handleKeyEvent(Keyboard& kb, const Event& ev) { + if (ev.type == event_traits::down_type) { // lookup key, skip if outside auto* key = kb.getKey(ev.location); if (key == nullptr) { @@ -427,7 +466,7 @@ handleEvent(Keyboard& kb, const Event& ev) { std::cerr << "key down: " << key->info.name << std::endl; - key->slot = slot; + key->slot = event_traits::getSlot(ev); key->nextRepeat = time_source::now() + repeat_delay; kb.drawKey(*key); @@ -452,7 +491,8 @@ handleEvent(Keyboard& kb, const Event& ev) { key->stuck = false; } - } else if (ev.type == up_type) { + } else if (ev.type == event_traits::up_type) { + const auto slot = event_traits::getSlot(ev); auto keyIt = std::find_if(kb.keys.begin(), kb.keys.end(), [slot](const auto& key) { return key.slot == slot; @@ -468,6 +508,7 @@ handleEvent(Keyboard& kb, const Event& ev) { keyIt->keyRect, rmlib::fb::Waveform::DU, rmlib::fb::UpdateFlags::None); } } +} // namespace void Keyboard::handleEvents(const std::vector& events) { @@ -475,7 +516,11 @@ Keyboard::handleEvents(const std::vector& events) { std::visit( [this](const auto& ev) { if constexpr (!std::is_same_v, KeyEvent>) { - handleEvent(*this, ev); + if (screenRect.contains(ev.location)) { + handleScreenEvent(*this, ev); + } else { + handleKeyEvent(*this, ev); + } } }, event); diff --git a/apps/yaft/keyboard.h b/apps/yaft/keyboard.h index 1d5e659..3e7272e 100755 --- a/apps/yaft/keyboard.h +++ b/apps/yaft/keyboard.h @@ -60,14 +60,15 @@ struct Keyboard { // members int baseKeyWidth; int startHeight; + rmlib::Rect screenRect; - int touchFd; - int penFd; rmlib::input::InputManager input; rmlib::fb::FrameBuffer* fb; terminal_t* term; - // Slots for tracking modifier state. + int mouseSlot = -1; + + // Pointers for tracking modifier state. Key* shiftKey = nullptr; Key* altKey = nullptr; Key* ctrlKey = nullptr; diff --git a/apps/yaft/terminal.h b/apps/yaft/terminal.h old mode 100644 new mode 100755 index 18e090e..7a18ba0 --- a/apps/yaft/terminal.h +++ b/apps/yaft/terminal.h @@ -359,6 +359,8 @@ term_init(struct terminal_t* term, int width, int height) { term->cols = term->width / CELL_WIDTH; term->lines = term->height / CELL_HEIGHT; + term->marginTop = (term->height - term->lines * CELL_HEIGHT); + term->esc.size = ESCSEQ_SIZE; logging(DEBUG, "terminal cols:%d lines:%d\n", term->cols, term->lines); diff --git a/apps/yaft/yaft.h b/apps/yaft/yaft.h old mode 100644 new mode 100755 index 1227f0f..2c9c572 --- a/apps/yaft/yaft.h +++ b/apps/yaft/yaft.h @@ -125,6 +125,7 @@ enum term_mode { MODE_AMRIGHT = 0x04, /* auto wrap: DECAWM */ MODE_VWBS = 0x08, /* variable-width backspace */ MODE_APP_CURSOR = 0x10, /* app cursor mode */ + MODE_MOUSE = 0x20, /* enable xterm mouse */ }; #ifdef __cplusplus @@ -240,6 +241,8 @@ struct terminal_t { const struct glyph_t* glyph[UCS2_CHARS]; /* array of pointer to glyphs[] */ struct glyph_t drcs[DRCS_CHARS]; /* DRCS chars */ struct sixel_canvas_t sixel; + + int marginTop; }; struct parm_t { /* for parse_arg() */