Saturday, April 28, 2018

text based user interface: termbox tutorial - 3. mouse input

When we talk about user interface, it is always about keyboard and mouse. In most cases, mouse is the most handy interface.

termbox provide the library to interact with mouse. It is simple and easy. For simple, it comes with missing feature. I was wrong; termbox is a great library. I will explain it at the latter part of blog.

For example, I need to click on the box which is comprised of few blocks. I named the block "ESC", I need to click in the very middle of each character, then only the mouse click event is detected.

Either way, it is still a good feature. Better than none.

As usual, paste the source code here.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <stdio.h>
#include <string.h>
#include "../termbox.h"

struct key {
        unsigned char x;
        unsigned char y;
        uint32_t ch;
};

static const char chars_hw[] = "hello world";

#define STOP {0,0,0}
struct key K_ESC[] = {{1,1,'E'},{2,1,'S'},{3,1,'C'},STOP};
void draw_key(struct key *k, uint16_t fg, uint16_t bg)
{
        while (k->x) {
                tb_change_cell(k->x+2, k->y+4, k->ch, fg, bg);
                k++;
        }
}

int main(int argv, char **argc) {
        (void)argc; (void)argv;
        int code = tb_init();
        if (code < 0) {
                fprintf(stderr, "termbox init failed, code: %d\n", code);
                return -1;
        }

        tb_select_input_mode(TB_INPUT_ESC | TB_INPUT_MOUSE);
        tb_select_output_mode(TB_OUTPUT_256);
        tb_clear();

        int j, k;
        for (k = 0; k < 5; k++) {
                j = 0;
                while(chars_hw[j] != 0) {
                        tb_change_cell(j, k, chars_hw[j], 32+j, 231-k);
                        j++;
                }
        }

        draw_key(K_ESC, TB_WHITE, TB_BLUE);

        tb_present();

        for (;;) {
                struct tb_event ev;
                int mx = -1;
                int my = -1;
                int t = tb_poll_event(&ev);
                if (t == -1) {
                        tb_shutdown();
                        fprintf(stderr, "termbox poll event error\n");
                        return -1;
                }

                switch (t) {
                case TB_EVENT_KEY:
                        if (ev.key == TB_KEY_ESC) {
                                tb_shutdown();
                                return 0;
                        }
                        break;
                case TB_EVENT_MOUSE:
                        if (ev.key == TB_KEY_MOUSE_LEFT) {
                                mx = ev.x;
                                my = ev.y;

                                if((mx >= 3 && mx <= 5) && my == 5) {
                                        tb_shutdown();
                                        return 0;
                                }
                        }
                        break;
                }
        }
}

I created a development folder inside the termbox-master, directory as "termbox-master/src/development".

to compile - "gcc mouse.c ../termbox.c ../utf8.c -o mouse".

You will have the mouse binary file. Run that file "./mouse" and you will get the following:

After some trying, I noticed that I have to click twice in order to close the program. This is weird and most likely is my mistake, so I did some debugging and read the demo file - keyboard.c.

There are several input for mouse clicks:
TB_KEY_MOUSE_LEFT:
TB_KEY_MOUSE_MIDDLE:
TB_KEY_MOUSE_RIGHT:
TB_KEY_MOUSE_WHEEL_UP:
TB_KEY_MOUSE_RELEASE:

ah, ha. I need to have one click and one release, then only it is detected as valid mouse click.

I re-modify the program and adding detection for click and release:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
                case TB_EVENT_MOUSE:
                        if (ev.key == TB_KEY_MOUSE_LEFT)
                                detect_click = 1;

                        if (ev.key == TB_KEY_MOUSE_RELEASE)
                                detect_release = 1;

                                mx = ev.x;
                                my = ev.y;
                        if (detect_click == 1 && detect_release == 1) {
                                detect_click = 0;
                                detect_release = 0;
                                if((mx >= 3 && mx <= 5) && my == 5) {
                                        tb_shutdown();
                                        return 0;

                                }
                        }
                        break;
                }

After adding that, the program working fine without error.

Termbox is a great TUI library.


No comments:

Post a Comment