Событие нажатия клавиши C++ cin

Я считаю, что это очень простой вопрос, но я не могу найти на него простого ответа. У меня есть бесконечный цикл, например. while(1), for(;;), и мне нужно выйти из цикла по нажатию клавиши. Как это сделать проще всего?

P.S.: я не могу использовать getch, cin.ignore или cin.get, потому что это останавливает цикл.


person Lukas Salich    schedule 16.08.2012    source источник
comment
Если вы расскажете нам больше о контексте, я почти уверен, что мы могли бы что-нибудь придумать. В противном случае вам нужно будет использовать некоторые специфичные для ОС вещи.   -  person Kiril Kirov    schedule 16.08.2012
comment
Какой-то линукс на сервере. Я не знаю, какой дистрибутив. Разве в std нет кроссплатформенного решения?   -  person Lukas Salich    schedule 16.08.2012


Ответы (4)


Что ж, вам нужен асинхронный ввод. Все методы, предоставляемые cin, ждут ввода. Для этого вам придется использовать системные функции или использовать библиотеку, которая сделает это за вас.

Что вам нужно сделать, так это не только обработать вашу логику в цикле while, но и прослушивать канал сообщений из вашей ОС. Если вам нужна дополнительная информация об этом, пожалуйста, оставьте комментарий.

РЕДАКТИРОВАТЬ: есть еще один способ, но я бы не рекомендовал его, так как я считаю, что он может быть непереносимым. Следующий код компилируется и запускается под VS2012RC.

#include<iostream>
#include<conio.h>

using namespace std;

int main()
{
   cout << "Enter a character";
   getch();
}
person Bartek Banachewicz    schedule 16.08.2012
comment
Вау, я думал, что такая простая вещь, как нажатие клавиши, будет реализована одинаково на всех платформах. Я понимаю, что cin это просто какой-то поток, но все же думаю, что будет кроссплатформенное решение. Я буду запускать его на сервере, где есть линукс, но я не знаю какой дистрибутив. Я также помню, когда давным-давно я попробовал что-то на Паскале в школе, было просто событие нажатия клавиши, поэтому я просто написал повтор до нажатия клавиши; так в С++ в то время как (?) {}? - person Lukas Salich; 16.08.2012
comment
Что ж, я считаю, что обработка сообщений в Linux довольно проста. Вам просто нужно запустить один или два вызова ОС, чтобы опросить сообщение, а затем запустить действие по умолчанию, если вы не хотите ничего делать. Существенное отличие состоит в том, что с потоками вы получаете char введенного символа, в то время как с помощью вызовов ОС вы получаете события Key Up/Down, вы можете использовать клавиши-модификаторы как обычные (shift, ctrl и т. д.) - person Bartek Banachewicz; 16.08.2012
comment
Что касается вопроса о Паскале, посмотрите на функцию conio.h/getch(). Он может называться по-разному в зависимости от используемого вами компилятора, но на самом деле он обычно предоставляется. (Это может быть getch, getchar или любой другой) - person Bartek Banachewicz; 16.08.2012
comment
Я даже не могу использовать conio.h в компиляторе. - person Lukas Salich; 16.08.2012
comment
Разве это не старый заголовок? Кстати, я использую почти новейший компилятор G++. - person Lukas Salich; 16.08.2012
comment
Я предупредил вас о проблемах с переносимостью. Вы должны будете сделать это должным образом. Предлагаю использовать готовую библиотеку. Google для простой библиотеки сообщений Linux или что-то в этом роде. - person Bartek Banachewicz; 17.08.2012
comment
conio.hms-dos, заголовок c, такой уродливый! - person Tacet; 23.11.2014

Ниже приведен код консоли Windows, который использует kbhit() и имеет бесконечный цикл. Но если нажать на клавиатуру, она разорвет цикл и выйдет. Если у вас есть <conio.h> , попробуйте следующее:

#include <iostream> 
#include <conio.h>

using namespace std;


int main()
{


   while (1)
   { 
     if (kbhit()) break;

   }

  return 0;
}
person Software_Designer    schedule 16.08.2012
comment
Так что я могу просто использовать в конце цикла: if(kbhit()) break;? - person Lukas Salich; 16.08.2012
comment
внутри цикла while добавьте if(kbhit()) break; - person Software_Designer; 16.08.2012
comment
Компилятор не может найти conio.h или просто conio. - person Lukas Salich; 16.08.2012

