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


场景:

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






你可能感兴趣的:(C++,linux,控制台,不输入回车,响应按键)