看到了一个底层的控制台输入函数。
ReadConsoleInput
非常强大,于是在控制台下也可以玩鼠标了。
读入的INPUT_RECORD定义如下:
typedef struct _INPUT_RECORD { // ir
WORD EventType;
union {
KEY_EVENT_RECORD KeyEvent;
MOUSE_EVENT_RECORD MouseEvent;
WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
MENU_EVENT_RECORD MenuEvent;
FOCUS_EVENT_RECORD FocusEvent;
} Event;
} INPUT_RECORD;
EventType可以判断出事件类型。
下面Event是个联合,
不同的EventType时,应该用不同的结构体去对应其中的信息。
跟鼠标有关的是这个:
typedef struct _MOUSE_EVENT_RECORD { // mer
COORD dwMousePosition;
DWORD dwButtonState;
DWORD dwControlKeyState;
DWORD dwEventFlags;
} MOUSE_EVENT_RECORD;
其中要取得坐标和按键状态都很容易了,在MSDN上很清楚。
要注意的是,x坐标是向右,y坐标是向下。
并且控制台的尺寸是80*25。
但当输出内容过多的时候,会向下滚动,
于是得到的(x,y)坐标的行值可能会一直增大。
最大的时候也就是299,因为只支持300行。
一个演示程序:
输出鼠标的位置,并且用'0'画上一个跟随鼠标走的十字标记。
#include <stdio.h>
#include <windows.h>
const int ROW = 25 ;
const int COL = 80 ;
char buffer[ROW][COL] ;
HANDLE ih ;
HANDLE oh ;
void back_to_00(){
COORD cp ;
int ret ;
cp.X = 0 ;
cp.Y = 0 ;
ret = SetConsoleCursorPosition(oh , cp) ;
}
void draw_heart(int x , int y){
int i , j ;
for ( i = 0 ; i < ROW ; i ++ ){
buffer[i][x] = '0' ;
}
for ( j = 0 ; j < COL ; j += 2 ){
buffer[y][j] = '0' ;
}
sprintf(buffer[0] , "(%d,%d)" , x , y) ;
}
void flush_buffer(){
int i , j ;
back_to_00() ;
for ( i = 0 ; i < ROW ; i ++ ){
for ( j = 0 ; j < COL ; j ++ ){
putchar(buffer[i][j]) ;
}
}
back_to_00() ;
memset(buffer , ' ' , sizeof(buffer)) ;
}
int main(){
INPUT_RECORD irc ;
DWORD n ;
ih = GetStdHandle(STD_INPUT_HANDLE) ;
oh = GetStdHandle(STD_OUTPUT_HANDLE) ;
flush_buffer() ;
while(1){
ReadConsoleInput(ih , &irc , 1 , &n) ;
if ( n == 1 ){
if ( irc.EventType == MOUSE_EVENT ) {
MOUSE_EVENT_RECORD mrc = irc.Event.MouseEvent ;
//flush_buffer() ;
//printf("%d,%d/n" , mrc.dwMousePosition.X , mrc.dwMousePosition.Y ) ;
//puts("mouse") ;
draw_heart(mrc.dwMousePosition.X , mrc.dwMousePosition.Y) ;
flush_buffer() ;
}
}
}
return 0 ;
}