В С++ нет "клавиатуры". У вас есть только непрозрачный поток входных данных, который ваш терминал время от времени заполняет собственным вводом с клавиатуры. Это почти всегда буферизованный, редактируемый построчный ввод, поэтому у вас нет возможности узнать, когда была нажата та или иная клавиша.

Вам нужен специфичный для платформы метод для прямой связи с вашим терминалом на более низком уровне. Одной из таких библиотек, довольно широко распространенных и переносимых, является ncurses (существует совместимый вариант для Windows). Платформы переносимых графических приложений, такие как SDL и Allegro, также обеспечивают необработанную обработку клавиатуры.

person Kerrek SB    schedule 16.08.2012
comment
Omg, должно быть простое решение в std. Например, на каждой итерации цикла получайте данные из этого потока входных данных (cin?) и проверяйте, пуст ли он, но я не знаю, как это сделать... - person Lukas Salich; 16.08.2012
comment
Нет, стримы этого не допустят. Посмотрите на мой комментарий под моим ответом. - person Bartek Banachewicz; 16.08.2012
comment
@LukasSalich: Посмотрите на это так: если ваше приложение C++ будет получать каждое нажатие клавиши, оно будет ответственно за него. Ваша программа на C++ должна будет обрабатывать, например, редактирование строк, что, в свою очередь, потребует глубокого знания API терминала, чтобы вы могли, например. удалить символ нажатием backspace. Чтобы защитить среднее приложение/среду выполнения C++ от этого бремени, это не является частью стандарта. Однако есть много библиотек, которые делают это, например, conio, ncurses и т. д.; это означает, что вы можете выбрать любую библиотеку, лучше всего соответствующую вашим потребностям. Один из больших жирных плюсов C/C++. - person DevSolar; 16.08.2012

Это проверяет, нажата ли «стрелка влево» или нет:

GetKeyState(VK_LEFT)

И это ничего не ждет. Просто проверяет некоторые флаги.

Некоторые другие ключи, определенные в winuser.h:

#define VK_NUMPAD0        0x60
#define VK_NUMPAD1        0x61
#define VK_NUMPAD2        0x62
#define VK_NUMPAD3        0x63
#define VK_NUMPAD4        0x64
#define VK_NUMPAD5        0x65
#define VK_NUMPAD6        0x66
#define VK_NUMPAD7        0x67
#define VK_NUMPAD8        0x68
#define VK_NUMPAD9        0x69

#define VK_CLEAR          0x0C
#define VK_RETURN         0x0D

#define VK_SHIFT          0x10
#define VK_CONTROL        0x11
#define VK_MENU           0x12
#define VK_PAUSE          0x13
#define VK_CAPITAL        0x14

#define VK_KANA           0x15
#define VK_HANGEUL        0x15  /* old name - should be here for compatibility */
#define VK_HANGUL         0x15
#define VK_JUNJA          0x17
#define VK_FINAL          0x18
#define VK_HANJA          0x19
#define VK_KANJI          0x19

#define VK_ESCAPE         0x1B

#define VK_CONVERT        0x1C
#define VK_NONCONVERT     0x1D
#define VK_ACCEPT         0x1E
#define VK_MODECHANGE     0x1F

#define VK_SPACE          0x20
#define VK_PRIOR          0x21
#define VK_NEXT           0x22
#define VK_END            0x23
#define VK_HOME           0x24
#define VK_LEFT           0x25
#define VK_UP             0x26
#define VK_RIGHT          0x27
#define VK_DOWN           0x28
#define VK_SELECT         0x29
#define VK_PRINT          0x2A
#define VK_EXECUTE        0x2B
#define VK_SNAPSHOT       0x2C
#define VK_INSERT         0x2D
#define VK_DELETE         0x2E
#define VK_HELP           0x2F

winuser.h должен быть включен в windows.h

person huseyin tugrul buyukisik    schedule 16.08.2012
comment
Это только для Windows. Он не кроссплатформенный (в вопросе об этом не написано, но читая комментарии, вы поймете, что вопрос для чего-то стандартного. - person Kiril Kirov; 16.08.2012
comment
Извините, я не читал комментарии, пока строил ответ ^^ - person huseyin tugrul buyukisik; 16.08.2012