如何在控制台应用程序中使用GetMessage()在Windows API中识别C ++中的键盘input?

首先是大图:我试图通过Windows 7(64位)上的控制台程序来同步两个外部设备。 也就是说,设备1应该触发设备2.(为了好奇,设备1是NI USB-6525,我正在使用它的变化检测function。)

我在while循环中使用GetMessage()来等待由设备1触发的消息。(因为我没有为该硬件编写软件,所以我不能改变我必须阅读此消息的事实。 )一旦这个消息被读取,它就被分派 。 此调度将导致对使用设备2执行测量的函数进行callback,并将measurementComplete设置为true 。 一旦callback返回,循环结束。 然后我执行清理,应用程序退出。

问题在于,用户也应该能够在等待消息时中止,例如通过按下一个键。 我试图实现一个检查,看看收到的消息是来自另一个线程或键盘,但它永远不会识别键盘input:

 #include <cstdio> #include <windows.h> using namespace std; bool measurementComplete = false; BOOL bRet = 0; MSG threadMessage; signed long __cdecl callbackFunction(type1 param1, type2 param2) // (pseudo args) { measurementComplete = 1; performMeasurement(); return 0; } int main (int argc, char* argv[]) { /* Load libraries, set up hardware, call NI function that looks for signal from Device 1 in separate thread and sends a Windows message upon signal detection */ while (!measurementComplete) { // measurement has not yet been performed // wait for message puts("Waiting for message."); if ((bRet = GetMessage(&threadMessage, NULL, 0, 0)) != 0) { // if message available if (bRet == -1) { puts("Error: GetMessage() returned -1. The program will now exit."); break; } else { DispatchMessage(&threadMessage); if ((TranslateMessage(&threadMessage)) != 0) // if character message (indicates key press) break; } } puts("Message handled."); } /* perform cleanup */ return 0; } 

我是新来的Windows API,所以我不熟悉它。 我在Code :: Blocks 13.12 IDE中编程并使用GCC。 我没有MFC或任何类似Microsoft的支付产品,所以我不能使用MFC函数或类。 不幸的是,我发现许多类似的问题的答案包括MFC的function。

从我对这个问题的研究来看,似乎键盘消息可能没有窗口可去。 我试图创build一个只有消息的窗口,如这里所描述的,但我总是得到Error 18: There are no more files调用CreateWindowEx()时Error 18: There are no more files 。 如果需要,我可以提供该代码,但我甚至不确定是否真的需要创build一个窗口。 当我运行FindWindowEx(HWND_MESSAGE, NULL, NULL, NULL); ,我可以看到这个窗口已经存在了。 我不知道该函数发现的窗口是否是由我的二进制程序自动创build的窗口,还是由我的计算机上运行的另一个程序创build的消息窗口。 另外,我不是已经有一个窗口(控制台窗口)?

有没有人有任何提示如何将键盘input到控制台应用程序中的消息系统? 任何帮助将不胜感激。

Solutions Collecting From Web of "如何在控制台应用程序中使用GetMessage()在Windows API中识别C ++中的键盘input?"

事实上,“控制台应用程序”没有“窗口”,因此他们无法收到任何消息(以简单的方式)。

如果我没有记错的话,你实际上可以编写代码来创建一个带有消息泵的不可见窗口,这样所有的消息都会被发送出去。 *)

但是,接下来,你有很多与窗口相关的代码来研究,编写和维护。 开始使用“Windows应用程序”并在启动时隐藏窗口要容易得多。 您将从项目代码模板中免费获得所有的messagepump代码。 如果你喜欢那种UI风格的话,你也可以分配窗口并打开一个控制台窗口。

*)您可以启动一个新的窗口应用程序项目,并在里面窥视窗口是如何注册一个处理消息的“wndproc”例程。 在你的main()代码的某个时候,你将需要执行与'windowed'项目执行相同的操作。 此外,请记住,您将需要实际进入调度循环,这阻止你的线程,直到dispatchloop关闭(与PostQuitMessage等) – 通常当应用程序获得关闭“信号”(注意,通常这是你的代码已经听取和响应这个“信号”,当你决定退出时你必须调用PostQuitMessage )。

你不能逃避,这里没有魔法! 有东西必须听消息。 如果你想让消息通过并且也有一些平行的工作,你将需要:

  • 两个线程,一个用于消息泵,一个用于工作,所有的同步操作都在它们之间安全地进行通信
  • 或者只有一个线程运行消息泵,然后REWRITE THE JOB通过消息与消息通知异步,所以任何notifs /回调也都由消息循环处理

选择你不喜欢的东西:)

以下是从MSDN站点取得的正常消息循环:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms644928%28v=vs.85%29.aspx

 while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0) { if (bRet == -1) { // handle the error and possibly exit } else { TranslateMessage(&msg); DispatchMessage(&msg); } } 

忽略BOOL在这里使用的值不是true和false的可怕事实,并且注意GetMessage()的返回是消息循环何时退出的最外层控制。 这对于Win32来说很自然。 把其他东西(比如测试是否已经被采取的测试)打乱了这个简单的模式。

注意:正如前面所讨论的,让DispatchMessage()实现引发一个将启动应用程序退出的消息是可以接受的(也是期望的)。 (通过在主线程上发布PostQuitMessage()

最后:在Win32应用程序中没有过滤器的情况下,您肯定会从GetMessage()获取大量的键盘消息。 不是说TranslateMessage()和/或DispatchMessage()默认实现可能不会将你隐藏起来。

立即检测信号消息是我同步的关键

似乎这将是从任何接近实时立场的dicey,因为那些显然是你的唯一接口的窗口消息, 排队与系统上的任何和所有的GUI消息

基本上,时机是艰难的: 如何使线程睡眠不到一毫秒在Windows上