Нужна помощь в создании моей собственной функции getch() на C с использованием Windows API в консольном приложении.

Я новичок в программировании на C. Ради интереса я начал с попытки создать небольшую игру, в которой игрок представлен буквой, которую можно перемещать в окне консоли.

Одним из первых препятствий, с которыми я столкнулся, было отсутствие стандартного способа чтения символов с клавиатуры в C без ожидания нажатия пользователем клавиши Enter.

Конечно, в заголовочном файле conio.h есть функция Getch(), но я бы предпочел использовать Windows API, так как все равно буду работать под этой ОС. Погуглив, я обнаружил, что GetKeyState будет лучшей функцией для этого приложения (поскольку это консольное приложение, я не могу использовать WM_KEYDOWN, верно?).

Это то, что у меня есть до сих пор:

#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;
}

Проблема, с которой я сталкиваюсь, заключается в том, что функция get_char() не возвращает правильный символ. Например, когда я нажимаю «а» на клавиатуре, printf отображает «А».

Я понимаю, что GetKeyState работает с виртуальными ключами (не ASCII), но есть ли способ заставить функцию get_char() возвращать два значения, одно VK и одно ASCII-значение?


person Jens M.    schedule 09.11.2018    source источник
comment
Примечание: conio.h на самом деле также не является стандартным заголовком C; это эксклюзивно для DOS и Windows.   -  person Govind Parmar    schedule 09.11.2018
comment
Вам необходимо прочитать документацию. более внимательно: статус ключа, возвращаемый этой функцией, изменяется по мере того, как поток считывает ключевые сообщения из своей очереди сообщений. Состояние не отражает состояние уровня прерывания, связанного с оборудованием. Вы не читаете сообщения из очереди сообщений, поэтому состояние не обновляется. Совет здесь таков: если вы хотите продолжать получать удовольствие от обучения, просто используйте _getch() и переходите к чему-то более интересному.   -  person IInspectable    schedule 09.11.2018
comment
Вам следует ознакомиться с этим: docs. microsoft.com/en-us/windows/desktop/api/winuser/   -  person movcmpret    schedule 09.11.2018
comment
Помимо того, что ваша реализация не работает, она также имеет еще одно нежелательное свойство: она сжигает все ядро ​​из-за постоянного опроса. Windows лучше всего программировать, используя модель, управляемую событиями. Вместо этого рассмотрите возможность использования ReadConsoleInput.   -  person IInspectable    schedule 09.11.2018
comment
Не стесняйтесь использовать это: stackoverflow.com/a/9783195/584518   -  person Lundin    schedule 09.11.2018
comment
Возможно, вам следует использовать API консоли Windows (см. docs.microsoft. com/en-us/windows/console/using-the-console).   -  person Stuart    schedule 12.11.2018
comment
@movcmpret: Спасибо, думаю, это то, что я искал.   -  person Jens M.    schedule 26.11.2018
comment
@IInspectable: Спасибо за вклад. Думаю, мне лучше больше изучать WinAPI.   -  person Jens M.    schedule 26.11.2018


Ответы (1)


Вам также необходимо проверить ключ "CapsLock", добавьте условие ниже: if (GetKeyState(VK_CAPITAL) & (~MSB));//Чтобы проверить, включен ли CapsLock Вот код:

#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;
}
person Drake Wu    schedule 12.11.2018