RVVM icon indicating copy to clipboard operation
RVVM copied to clipboard

Virtual Terminal as UART backend

Open ghost opened this issue 2 years ago • 4 comments

Hello I'd like to add VT support to RVVM.

Exact requirements

I think it should:

  • compatible with TERM=xterm, with a good score from vttest, https://www.invisible-island.net/vttest/
  • takeover fb_window for input/output, a keyboard shortcut can be used to switch between VT and original mode
  • support UTF-8, has built-in font for ASCII, can load external font file for CJK etc.
  • maybe color support, so compatible with TERM=xterm-256color
  • maybe bold and itatic support, with seperated font files

Suggested solution

My current plan are:

  • use libvterm for VT emulation, can be switch out later..

  • support pcbasic / hex font format, pre-made (.hex) fonts: https://github.com/robhagemans/pcbasic/tree/master/pcbasic/data/fonts tools: https://github.com/robhagemans/monobit

  • implement a chardev VT backend, with fb_window takeover and switch logic

Expected results and side effects

The showcase can be TERM=xterm-mono emacs -nw running in OpenBSD editing UTF-8 text, via RetroArch...

How does this sound?

ghost avatar Jun 28 '23 11:06 ghost

Very good idea, some more things I'd love to add:

  • Intermediate API to look at VT contents as a character array with color attributes. I need this for one of my side projects, and it also can bring proper VT state saving and VT support on older Windows hosts.
  • Perhaps some way to build it in-tree without fetching separate repos or relying on lib presence in the system at build or run time (A directory like deps/ or src/deps/ may be used)
  • @nebulka1 almost finished an inhouse VT100 emulation but didn't complete it, and maybe we could have some kind of authentic inhouse retro VT at some point if that work has some traction again

LekKit avatar Jun 28 '23 14:06 LekKit

Very good idea, some more things I'd love to add:

  • Intermediate API to look at VT contents as a character array with color attributes. I need this for one of my side projects, and it also can bring proper VT state saving and VT support on older Windows hosts.

libvterm has those:

typedef struct {
  uint32_t chars[VTERM_MAX_CHARS_PER_CELL];
  char     width;
  VTermScreenCellAttrs attrs;
  VTermColor fg, bg;
} VTermScreenCell;

size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect);
size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect);
int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell);

which seems fine.

Now I'm trying to implement "input takeover" by hook hid_keyboard with:

+PUBLIC void hid_keyboard_hook(hid_keyboard_t* kb,
+                              bool (*on_press)(hid_key_t key),
+                              bool (*on_release)(hid_key_t key))
+{
+    kb->on_press = on_press;
+    kb->on_release = on_release;
+}
+
 PUBLIC void hid_keyboard_press(hid_keyboard_t* kb, hid_key_t key)
 {
     bool is_input_avail = false;
+    if (kb->on_press && kb->on_press(key))
+        return;
     spin_lock(&kb->lock);
     // key is guaranteed to be 1 byte according to HID spec
     if (key != HID_KEY_NONE) {
@@ -188,6 +204,8 @@ PUBLIC void hid_keyboard_press(hid_keyboard_t* kb, hid_key_t key)
 PUBLIC void hid_keyboard_release(hid_keyboard_t* kb, hid_key_t key)
 {
     bool is_input_avail = false;
+    if (kb->on_release && kb->on_release(key))
+        return;
     spin_lock(&kb->lock);
     if (key != HID_KEY_NONE) {
         kb->keys[key/32] &= ~(1U << (key%32));

So in fb_window (instead of in sdl_window, etc.) I can handle input with:

+static bool keyboard_press(hid_key_t key)
+{
+    rvvm_info("key pressed: %d", key);
+    return false; // !! return true to stop propagate event to the guest
+}
+
+static bool keyboard_release(hid_key_t key)
+{
+    rvvm_info("key released: %d", key);
+    return false;
+}
+
 bool fb_window_init_auto(rvvm_machine_t* machine, uint32_t width, uint32_t height)
 {
     fb_window_t* window = safe_calloc(sizeof(fb_window_t), 1);
@@ -125,15 +137,17 @@ bool fb_window_init_auto(rvvm_machine_t* machine, uint32_t width, uint32_t heigh
     window->machine = machine;
     window->keyboard = hid_keyboard_init_auto(machine);
     window->mouse = hid_mouse_init_auto(machine);
+    hid_keyboard_hook(window->keyboard, keyboard_press, keyboard_release);

Does this look reasonable? :thinking:

ghost avatar Jul 01 '23 03:07 ghost

I think we shouldn't pollute the hid_api itself, or the actual devices (reinventing something inside the device would be bad). What I think should be done is more refining for fb_window, it is purposed as a middle-ground between raw machine APIs (framebuffer, hid_api) and native windowing backends (SDL, X11, Win32, Haiku). Perhaps you could implement something like gui_keypress() with same semantics as the hid call, and then translate it to whatever you like.

LekKit avatar Jul 01 '23 06:07 LekKit

Okay, that gui_keypress seems more clearly to me too. Haven't got much time to works on this yet, hope to pick this up later...

ghost avatar Jul 26 '23 13:07 ghost