Windows Console TUI, functions vs methods, class not working

Hi everyone.

I've created a library that uses the windows.h library to make text user interfaces (TUIs) through functions, and it works wonderfully except for mouse and unbuffered input.

Now I tried to turn those functions in a class with static methods and those regarding printing (cursor positioning, coloring) aren't working anymore!

I'm aware of the C++ feature that disables the reference to stuff declared as static (and const too) and have already implemented the workaround for it, but saw no change.

The code's too big to post but if I don't get an answer until tomorrow (I should be sleeping by my time zone) I'll post it. Worst case scenario I can use the old function based one, so it's not that big deal.

Thanks in advance.

Edit: here's a test program:

1
2
3
4
5
6
// util.h
// general purpose utilities file
// only one utility coded so far
int getbit (int variable, int bit) {
    return (((1<<bit)&variable)>>bit);
}

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
// tui_old.h
// text user interface file implemented as functions, working
#define tui_black 0b0000
#define tui_dred 0b0001
#define tui_dyellow 0b0011
#define tui_dgreen 0b0010
#define tui_dcyan 0b0110
#define tui_dblue 0b0100
#define tui_dmagenta 0b0101
#define tui_bgray 0b0111

#define tui_dgray 0b1000
#define tui_bred 0b1001
#define tui_byellow 0b1011
#define tui_bgreen 0b1010
#define tui_bcyan 0b1110
#define tui_bblue 0b1100
#define tui_bmagenta 0b1101
#define tui_white 0b1111

void tui_setConsoleName (char * name) {
    SetConsoleTitle(name);
}

void tui_setCurPos (int x, int y) {
    COORD position;
    position.X = x;
    position.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),position);
}

void tui_clearScreen () {
    for (int tui_i = 0; tui_i < 60; tui_i++)
        printf("\n");
}

void tui_setCursor (int intensity = 100, bool state = true) {
    CONSOLE_CURSOR_INFO ConCurInf;
    ConCurInf.dwSize = intensity;
    ConCurInf.bVisible = state;
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&ConCurInf);
}

void tui_setColor (int fcolor, int bcolor) {
    int tui_color = 0;
    tui_color |= ((getbit(fcolor,3) == 1)?FOREGROUND_INTENSITY:0);
    tui_color |= ((getbit(fcolor,2) == 1)?FOREGROUND_BLUE:0);
    tui_color |= ((getbit(fcolor,1) == 1)?FOREGROUND_GREEN:0);
    tui_color |= ((getbit(fcolor,0) == 1)?FOREGROUND_RED:0);
    tui_color |= ((getbit(bcolor,3) == 1)?BACKGROUND_INTENSITY:0);
    tui_color |= ((getbit(bcolor,2) == 1)?BACKGROUND_BLUE:0);
    tui_color |= ((getbit(bcolor,1) == 1)?BACKGROUND_GREEN:0);
    tui_color |= ((getbit(bcolor,0) == 1)?BACKGROUND_RED:0);
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),tui_color);
}

bool tui_getKey (char * tui_key) {
    HANDLE tui_handle = GetStdHandle(STD_INPUT_HANDLE);
    DWORD tui_evtc;
    GetNumberOfConsoleInputEvents(tui_handle,&tui_evtc);
    INPUT_RECORD tui_inrec;
    DWORD tui_numread;
    bool tui_havehappened = false;
    while (tui_evtc > 0) {
        ReadConsoleInput(tui_handle,&tui_inrec,1,&tui_numread);
        if (tui_inrec.EventType == KEY_EVENT) {
            if (tui_inrec.Event.KeyEvent.bKeyDown) {
                *tui_key = tui_inrec.Event.KeyEvent.wVirtualKeyCode;
                tui_havehappened = true;
            }
        }
        GetNumberOfConsoleInputEvents(tui_handle,&tui_evtc);
    }
    return tui_havehappened;
}

Last edited on
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// TUI.h
// same as last, but modified into a class, everything other than input not working
// classe para gerar interface gráfica em modo texto

// definições de cores
#define tui_black 0b0000
#define tui_dred 0b0001
#define tui_dyellow 0b0011
#define tui_dgreen 0b0010
#define tui_dcyan 0b0110
#define tui_dblue 0b0100
#define tui_dmagenta 0b0101
#define tui_bgray 0b0111

#define tui_dgray 0b1000
#define tui_bred 0b1001
#define tui_byellow 0b1011
#define tui_bgreen 0b1010
#define tui_bcyan 0b1110
#define tui_bblue 0b1100
#define tui_bmagenta 0b1101
#define tui_white 0b1111

