Search code examples
c++asciiarrow-keysgetch

getch() and mixing regular keys with arrow keys


I can't get the text to display on console and neither is it saved properly. I got the arrow keys, enter,backspace and escpe working though.

also another /small/ error I don't really get is when I press esc and it exits from the void I get directed to this piece of code

#endif  /* defined (_M_IX86) || defined (_M_X64) */
        __fastfail(FAST_FAIL_STACK_COOKIE_CHECK_FAILURE);

inside of gc_report.c, which I don't find nuch infor,ation about (or atleast related to my problem).

#define KEY_UP 72
#define KEY_DOWN 80
#define KEY_LEFT 75
#define KEY_RIGHT 77
#define KEY_ENTER 13
#define KEY_BACKSPACE 8
#define KEY_ESCAPE 27

void texteditor(int x, int y,int kolommen,char textarr[20][20],int rijen=20)
{
    int index = 0, indey = 0, keuze,lol = 20;
    do{
        gotoxy(index + x, indey + y); 
        keuze = 0;
        keuze = _getch();
        if (keuze == 0 || keuze == 0xE0 || keuze == 224)
        {
            keuze = _getch();
            gotoxy(index + x, indey + y);
            switch (keuze)
            {
            case KEY_UP:indey--;
                break;
            case KEY_LEFT: index--;
                break;
            case KEY_DOWN:indey++;
                break;
            case KEY_RIGHT: index++;
                break;
            }
            indey = (indey <= 0) ? 0 : (indey > kolommen) ? kolommen : indey;
            index = (index <= 0) ? 0 : (index > rijen) ? rijen : index;
        }
            if (keuze == 32 || (keuze >= 46 && keuze <= 57) || (keuze <= 64 && keuze >= 126))
            {
                textarr[index][indey] = (char)keuze;
                std::cout << textarr[index][indey];
                index++;
                index = (index <= 0) ? 0 : (index > rijen) ? rijen : index;
            }
            if (keuze == KEY_BACKSPACE)
            {
                index = index--;
                gotoxy(index + x, indey + y);
                std::cout << " ";
                index = (index <= 0) ? 0 : (index > rijen) ? rijen : index;
            }
            if (keuze == KEY_ENTER)
            {
                index = 0;
                indey++;
                indey =(indey >= kolommen) ? kolommen : indey++;
            }       
    } while (keuze != KEY_ESCAPE);}

I also searched a bit on the values behind the arrow keys, in which I found 37(left arrow),38(up arrow),39(right arrow),40(down arrow) as ASCII value, then what's the difference from mine?


Solution

  • The ASCII charset, as the name implies, describes a character set and not the keys on the keyboard. For that reason there are no values for arrow keys in ASCII.

    Instead the _getch() function you are using is returning either 224 (E0h) or 0 to indicate that what's following is a key scan code. The values you are using for these are correct and you can look them up here.

    The other values you found (37-40) are called virtual keys and are much more common. e.g they are returned in Javascript for event.keyCodeand also available in the WinApi but they are not applicable to your _getch() example.

    Now that this is sorted out, let's look at your example:

    • You can remove the E0 as it equals 224.
    • The textarr array you are using, has the dimensions 20x20. That means writing beyond textarr[19][19] is undefined behaviour. You are comparing the array index for being bigger than 20 before you use rijen as substitute index. You should instead have rijen be 19. That way you don't have the out of bound access.
    • I would place kolommen next to rijen. It makes no sense to have the array between them + it hinders you from setting a default value for it.
    • You are also ignoring a lot of printable characters. You should structure your code to have an else condition at the end, where you then check with isprint() whether it's printable and then print it.
    • And now the main part: if (... || (keuze <= 64 && keuze >= 126)). Do you see the problem? I guess you meant (keuze >= 64 && keuze <= 126). The way it's now you are ignoring all the ASCII letters.
    • Maybe you would like to clear screen before starting running texteditor(). system("cls") is the standard Windows way of doing this.

    Another thing, nesting ternary expressions is ugly. The unneeded parenthesis you used for the condition would be much better around the second ternary expression. Also the windows console defaults to 80x25, which you might want to use instead of 20x20.

    And finally, conio.h is a non-standard header and you'd be better off using the functionality present in <windows.h> instead. Or get away from the suboptimal terminal handling in Windows altogether and use a library like ncurses together with a proper terminal.