console mouse input

Hi all! I want to make an interface for handling mouse input in a console window. I've been experimenting with wrapping some asynchronous windows api functions (GetAsyncKeyState, GetCursorPos), but before I move on I would like to know if there are better core functions for my wrapper. But I dont want to use ReadConsoleInput and such coz (1) they are synchronous and (2) the console event buffer is the same for keyboard and mouse and this really doesn't serve me coz I want to be able to handle mouse events while I use cin for input. Any help would be appreciated! Here is my code: (only left mouse button input is handled at the moment)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#define _WIN32_WINNT 0x0500

#include <cstdlib>
#include <iostream>
#include <process.h>
#include <windows.h>

using namespace std;

class MouseInputHandler
{
      //mouse input handler callback function pointer
      typedef void (*MIHCB)(int,int,void*);
      
      public:
      MouseInputHandler(){}
      ~MouseInputHandler(){}
      void init();
      
      inline void start_polling()
      {
             _beginthread(polling_function,0,this);
             polling=true;
      }
      
      inline void stop_polling()
      {
             input.quit=true;
             while (polling);
      }
      
      int getx();
      int gety();
      void getxy(int & x, int & y);
      
      //setting the callbacks
      inline void set_lbdcb(MIHCB f){lbdcb=f;}
      inline void set_lbucb(MIHCB f){lbucb=f;}
      inline void set_lbccb(MIHCB f){lbccb=f;}
      inline void set_rbdcb(MIHCB f){}
      inline void set_rbucb(MIHCB f){}
      inline void set_rbccb(MIHCB f){}
      
      //setting the params for the callbacks
      inline void set_lbdcbp(void*p){lbdcbp=p;}
      inline void set_lbucbp(void*p){lbucbp=p;}
      inline void set_lbccbp(void*p){lbccbp=p;}
      inline void set_rbdcbp(void*p){}
      inline void set_rbucbp(void*p){}
      inline void set_rbccbp(void*p){}
      
      private:
      struct MouseInput
      {
             //current and previous mouse button status
             bool cleft, pleft;
             bool cright, pright;
             
             bool quit;
             int x,y;
                          
      } input;
      
      bool polling;
      
      static void polling_function(void*);
      static inline bool is_pressed(int key)
      {
             return (GetAsyncKeyState(key)>>15);
      }
      
      MIHCB lbdcb;
      MIHCB lbucb;
      MIHCB lbccb;
      MIHCB rbdcb;
      MIHCB rbucb;
      MIHCB rbccb;
      
      void* lbdcbp;
      void* lbucbp;
      void* lbccbp;
      void* rbdcbp;
      void* rbucbp;
      void* rbccbp;
  
};

void MouseInputHandler::polling_function(void*p)
{
     MouseInputHandler * m=(MouseInputHandler*)p;
     
     m->input.quit=false;
     
     HWND window=GetConsoleWindow();
     RECT wpos;
     POINT cpos;
     
     
     m->input.cleft=m->input.pleft=m->input.cright=m->input.pright=false;
     int x,y;
     int tl, tr,t;
     
          
     while (!m->input.quit)
     {
           GetWindowRect(window,&wpos);
           GetCursorPos(&cpos);
           
           cpos.x-=wpos.left;
           cpos.y-=wpos.top;
           
           //transform screen to console coords
           x=(cpos.x-5)/8;           
           y=(cpos.y-25)/12;
           
           m->input.cleft=is_pressed(VK_LBUTTON);
           m->input.cright=is_pressed(VK_RBUTTON);
           
           //mouse down event: it was up and now is down 
           if (m->input.cleft && !m->input.pleft)
           {
              tl=(clock()*1000)/CLOCKS_PER_SEC;                
              m->lbdcb(x,y,m->lbdcbp);
           }
           
           //mouse up event: it was down and now is up
           if (!m->input.cleft && m->input.pleft)
           {
              t=(clock()*1000)/CLOCKS_PER_SEC;             
              m->lbucb(x,y,m->lbucbp);
              
              //mouse click event:
              //down->up in less than 100 ms
              if (t-tl<=100)
              m->lbccb(x,y,m->lbccbp);
           }
           
           //...more stuff here
           
           m->input.pleft=m->input.cleft;
           //m->input.pright=m->input.cright;
     
           Sleep(25);
     }
     m->polling=false;
}

////////////////////////////////////////////////////////////////////////////////

void left_down(int x, int y, void*p)
{
     printf("left button down at (%d,%d)\n",x,y);
}

void left_up(int x, int y, void*p)
{
     printf("left button up at (%d,%d)\n",x,y);
}

void left_click(int x, int y, void*p)
{
     printf("left click at (%d,%d)\n",x,y);
}

int main()
{
    MouseInputHandler mouse;
    mouse.set_lbdcb(left_down);
    mouse.set_lbucb(left_up);
    mouse.set_lbccb(left_click);
    
    cout << "hit esc anytime to quit" << endl;
    
    mouse.start_polling();
    
    while (!(GetAsyncKeyState(VK_ESCAPE)>>15));
    
    mouse.stop_polling();
    
    system("pause");
    return 0;
}



Last edited on
Why not just hook mouse input globally and then check from there?
Kiana, thanks for the suggestion! I know I can use hooks and I also know that things would be simpler for me if I did. In fact I also got this answer on another forum where I posted the same question. But what would happen if every program that handles mouse input did this using hooks? Disaster... You see,

Hooks tend to slow down the system because they increase the amount of processing the system must perform for each message. You should install a hook only when necessary, and remove it as soon as possible.

( http://msdn.microsoft.com/en-us/library/ms644959%28v=VS.85%29.aspx )

So I'd rather stick to methods that only affect my own application's performance :P
Last edited on
Is this more misuse of the console?

Any particular reason you need the console for? Why not just use a normal windowed program where you don't have to jump through hoops for this kind of thing?
In my humble opinion its not a good idea to try to mix high level and low level input routines like you are trying to do. You are reading mouse input records out of the console input buffer and I'd deal the same way with the keyboard input records. Just tough it out and write yourself a low level routine to get the keyboard input records into a form where you'll be able to use them.
Mmm... So, you mean that it would be best that I use console windows API to handle all input and all ouput? And not use cin and cout at all? I thought it might come down to this :/ Well, if that's the only way... Anyway, thnx to all of you!
Yes, I think once you make the decision to utilize the mouse input records in the console input buffer, that effectively closes the options to utilize the higher level keyboard routines be they something from iostream, stdio, or the Windows Api functions themselves that block (because then you won't get mouse input (I think I'm right about that).

I used to play with these things years ago, but not so much anymore. As a programmer, the console Api is fun to play with, but not too many folks who aren't programmers want console programs. Just my opinion, of course.
Topic archived. No new replies allowed.