class TUI {
private:
    // variáveis utilizadas pela biblioteca windows
    static COORD position;
    static HANDLE handle;
    static CONSOLE_CURSOR_INFO conCurInf;
    static DWORD eventCount;
    static INPUT_RECORD inputRecord;
    static DWORD numberRead;
    static int color;
    static bool haveHappened;
    static int i;
public:
    TUI () {}
    static void init () {
        handle = GetStdHandle(STD_INPUT_HANDLE);
    }
    static void setConsoleName (char * NAME) { // altera o título da janela
        SetConsoleTitle(NAME);
    }
    static void setCurPos (int X, int Y) { // altera a posição do cursor
        position.X = X;
        position.Y = Y;
        SetConsoleCursorPosition(handle,position);
    }
    static void clearScreen () { // limpa a tela
        for (int i = 0; i < 60; i++) printf("\n");
    }
    static void setCursor (int SIZE = 100, bool STATE = true) { // altera o tamanho do cursor e o liga/desliga
        if (SIZE > 100) SIZE = 100;
        conCurInf.dwSize = SIZE;
        conCurInf.bVisible = STATE;
        SetConsoleCursorInfo(handle,&conCurInf);
    }
    static void setColor (int FCOLOR, int BCOLOR) { // muda a cor do texto (foreground) e do fundo (background)
        color = 0;
        color |= ((getbit(FCOLOR,3) == 1)?FOREGROUND_INTENSITY:0);
        color |= ((getbit(FCOLOR,2) == 1)?FOREGROUND_BLUE:0);
        color |= ((getbit(FCOLOR,1) == 1)?FOREGROUND_GREEN:0);
        color |= ((getbit(FCOLOR,0) == 1)?FOREGROUND_RED:0);
        color |= ((getbit(BCOLOR,3) == 1)?BACKGROUND_INTENSITY:0);
        color |= ((getbit(BCOLOR,2) == 1)?BACKGROUND_BLUE:0);
        color |= ((getbit(BCOLOR,1) == 1)?BACKGROUND_GREEN:0);
        color |= ((getbit(BCOLOR,0) == 1)?BACKGROUND_RED:0);
        SetConsoleTextAttribute(handle,color);
    }
    static bool getKey (char * KEY) {
    // retorna se havia uma tecla pressionada no momento da chamada e se havia, guarda qual tecla no parâmetro
        GetNumberOfConsoleInputEvents(handle,&eventCount);
        haveHappened = false;
        while (eventCount > 0) {
            ReadConsoleInput(handle,&inputRecord,1,&numberRead);
            if (inputRecord.EventType == KEY_EVENT) {
                if (inputRecord.Event.KeyEvent.bKeyDown) {
                    *KEY = inputRecord.Event.KeyEvent.wVirtualKeyCode;
                    haveHappened = true;
                }
            }
            GetNumberOfConsoleInputEvents(handle,&eventCount);
        }
        return haveHappened;
    }
};

// bug do C++: quando coisas são declaradas como 'static' (e const também), elas perdem suas referências,
// e só é possível obter o valor que elas guardam, como '#defines'
// para restaurar a referência, é necessário declarar as variáveis como segue:
COORD TUI::position;
HANDLE TUI::handle;
CONSOLE_CURSOR_INFO TUI::conCurInf;
DWORD TUI::eventCount;
INPUT_RECORD TUI::inputRecord;
DWORD TUI::numberRead;
int TUI::color;
bool TUI::haveHappened;
int TUI::i;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// main.cpp
// test program
#include <stdio.h>
#include <windows.h>
#include "util.h"
#include "TUI.h"
#include "tui_old.h"

int main () {
    TUI::init();
    TUI::setCurPos(1,1);
    TUI::setColor(tui_black, tui_white);
    printf("TUI should be working");
    tui_setCurPos(2,2);
    tui_setColor(tui_byellow, tui_bblue);
    printf("tui_old is working");
    return 0;
}


Last edited on
I got an answer at MSDN's forum. All of the functions from windows.h have been copied from another website. I just arranged them into more intuitive functions. Since I copied and pasted the code around, I overlooked a detail.
In tui_old.h, the handle is acquired sometimes from STD_INPUT_HANDLE and other times from STD_OUTPUT_HANDLE. Then I made the class and replaced the calls to retrieve the handle by a handle attribute, which didn't made a distinction between input and output. All I had to do is create another handle and initialize them properly. As simple as that!
Last edited on
Topic archived. No new replies allowed.