0

I'm new to C programming. Just for fun, I started by trying to create a small game where the player is represented by a letter that can be moved around in the console window.

One of the first obstacles I encountered was that there's no standard way of reading characters from the keyboard in C without waiting for the user to hit the Enter key.

Of course, there's the Getch() function in the conio.h header file, but I'd rather use the Windows API since I'll be working under that OS anyway. After googling, I found that GetKeyState would be the best function for this application (since it's a console app I can't use WM_KEYDOWN, right?).

This is what I have so far:

#include <stdio.h>
#include <windows.h>

#define BITS sizeof(short) * 8

const short MSB = 1 << (BITS - 1);

char get_char(void);

int main(void)
{
    char c;

    while (1)
    {
        if (c = get_char()) printf("|%d|%c|\n", c, c);
    }
    return 0;
}

char get_char(void)
{
    int i = 0;

    while (i++ < 256)    // All keys on the keyboard
    {
        if (GetKeyState(i) & MSB)
        {
            while (1)    // Waits until the pressed key goes up again
            {
                if (!(GetKeyState(i) & MSB)) return i;
            }
        }
    }
    return 0;
}

The problem I get with this is that the get_char() function doesn't return the correct character. For example, when I press 'a' on the keyboard printf displays 'A'.

I understand that GetKeyState works with Virtual Keys (not ASCII), but is there a way to make the get_char() function to return two values, one VK and one ASCII-value?

Jens M.
  • 43
  • 3
  • Note: `conio.h` is not actually a standard C header either; it's exclusive to DOS and Windows. – Govind Parmar Nov 09 '18 at 14:54
  • You're going to have to read the [documentation](https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getkeystate) more carefully: *"The key status returned from this function changes as a thread reads key messages from its message queue. The status does not reflect the interrupt-level state associated with the hardware."* You aren't reading messages from the message queue, hence the state is not updated. The advice here is: If you want to continue to have fun learning, just use `_getch()` and move on to something more interesting. – IInspectable Nov 09 '18 at 14:57
  • You should take a look into this: https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-toascii – movcmpret Nov 09 '18 at 15:11
  • 1
    Besides not working, your implementation also has another undesirable property: It burns an entire core by constantly polling. Windows is best programmed using an event-driven model. Consider using [ReadConsoleInput](https://learn.microsoft.com/en-us/windows/console/readconsoleinput) instead. – IInspectable Nov 09 '18 at 15:13
  • Feel free to use this: https://stackoverflow.com/a/9783195/584518 – Lundin Nov 09 '18 at 15:15
  • Maybe you should use the Windows Console API (see https://learn.microsoft.com/en-us/windows/console/using-the-console). – Stuart Nov 12 '18 at 02:53
  • @movcmpret: Thanks, I think that is what I was looking for. – Jens M. Nov 26 '18 at 09:53
  • @IInspectable: Thanks for the input. I guess I'd better study the WinAPI more. – Jens M. Nov 26 '18 at 09:55

1 Answers1

1

You also need to check the Key "CapsLock", Add the condition below: if (GetKeyState(VK_CAPITAL) & (~MSB));//To Check if CapsLock on Here is the code:

#include <windows.h>
#include <iostream>
#define BITS sizeof(short) * 8

const short MSB = 1 << (BITS- 1);
int Case = 'a' - 'A';
char get_char(void);

int main(void)
{
    char c;

    while (1)
    {
        if (c = get_char()) 
            printf("|%d|%c|\n", c, c);
    }
    return 0;
}

char get_char(void)
{
    int i = 0;
    int ret = 0;
    while (i++ < 256)    // All keys on the keyboard
    {
        if (ret = (GetKeyState(i) & MSB))
        {
            while (1)    // Waits until the pressed key goes up again
            {
                if (!(GetKeyState(i) & MSB))
                {
                    if (i >= 'A' && i <= 'Z') 
                    {
                        if (GetKeyState(VK_CAPITAL) & (~MSB))
                            return i;
                        else
                            return i + Case;
                    }
                    return i;
                }
            }
        }
    }
    return 0;
}
Drake Wu
  • 6,927
  • 1
  • 7
  • 30