您的位置:首页 > 运维架构 > Linux

[C/C++]_[Linux,Windows,MacOSX控制台即时响应按键消息]

2014-04-22 13:48 387 查看
场景:

1. 在做多线程单元测试时难免需要在控制台打印数据,如果是实时输出的话,通过getc方式还需要输入一个回车键,不能及时响应,还有就是屏幕刷屏时可能都看不清自己敲了什么字母. 关键代码PressAnyKey是参考cplusplus的。

参考: http://www.cplusplus.com/forum/articles/7312/
Linux,Unix,MacOSX

#include <stdio.h>
#include <assert.h>
#include <string>
#include "gtest/gtest.h"
#include "gtest/internal/gtest-filepath.h"
#include "gtest/internal/gtest-port.h"
#include <pthread.h>

#include <unistd.h>
#include <termios.h>

//http://www.cplusplus.com/forum/articles/7312/
int PressAnyKey( const char* prompt )
{
#define MAGIC_MAX_CHARS 18
struct termios initial_settings;
struct termios settings;
unsigned char  keycodes[ MAGIC_MAX_CHARS ];
int            count;

tcgetattr( STDIN_FILENO, &initial_settings );
settings = initial_settings;

/* Set the console mode to no-echo, raw input. */
/* The exact meaning of all this jazz will be discussed later. */
settings.c_cc[ VTIME ] = 1;
settings.c_cc[ VMIN  ] = MAGIC_MAX_CHARS;
settings.c_iflag &= ~(IXOFF);
settings.c_lflag &= ~(ECHO | ICANON);
tcsetattr( STDIN_FILENO, TCSANOW, &settings );

printf( "%s", prompt ? prompt : "Press a key to continue..." );
int fo = fileno(stdin);
count = read( fo, (void*)keycodes, MAGIC_MAX_CHARS );

tcsetattr( STDIN_FILENO, TCSANOW, &initial_settings );

return (count == 1)
? keycodes[ 0 ]
: -(int)(keycodes[ count -1 ]);
}

void * StartPthread(void * arg)
{
static int i = 0;
while(true)
{
GTEST_LOG_(INFO) << "StartPthread: " << i++ ;
sleep(2);
}
}

int main(int argc, char const *argv[])
{
#if 1
pthread_t t1;
pthread_create(&t1, NULL, StartPthread, NULL);
pthread_detach(t1);

while(true)
{
int c = PressAnyKey("Press any key to continue.");
GTEST_LOG_(INFO) << "c: " << c ;
if(c == 'q')
{
break;
}
}
#endif
return 0;
}


Windows:

/* ---------------------------------------------------------------------------
* PressAnyKey()
* ---------------------------------------------------------------------------
* Copyright 2008 Michael Thomas Greer
* http://www.boost.org/LICENSE_1_0.txt *
* function
*   Optionally print a message and and wait for the user to press (and
*   release) a single key.
*
* arguments
*   The message to print. If NULL, uses a default message. Specify the empty
*   string "" to not print anything.
*
* returns
*   The virtual keycode for the key that was pressed.
*
*   Windows #defines virtual keycode values like
*     VK_UP
*     VK_DOWN
*     VK_RIGHT
*     VK_LEFT
*   which you can use to identify special keys.
*
*   Letter keys are simply the upper-case ASCII value for that letter.
*/
#include <windows.h>
#include <iostream>

using namespace std;

int PressAnyKey( const char *prompt )
{
DWORD        mode;
HANDLE       hstdin;
INPUT_RECORD inrec;
DWORD        count;
char         default_prompt[] = "Press a key to continue...";

/* Set the console mode to no-echo, raw input, */
/* and no window or mouse events.              */
hstdin = GetStdHandle( STD_INPUT_HANDLE );
if (hstdin == INVALID_HANDLE_VALUE
|| !GetConsoleMode( hstdin, &mode )
|| !SetConsoleMode( hstdin, 0 ))
return 0;

if (!prompt) prompt = default_prompt;

/* Instruct the user */
WriteConsole(
GetStdHandle( STD_OUTPUT_HANDLE ),
prompt,
lstrlen( prompt ),
&count,
NULL
);

FlushConsoleInputBuffer( hstdin );

/* Get a single key RELEASE */
do ReadConsoleInput( hstdin, &inrec, 1, &count );
while ((inrec.EventType != KEY_EVENT) || inrec.Event.KeyEvent.bKeyDown);

/* Restore the original console mode */
SetConsoleMode( hstdin, mode );

return inrec.Event.KeyEvent.wVirtualKeyCode;
}

int main(int argc, char const *argv[])
{
int keyCode = PressAnyKey(NULL);
cout << "keyCode: " << (char)keyCode << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: