Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> отработать событие клавиатуры, mingw gcc 
:(
    Опции темы
comcon1
Дата 3.7.2008, 10:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: 12
Всего: 17



Здравствуйте. Никогда не сталкивался ранее с подобной проблемой для консольного приложения. Нужно отработать в потоке нажатие клавиши, потоки у меня boost::thread. Желательно кросс-платформенно отработать событие, но если такого варианта нет, тогда можно под винду.

Спасибо.


--------------------
PM MAIL   Вверх
SABROG
Дата 3.7.2008, 11:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 4
Всего: 91



fgetc(stdin) ? Или нужны сканкоды ?


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
comcon1
Дата 3.7.2008, 16:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: 12
Всего: 17



вот этот код:
Код

    printf("Press any key:  ");
    boost::thread thrd1(&modify_random);
    thrd1.join(); 
    for(;;) {
          c = fgetc(stdin);
          cout << entropy << flush;
    }

не отрабатывает событие.
Что-то не так или fgetc как раз таки использовать нельзя...


--------------------
PM MAIL   Вверх
JackYF
Дата 3.7.2008, 17:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


полуавантюрист
****


Профиль
Группа: Участник
Сообщений: 5814
Регистрация: 28.8.2004
Где: страна тысячи озё р

Репутация: 18
Всего: 162



Цитата(comcon1 @  3.7.2008,  09:29 Найти цитируемый пост)
нажатие клавиши

Нажатие клавиши или ввод символа?


--------------------
Пожаловаться на меня как модератора можно здесь.
PM MAIL Jabber   Вверх
comcon1
Дата 3.7.2008, 17:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: 12
Всего: 17



именно нажатие.


--------------------
PM MAIL   Вверх
comcon1
Дата 4.7.2008, 16:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: 12
Всего: 17



Для винды решил следующим образом.
Код

int main(int argc, char *argv[])
{
  printf("Press any key:  ");
 // вот если две нижние строчки закоменитить, работает на отличненька!
  boost::thread thrd1(&modify_random);
  thrd1.join();
  hin = GetStdHandle(STD_INPUT_HANDLE);
  for (;;num++) {
     if (!ReadConsoleInput(hin, &ir, 2, &tmp)) {
     cout << entropy << flush; 
   } else { 
          cerr << "ERROR: " << GetLastError() << endl; 
   }
  }    
//    boost::thread thrd0(&modify_entropy);
//    thrd0.join();
    return EXIT_SUCCESS;
}


Но когда хотя бы один поток запущен - сразу перестаёт работать. Не знаете, в чем дело? Запихать отработку события в поток тоже не помогает.

Это сообщение отредактировал(а) comcon1 - 4.7.2008, 16:36


--------------------
PM MAIL   Вверх
Partizan
Дата 4.7.2008, 17:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Let's do some .NET
****


Профиль
Группа: Модератор
Сообщений: 2828
Регистрация: 19.12.2005
Где: Санкт-Петербург

Репутация: 4
Всего: 67



comcon1, читайте в MSDN про AttachThreadInput 


--------------------
СУВ,
       Partizan.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
pan2004
Дата 5.7.2008, 19:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 357
Регистрация: 28.7.2007

Репутация: 1
Всего: 9



Код

...
 // вот если две нижние строчки закоменитить, работает на отличненька!
  boost::thread thrd1(&modify_random);
  thrd1.join(); //Здесь ты АБСОЛЮТНО ПОЛНОСТЬЮ уверен? join() ЖДЕТ окончания работы потока, ОСТАНАВЛИВАЯ текущий. фактически, можно вместо этих двух строк написать просто
  modify_random(); //Эффект тот же, но без дополнительного потока
...


Добавлено через 8 минут и 9 секунд
Цитата(comcon1 @  4.7.2008,  16:36 Найти цитируемый пост)
Но когда хотя бы один поток запущен - сразу перестаёт работать. Не знаете, в чем дело? Запихать отработку события в поток тоже не помогает.

Не работает, потому что когда до твоего цикла с ReadConsoleInput доходит управление(и если), поток уже завершил свою работу. 
Помести thread.join() в конец программы, где ему и место.


--------------------
Qt4/C++ fan
WinXP SP3: MSVC++2005 Qt4.5.1 Boost1.39
сыграем в дурака?
PM MAIL   Вверх
pan2004
Дата 5.7.2008, 21:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 357
Регистрация: 28.7.2007

Репутация: 1
Всего: 9



Кусок из моей программы:
Этот код делает примерно то же самое, что желает comcon1, только второй поток в моем случае не обрабатывает событие, а ждет ввода пользователя, который затем направляется в основной поток. Кроме того, здесь ожидается ввод строки, а не нажатие клавиши, но это несущественное отличие.
Код
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
...
//Функция, ждущая ввода пользователя
void gettingCommand(wstring* command)
{
    wchar_t buffer[250]; // I think it's enough
    wcin.getline(buffer, 250);
    *command = buffer;
}
...
int main()
{
    ...
    //Ожидание ввода пользователя
    wstring command;
    // Создаем поток, который начинает сразу работать
    boost::thread* inputThread = new boost::thread(boost::bind (&gettingCommand, &command));
    // Create a "null" time duration object.
    const boost::posix_time::time_duration nullTime = boost::posix_time::millisec(0);
    while(true) // Основной цикл
    {
        // boost::thread не имеет функции проверки, завершился ли поток,
        // но это дурацкий способ все таки узнать это, не застревая в ожидании
        if (inputThread->timed_join(nullTime))
        {
            delete inputThread;
            inputThread = 0;
            ...//Обрабатываем то что мы имеем в command, если надо, запускаем поток снова
            inputThread = new boost::thread(boost::bind (&gettingCommand, &command));
        }
        ... //Выполняем остальные действия
        boost::this_thread::sleep(boost::posix_time::millisec(20)); //Sleep()? Она самая :)
    }
    ...
    if (inputThread) inputThread->join(); // Вот где нужна эта функция
    return 0;
}



--------------------
Qt4/C++ fan
WinXP SP3: MSVC++2005 Qt4.5.1 Boost1.39
сыграем в дурака?
PM MAIL   Вверх
pan2004
Дата 5.7.2008, 22:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 357
Регистрация: 28.7.2007

Репутация: 1
Всего: 9



В файле conio.h есть функция kbhit() , которая должна проверять нажатую клавишу. Кроме того, не блокирует работу программы - нет нажатой клавиши, просто возвращает 0, так что можно обойтись без дополнительных потоков. Встретил такой кусок в одной проге:
Код

        if (kbhit())
        {
            key = getch();

            switch (key)
            {
                ...
            }
        }

Функция есть по крайней мере в gcc, компиляторах от Борланда и Микрософт.


--------------------
Qt4/C++ fan
WinXP SP3: MSVC++2005 Qt4.5.1 Boost1.39
сыграем в дурака?
PM MAIL   Вверх
bsa
Дата 6.7.2008, 12:20 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Цитата(pan2004 @ 5.7.2008,  22:11)
Функция есть по крайней мере в gcc, компиляторах от Борланда и Микрософт.

Ты сильно заблуждаешься. Во-первых, в компиляторе вообще функций нет, они есть в библиотеках. Во-вторых, в стандарт не входит ни conio.h, ни kbhit(). В-третьих, под GNU/Linux, например, ничего похожего на kbhit в стандартной библиотеке нет.
PM   Вверх
pan2004
Дата 6.7.2008, 14:10 (ссылка)  | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 357
Регистрация: 28.7.2007

Репутация: 1
Всего: 9



Цитата(bsa @  6.7.2008,  12:20 Найти цитируемый пост)
Ты сильно заблуждаешься. Во-первых, в компиляторе вообще функций нет, они есть в библиотеках.

Придираемся к словам, да? smile Сам понимаешь, что я имел в виду
Цитата

Во-вторых, в стандарт не входит ни conio.h, ни kbhit(). В-третьих, под GNU/Linux, например, ничего похожего на kbhit в стандартной библиотеке нет.

Ну тут я действительно несколько ошибся - посмотрел, что в MinGW такая функция (kbhit) есть. Есть она, судя по этому и в двух остальных компиляторах. То, что дела с conio.h в gcc(в общем) обстоят несколько иначе, чем в MinGW, я предположить не смог

PS Вот эмуляция kbhit и еще некоторых функций под линух, рабочая или нет, сказать не могу:
Код
#if !defined(WINCOMPAT_INCLUDED) && !defined(PLATFORM_WINDOWS) && !defined(WIN32) && !defined(WINDOWS) && !defined(__WIN32__)
#define WINCOMPAT_INCLUDED

/**
 * 
 * Author: Magnus Naeslund ([email protected], [email protected])
 * (c) 2000 Magnus Naeslund, all rights reserved
 * 
 */

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef TRUE
  #define TRUE 1
#endif
#ifndef FALSE
  #define FALSE 0
#endif

#define _kbhit kbhit
#define _getch getch
#define stricmp strcasecmp
#define strnicmp strncasecmp

#define Sleep(x) usleep((x)*1000)

static int    inited=0;
static struct termios ori;

static void tcatexit(){
   tcsetattr(0,TCSANOW,&ori);
}

static void init_terminal(){
   struct termios t;
   tcgetattr(0,&t);
   tcgetattr(0,&ori);
   t.c_lflag &= ~(ICANON);
   t.c_lflag &= ~(ECHO);
   tcsetattr(0,TCSANOW,&t);
   atexit(tcatexit);
}

static inline int kbhit(){
  fd_set rfds;
  struct timeval tv;

   if (!inited){
      inited=1;
      init_terminal();
   }
   
   FD_ZERO(&rfds);
   FD_SET(0, &rfds);
   tv.tv_sec = 0;
   tv.tv_usec = 10*1000;
   return select(1, &rfds, NULL, NULL, &tv)>0;
}

static inline int getch(){
   fd_set rfds;
   
   if (!inited){
      inited=1;
      init_terminal();
   }
   
   FD_ZERO(&rfds);
   FD_SET(0, &rfds);
   if (select(1, &rfds, NULL, NULL, NULL)>0)
     return getchar();
   else{
      printf("wincompat.h: select() on fd 0 failed\n");
      return 0xDeadBeef;
   }     
}

#endif


Это сообщение отредактировал(а) pan2004 - 6.7.2008, 14:21


--------------------
Qt4/C++ fan
WinXP SP3: MSVC++2005 Qt4.5.1 Boost1.39
сыграем в дурака?
PM MAIL   Вверх
JackYF
Дата 6.7.2008, 18:07 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


полуавантюрист
****


Профиль
Группа: Участник
Сообщений: 5814
Регистрация: 28.8.2004
Где: страна тысячи озё р

Репутация: 18
Всего: 162



Цитата(pan2004 @  6.7.2008,  13:10 Найти цитируемый пост)
conio.h

Нет ни в одном стандарте. Есть функции для работы с консолью в WinAPI и ncurses/slang под Unix-like-системы.


--------------------
Пожаловаться на меня как модератора можно здесь.
PM MAIL Jabber   Вверх
comcon1
Дата 7.7.2008, 10:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: 12
Всего: 17



всем большое спасибо. Сделал пока чисто в API-вызовах, буст выкинул нах.

Код

DWORD WINAPI catch_event( LPVOID lpParam )
{
  HANDLE hin = GetStdHandle(STD_INPUT_HANDLE);
  printf("Event thread joined: %d\n", GetCurrentThreadId());
  printf("Press any key: _  ");
  for (;;) {
    ReadConsoleInput(hin, &ir, 128, &tmp);
/*    printf("--%d--", ir.EventType);*/
    if (ir.EventType == KEY_EVENT) {
        sum += entropy;
        num++;
       printf("\b\b%2d", entropy);
        if (ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) {
           printf("\n\nYour result. Num: %10d; Aver: %10.6f\n",num, sum/num);
           printf(    "RNG stats.   Num: %10d; Aver: %10.6f\n",numv, sumv/numv);
           system("PAUSE");
           exit(0); 
        }
    }
    // flush console..
  }
}

DWORD WINAPI modify_random( LPVOID lpParam ) 
{
  printf("Calculus thread joined: %d\n", GetCurrentThreadId());      
  for (;;) {
      entropy = die();
      numv++;
      sumv += entropy;
  }
}

int main(int argc, char *argv[])
{
  DWORD curTid = GetCurrentThreadId();
  hThread[0] = CreateThread(NULL, 0, modify_random, NULL, 0, &threadId[0]);
  hThread[1] = CreateThread(NULL, 0, catch_event, NULL, 0, &threadId[1]);
  AttachThreadInput(curTid, threadId[1], TRUE);
  WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
  return EXIT_SUCCESS;
}


Остался вопрос иного рода: у меня почему-то периодически одно нажатие клавиши срабатывает 2 раза...


--------------------
PM MAIL   Вверх
comcon1
Дата 7.7.2008, 12:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: 12
Всего: 17



Ладно, всем спасибо. Решил пока проблему вставкой Sleep(100) после считывания события, но это костыль, поэтому тему закрывать не буду.


--------------------
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0610 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.