Win32APIのGetAsyncKeyStateを使ってキー判定プログラムを作りたいと思っています。
#include <stdio.h>
#include <windows.h>
int main( void )
{
printf("roop in\n");
while(1){
if( GetAsyncKeyState(VK_RETURN))
break;
Sleep(500);
}
printf("roop out\n");
return 0;
}
このようなプログラムを作りました。
こちらの予想としては、リターンキーを押したらプログラムループがとまると思っていたのですが、実際にはループがとまりません。
どうしたらリターンキーが押されたかどうか判定できるでしょうか?
どなたか教えてください。
getchar()を使ったり、kbhit()等を使った方法ではなく、GetAsyncKeyStateまたは、それに類する関数を使った解決方法を教えて頂けないでしょうか?
よろしくお願いします。
Win32ConsoleApplicationでワークスペース作ってKSSPさんの書かれているものをそのまま実行したんですけど、リターンキーを押すことでループから抜けましたよ。
何が違うんでしょう・・・
環境:VC++6(SP5)、Windows2000
Windows98SEでKSSPさんのソースを実行してみました。
鈴木さんと同じ方法です。(VC++6(SP5)で)
いろいろ試行錯誤してみましたが…
正しく動作しませんね。
Win9X系のコンソールではGetAsyncKeyStateAPIは正しく動作しないのかも知れません。
KSSPさん、GetKeyboardState関数はどうなのでしょうか?
メッセージキューを介すのでよっぽどのことがないかぎり動作をすると思うのですが。
自分のWin2000でKSSPさんのソースで実行しても問題なく動きました。
microsofのホームページでは、GetAsyncKeyStateは解説で気になるところがありましたので抜粋しておきます。
>>microsofのホームページから抜粋
他のスレッド( またはプロセス)のウィンドウがキーボードフォーカスを備ている場合は、0 が返ります。
自分には意味がわからなかったのですが、これが何か関係しているのでしょうか?
いろいろご解答有難うございます。
こちらの開発環境は、Win98+VC++(6.0)です。
瀬戸っぷさんがおっしゃる通り、Win9X系のコンソールではGetAsyncKeyStateAPIは正しく動作しないのかも知れません。キーボードフォーカスのことは良く分からなかったので、また色々調べてみたいと思います。
本当にありがとうございました。
単にスペックの問題では?Sleep(1)とかにして実行してもダメですか?
というかDOS窓にWindowsメッセージは送られてくるのでしょうか?
どうも、はじめまして、
多分だと思いますが、GetAsyncKeyStateの使い方を間違っていると思います。
現在のRETURNキー押下情報を取りたい場合は、
if( GetAsyncKeyState(VK_RETURN) & 0x8000)
break;
となります。
戻り値は、最下位ビットON時は、
過去にそのキーが押されたか?という情報で、
戻り値は、最上位ビットON時は、
現在そのキーが押されたか?という情報であるからです。
後もう一つ考えられるのは、
キーボードフォーカスが合わさっていないという事です。
この関数の場合は、別スレッドにフォーカスが合わさっていてもキーが取れないので、注意が必要です。
おそらく解決されていると思われますが、
>Win9X系のコンソールではGetAsyncKeyStateAPIは正しく動作しないのかも知れません。
と書かれてるので追記。
Win9X環境でも正しく動くと思われます。
GetAsyncKeyStateは、
ウインドウメッセージに関係なく
その瞬間の情報を返すので、
上記のプログラムだと、
Sleep(500)で、待っている間にキーを押しても無駄だと思われます。
押し続けて、Sleep(500)を抜けた時に、GetAsyncKeyStateの判定部分に行くので
その瞬間に、キーが押されたままだった場合ループから抜けるみたいです。
これは、
DirectXが無い環境用の
リアルタイムなゲーム(メッセージ駆動を無視した)に使用されていたと思われます。
「Win9X系のコンソールアプリで…」という問題に対して同様の問題で悩んでいます。
間をおいているようですが書きこませていただきます。
KSSPさんと同様にWin9X系のコンソールアプリにてGetAsyncStateを使用しSHIFTキーの押下判定を行っているのですが、下記の動作となってしまいます。
なぜこのような動作となってしまうのか、また解決法をご存知の方がいらっしゃいましたら、大変恐縮ですが、ご教授お願いします。
-動作-
<※1>コンソールアクティブ時 :キー押下判定されない
コンソール非アクティブ時:キー押下判定される
<※2>WINDOWS2000で同アプリを実行すると、コンソールアクティブ時でもキー押下判定される。
<※3>GetKeyAsyncStateの換わりにGetKeyStateを使用すると、どんなときでもキー押下判定されない。
+ヘリ+さんの書込みによりますと、win2000でもwin9Xでも同様の動作をするとのことですが、なぜ環境によって動作がかわってしまうのでしょうか・・。
参考までに、現在テストとして作っているサンプルプログラムのソースを載せます。
(http://f1.aaacafe.ne.jp/~pointc/log249.htmlより抜粋したのですが「GetKeyState」→「GetAsyncKeyState」へ変更しております。)
ソース(test.cpp)------------------------------------------------
#include <windows.h>
#include <conio.h>
#include <stdio.h>
void main(void )
{
while(!kbhit()){
printf("Ctrl:%d Shift:%d Alt:%d\r",
(GetAsyncKeyState(VK_CONTROL) & 0x80000000)? 1 : 0,
(GetAsyncKeyState(VK_SHIFT) & 0x80000000)? 1 : 0,
(GetAsyncKeyState(VK_MENU) & 0x80000000)? 1 : 0);
}
getch();
}
------------------------------------------------------
ウィンドウズアプリにすれば解決するのかもしれませんが、コンソールアプリである必要があります。
大変申し訳ございませんが、ご助力の程宜しくお願い致します。
めちゃ当たり前の話で。
2000系のソフトエミュレーションコンソールは、バッファ位置がまったく違い。
もともとコンソール系はキーボード入力を標準入力と位置付け、バッファリングされている。
んで、このバッファは切替が効く(パイプとかファイルとか)ので、それをエミュするために普段と違うバッファに溜め込むに。
昔の状態(エスケープシーケンスとか効く状態)にしてやりゃ、動作が一致するんじゃないかな?
あんまり興味ないので、詳しく調べてませぬ。
SetConsoleModeとかConsoleAPI周りを漁ってくださ。
それと、なんでコンソールでないとダメなんでしょ?
コンソールでWin32APIを呼ぶこと自体、あまり宜しく感じないのですが。
そもそも16bit空間を無理に32bitにして...(省略w。
AUT'Sさんご回答ありがとうございますm(_ _)m
少し複雑ですが、がんばって理解してみます。
Win32APIも本当は使用したくなかったのですが(以前はアセンブラ+DOSシステムコールでがんばっていました→結局GetAsyncKeyStateと同じ)解決できず、仕方なく使用している状況です。(;_;)