v icon indicating copy to clipboard operation
v copied to clipboard

termui detect keyboard / mouse keyup event

Open alfu32 opened this issue 2 years ago • 1 comments

Describe the feature

termios should detect a event of type keyup from keyboard devices.

One reason I think is that the terminal emulator is simply not raising those events.

Use Case

if a key is pressed the user expects that the keystroke should repeat itself after a short pause with a frequency greater than the short pause.

Please note that gg module raises the keyup event.

Uses cases:

  • terminal text editors[1]
  • terminal games[1]
  • terminal editors[2]

[1] ( where key repeat or multiple key presses could be required ) [2] where arrow keys could be used to move visual stuff around.

Proposed Solution

One first step would be to actually introduce the event type key_up

pub enum EventType {
	...
	key_up
}

since the windows and unix implementations are quite different I assume that they could even be developed at different stages.

consider this as a first inquiry about the pertinence of introducing this feature in the standard library, its' cross-platform feasibility.

Other Information

Solution I currently employ.

notice the usage of that the struct input_event from input/input_event.h the device is read raw from fopen("/dev/event*") and not from C.STDIN_FILENO.


    #include <linux/input.h>
    #include <linux/input-event-codes.h>


    typedef struct Keyboard {
        struct termios oldt;
        struct termios newt;
        // maps key_code to corresponding char
        // if a key is not pressed the value of the corresponding key_code is 0
        // if a key is pressed the value of the corresponding key_code is the corresponding char
        char key_state[KEY_MAX];
        // fd of the keyboard device
        int device;
        struct input_event ev;
    } Keyboard;
    
    // it reads the input device synchronously and sets or unsets the
    // element that corresponds to the read event key code in the key_state key map
    int read_events(Keyboard *self) {

        ssize_t bytesRead = read(self->device, &(self->ev), sizeof(struct input_event));

        if (bytesRead == -1) {
            // perror("Error reading input event");
        } else if (bytesRead == sizeof(struct input_event)) {

            if (self->ev.type == EV_KEY) {
                // when ev.value == 0 the key was up
                if (self->ev.value == 0) {
                    self->key_state[self->ev.code] = 0;
                } else
                // when ev.value == 1 the key was down ( pressed )
                if (self->ev.value == 1) {
                    self->key_state[self->ev.code] = map_keycode_to_char(self->ev.code);
                }

            }

        }
        return 0;
    }

Acknowledgements

  • [X] I may be able to implement this feature request
  • [X] This feature might incur a breaking change

Version used

V 0.4.3 5b9d0f2

Environment details (OS name and version, etc.)

Linux 6.2.0-37-generic #38~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC x86_64 GNU/Linux

Distributor ID: Ubuntu Description: Ubuntu 22.04.3 LTS Release: 22.04 Codename: jammy

TERM=xterm-256color gnome-terminal-server (wayland)

I assume that on Windows the behaviour is the same

alfu32 avatar Jan 08 '24 14:01 alfu32

example of how it should behave:

  • pressing multiple keys shows all of them as pressed ( active )
import gg
struct App{
	pub  mut:
	current gg.Event
	buffer map[string]string
}
mut a:= &App{}

gg.start(
	window_title: 'Hello'
	bg_color: gg.Color{240, 240, 128, 255}
	width: 320
	height: 240
	event_fn: fn [mut a](e &gg.Event, data voidptr) {
		a.current=e
		cb := e.key_code.str()
		cc := e.char_code
		cd := if cb == 'invalid' { [u8(cc & 0xFF)].bytestr() } else { cb }
		if e.typ == .char {
			a.buffer[[u8(cc & 0xFF)].bytestr()]=[u8(cc & 0xFF)].bytestr()
		} else if e.typ == .key_up {
				a.buffer[cb]="-"
		}
	}
	frame_fn: fn [a](mut ctx &gg.Context) {
		ctx.begin()
		ctx.draw_text(40, 100, 'GG frame: ${ctx.frame:06} ${a.buffer}',
			size: 30
			color: gg.Color{50, 50, 255, 255}
		)
		ctx.show_fps()
		ctx.end()
	}
)

alfu32 avatar Jan 08 '24 15:01 alfu32