| |
1 /* Public Domain Curses */ |
| |
2 |
| |
3 #include <curspriv.h> |
| |
4 |
| |
5 RCSID("$Id: mouse.c,v 1.45 2008/07/13 16:08:18 wmcbrine Exp $") |
| |
6 |
| |
7 /*man-start************************************************************** |
| |
8 |
| |
9 Name: mouse |
| |
10 |
| |
11 Synopsis: |
| |
12 int mouse_set(unsigned long mbe); |
| |
13 int mouse_on(unsigned long mbe); |
| |
14 int mouse_off(unsigned long mbe); |
| |
15 int request_mouse_pos(void); |
| |
16 int map_button(unsigned long button); |
| |
17 void wmouse_position(WINDOW *win, int *y, int *x); |
| |
18 unsigned long getmouse(void); |
| |
19 unsigned long getbmap(void); |
| |
20 |
| |
21 int mouseinterval(int wait); |
| |
22 bool wenclose(const WINDOW *win, int y, int x); |
| |
23 bool wmouse_trafo(const WINDOW *win, int *y, int *x, bool to_screen); |
| |
24 bool mouse_trafo(int *y, int *x, bool to_screen); |
| |
25 mmask_t mousemask(mmask_t mask, mmask_t *oldmask); |
| |
26 int nc_getmouse(MEVENT *event); |
| |
27 int ungetmouse(MEVENT *event); |
| |
28 |
| |
29 Description: |
| |
30 As of PDCurses 3.0, there are two separate mouse interfaces: the |
| |
31 classic interface, which is based on the undocumented Sys V |
| |
32 mouse functions; and an ncurses-compatible interface. Both are |
| |
33 active at all times, and you can mix and match functions from |
| |
34 each, though it's not recommended. The ncurses interface is |
| |
35 essentially an emulation layer built on top of the classic |
| |
36 interface; it's here to allow easier porting of ncurses apps. |
| |
37 |
| |
38 The classic interface: mouse_set(), mouse_on(), mouse_off(), |
| |
39 request_mouse_pos(), map_button(), wmouse_position(), |
| |
40 getmouse(), and getbmap(). An application using this interface |
| |
41 would start by calling mouse_set() or mouse_on() with a non-zero |
| |
42 value, often ALL_MOUSE_EVENTS. Then it would check for a |
| |
43 KEY_MOUSE return from getch(). If found, it would call |
| |
44 request_mouse_pos() to get the current mouse status. |
| |
45 |
| |
46 mouse_set(), mouse_on() and mouse_off() are analagous to |
| |
47 attrset(), attron() and attroff(). These functions set the |
| |
48 mouse button events to trap. The button masks used in these |
| |
49 functions are defined in curses.h and can be or'ed together. |
| |
50 They are the group of masks starting with BUTTON1_RELEASED. |
| |
51 |
| |
52 request_mouse_pos() requests curses to fill in the Mouse_status |
| |
53 structure with the current state of the mouse. |
| |
54 |
| |
55 map_button() enables the specified mouse action to activate the |
| |
56 Soft Label Keys if the action occurs over the area of the screen |
| |
57 where the Soft Label Keys are displayed. The mouse actions are |
| |
58 defined in curses.h in the group that starts with BUTTON_RELEASED. |
| |
59 |
| |
60 wmouse_position() determines if the current mouse position is |
| |
61 within the window passed as an argument. If the mouse is |
| |
62 outside the current window, -1 is returned in the y and x |
| |
63 arguments; otherwise the y and x coordinates of the mouse |
| |
64 (relative to the top left corner of the window) are returned in |
| |
65 y and x. |
| |
66 |
| |
67 getmouse() returns the current status of the trapped mouse |
| |
68 buttons as set by mouse_set() or mouse_on(). |
| |
69 |
| |
70 getbmap() returns the current status of the button action used |
| |
71 to map a mouse action to the Soft Label Keys as set by the |
| |
72 map_button() function. |
| |
73 |
| |
74 The ncurses interface: mouseinterval(), wenclose(), |
| |
75 wmouse_trafo(), mouse_trafo(), mousemask(), nc_getmouse(), and |
| |
76 ungetmouse(). A typical application using this interface would |
| |
77 start by calling mousemask() with a non-zero value, often |
| |
78 ALL_MOUSE_EVENTS. Then it would check for a KEY_MOUSE return |
| |
79 from getch(). If found, it would call nc_getmouse() to get the |
| |
80 current mouse status. |
| |
81 |
| |
82 mouseinterval() sets the timeout for a mouse click. On all |
| |
83 current platforms, PDCurses receives mouse button press and |
| |
84 release events, but must synthesize click events. It does this |
| |
85 by checking whether a release event is queued up after a press |
| |
86 event. If it gets a press event, and there are no more events |
| |
87 waiting, it will wait for the timeout interval, then check again |
| |
88 for a release. A press followed by a release is reported as |
| |
89 BUTTON_CLICKED; otherwise it's passed through as BUTTON_PRESSED. |
| |
90 The default timeout is 150ms; valid values are 0 (no clicks |
| |
91 reported) through 1000ms. In x11, the timeout can also be set |
| |
92 via the clickPeriod resource. The return value from |
| |
93 mouseinterval() is the old timeout. To check the old value |
| |
94 without setting a new one, call it with a parameter of -1. Note |
| |
95 that although there's no classic equivalent for this function |
| |
96 (apart from the clickPeriod resource), the value set applies in |
| |
97 both interfaces. |
| |
98 |
| |
99 wenclose() reports whether the given screen-relative y, x |
| |
100 coordinates fall within the given window. |
| |
101 |
| |
102 wmouse_trafo() converts between screen-relative and window- |
| |
103 relative coordinates. A to_screen parameter of TRUE means to |
| |
104 convert from window to screen; otherwise the reverse. The |
| |
105 function returns FALSE if the coordinates aren't within the |
| |
106 window, or if any of the parameters are NULL. The coordinates |
| |
107 have been converted when the function returns TRUE. |
| |
108 |
| |
109 mouse_trafo() is the stdscr version of wmouse_trafo(). |
| |
110 |
| |
111 mousemask() is nearly equivalent to mouse_set(), but instead of |
| |
112 OK/ERR, it returns the value of the mask after setting it. (This |
| |
113 isn't necessarily the same value passed in, since the mask could |
| |
114 be altered on some platforms.) And if the second parameter is a |
| |
115 non-null pointer, mousemask() stores the previous mask value |
| |
116 there. Also, since the ncurses interface doesn't work with |
| |
117 PDCurses' BUTTON_MOVED events, mousemask() filters them out. |
| |
118 |
| |
119 nc_getmouse() returns the current mouse status in an MEVENT |
| |
120 struct. This is equivalent to ncurses' getmouse(), renamed to |
| |
121 avoid conflict with PDCurses' getmouse(). But if you define |
| |
122 NCURSES_MOUSE_VERSION (preferably as 2) before including |
| |
123 curses.h, it defines getmouse() to nc_getmouse(), along with a |
| |
124 few other redefintions needed for compatibility with ncurses |
| |
125 code. nc_getmouse() calls request_mouse_pos(), which (not |
| |
126 getmouse()) is the classic equivalent. |
| |
127 |
| |
128 ungetmouse() is the mouse equivalent of ungetch(). However, |
| |
129 PDCurses doesn't maintain a queue of mouse events; only one can |
| |
130 be pushed back, and it can overwrite or be overwritten by real |
| |
131 mouse events. |
| |
132 |
| |
133 Portability X/Open BSD SYS V |
| |
134 mouse_set - - 4.0 |
| |
135 mouse_on - - 4.0 |
| |
136 mouse_off - - 4.0 |
| |
137 request_mouse_pos - - 4.0 |
| |
138 map_button - - 4.0 |
| |
139 wmouse_position - - 4.0 |
| |
140 getmouse - - 4.0 |
| |
141 getbmap - - 4.0 |
| |
142 mouseinterval - - - |
| |
143 wenclose - - - |
| |
144 wmouse_trafo - - - |
| |
145 mouse_trafo - - - |
| |
146 mousemask - - - |
| |
147 nc_getmouse - - - |
| |
148 ungetmouse - - - |
| |
149 |
| |
150 **man-end****************************************************************/ |
| |
151 |
| |
152 #include <string.h> |
| |
153 |
| |
154 static bool ungot = FALSE; |
| |
155 |
| |
156 int mouse_set(unsigned long mbe) |
| |
157 { |
| |
158 PDC_LOG(("mouse_set() - called: event %x\n", mbe)); |
| |
159 |
| |
160 SP->_trap_mbe = mbe; |
| |
161 return PDC_mouse_set(); |
| |
162 } |
| |
163 |
| |
164 int mouse_on(unsigned long mbe) |
| |
165 { |
| |
166 PDC_LOG(("mouse_on() - called: event %x\n", mbe)); |
| |
167 |
| |
168 SP->_trap_mbe |= mbe; |
| |
169 return PDC_mouse_set(); |
| |
170 } |
| |
171 |
| |
172 int mouse_off(unsigned long mbe) |
| |
173 { |
| |
174 PDC_LOG(("mouse_off() - called: event %x\n", mbe)); |
| |
175 |
| |
176 SP->_trap_mbe &= ~mbe; |
| |
177 return PDC_mouse_set(); |
| |
178 } |
| |
179 |
| |
180 int map_button(unsigned long button) |
| |
181 { |
| |
182 PDC_LOG(("map_button() - called: button %x\n", button)); |
| |
183 |
| |
184 /****************** this does nothing at the moment ***************/ |
| |
185 SP->_map_mbe_to_key = button; |
| |
186 |
| |
187 return OK; |
| |
188 } |
| |
189 |
| |
190 int request_mouse_pos(void) |
| |
191 { |
| |
192 PDC_LOG(("request_mouse_pos() - called\n")); |
| |
193 |
| |
194 Mouse_status = pdc_mouse_status; |
| |
195 |
| |
196 return OK; |
| |
197 } |
| |
198 |
| |
199 void wmouse_position(WINDOW *win, int *y, int *x) |
| |
200 { |
| |
201 PDC_LOG(("wmouse_position() - called\n")); |
| |
202 |
| |
203 if (win && wenclose(win, MOUSE_Y_POS, MOUSE_X_POS)) |
| |
204 { |
| |
205 if (y) |
| |
206 *y = MOUSE_Y_POS - win->_begy; |
| |
207 if (x) |
| |
208 *x = MOUSE_X_POS - win->_begx; |
| |
209 } |
| |
210 else |
| |
211 { |
| |
212 if (y) |
| |
213 *y = -1; |
| |
214 if (x) |
| |
215 *x = -1; |
| |
216 } |
| |
217 } |
| |
218 |
| |
219 unsigned long getmouse(void) |
| |
220 { |
| |
221 PDC_LOG(("getmouse() - called\n")); |
| |
222 |
| |
223 return SP->_trap_mbe; |
| |
224 } |
| |
225 |
| |
226 unsigned long getbmap(void) |
| |
227 { |
| |
228 PDC_LOG(("getbmap() - called\n")); |
| |
229 |
| |
230 return SP->_map_mbe_to_key; |
| |
231 } |
| |
232 |
| |
233 /* ncurses mouse interface */ |
| |
234 |
| |
235 int mouseinterval(int wait) |
| |
236 { |
| |
237 int old_wait; |
| |
238 |
| |
239 PDC_LOG(("mouseinterval() - called: %d\n", wait)); |
| |
240 |
| |
241 old_wait = SP->mouse_wait; |
| |
242 |
| |
243 if (wait >= 0 && wait <= 1000) |
| |
244 SP->mouse_wait = wait; |
| |
245 |
| |
246 return old_wait; |
| |
247 } |
| |
248 |
| |
249 bool wenclose(const WINDOW *win, int y, int x) |
| |
250 { |
| |
251 PDC_LOG(("wenclose() - called: %p %d %d\n", win, y, x)); |
| |
252 |
| |
253 return (win && y >= win->_begy && y < win->_begy + win->_maxy |
| |
254 && x >= win->_begx && x < win->_begx + win->_maxx); |
| |
255 } |
| |
256 |
| |
257 bool wmouse_trafo(const WINDOW *win, int *y, int *x, bool to_screen) |
| |
258 { |
| |
259 int newy, newx; |
| |
260 |
| |
261 PDC_LOG(("wmouse_trafo() - called\n")); |
| |
262 |
| |
263 if (!win || !y || !x) |
| |
264 return FALSE; |
| |
265 |
| |
266 newy = *y; |
| |
267 newx = *x; |
| |
268 |
| |
269 if (to_screen) |
| |
270 { |
| |
271 newy += win->_begy; |
| |
272 newx += win->_begx; |
| |
273 |
| |
274 if (!wenclose(win, newy, newx)) |
| |
275 return FALSE; |
| |
276 } |
| |
277 else |
| |
278 { |
| |
279 if (wenclose(win, newy, newx)) |
| |
280 { |
| |
281 newy -= win->_begy; |
| |
282 newx -= win->_begx; |
| |
283 } |
| |
284 else |
| |
285 return FALSE; |
| |
286 } |
| |
287 |
| |
288 *y = newy; |
| |
289 *x = newx; |
| |
290 |
| |
291 return TRUE; |
| |
292 } |
| |
293 |
| |
294 bool mouse_trafo(int *y, int *x, bool to_screen) |
| |
295 { |
| |
296 PDC_LOG(("mouse_trafo() - called\n")); |
| |
297 |
| |
298 return wmouse_trafo(stdscr, y, x, to_screen); |
| |
299 } |
| |
300 |
| |
301 mmask_t mousemask(mmask_t mask, mmask_t *oldmask) |
| |
302 { |
| |
303 PDC_LOG(("mousemask() - called\n")); |
| |
304 |
| |
305 if (oldmask) |
| |
306 *oldmask = SP->_trap_mbe; |
| |
307 |
| |
308 /* The ncurses interface doesn't work with our move events, so |
| |
309 filter them here */ |
| |
310 |
| |
311 mask &= ~(BUTTON1_MOVED | BUTTON2_MOVED | BUTTON3_MOVED); |
| |
312 |
| |
313 mouse_set(mask); |
| |
314 |
| |
315 return SP->_trap_mbe; |
| |
316 } |
| |
317 |
| |
318 int nc_getmouse(MEVENT *event) |
| |
319 { |
| |
320 int i; |
| |
321 mmask_t bstate = 0; |
| |
322 |
| |
323 PDC_LOG(("nc_getmouse() - called\n")); |
| |
324 |
| |
325 if (!event) |
| |
326 return ERR; |
| |
327 |
| |
328 ungot = FALSE; |
| |
329 |
| |
330 request_mouse_pos(); |
| |
331 |
| |
332 event->id = 0; |
| |
333 |
| |
334 event->x = Mouse_status.x; |
| |
335 event->y = Mouse_status.y; |
| |
336 event->z = 0; |
| |
337 |
| |
338 for (i = 0; i < 3; i++) |
| |
339 { |
| |
340 if (Mouse_status.changes & (1 << i)) |
| |
341 { |
| |
342 int shf = i * 5; |
| |
343 short button = Mouse_status.button[i] & BUTTON_ACTION_MASK; |
| |
344 |
| |
345 if (button == BUTTON_RELEASED) |
| |
346 bstate |= (BUTTON1_RELEASED << shf); |
| |
347 else if (button == BUTTON_PRESSED) |
| |
348 bstate |= (BUTTON1_PRESSED << shf); |
| |
349 else if (button == BUTTON_CLICKED) |
| |
350 bstate |= (BUTTON1_CLICKED << shf); |
| |
351 else if (button == BUTTON_DOUBLE_CLICKED) |
| |
352 bstate |= (BUTTON1_DOUBLE_CLICKED << shf); |
| |
353 |
| |
354 button = Mouse_status.button[i] & BUTTON_MODIFIER_MASK; |
| |
355 |
| |
356 if (button & PDC_BUTTON_SHIFT) |
| |
357 bstate |= BUTTON_MODIFIER_SHIFT; |
| |
358 if (button & PDC_BUTTON_CONTROL) |
| |
359 bstate |= BUTTON_MODIFIER_CONTROL; |
| |
360 if (button & PDC_BUTTON_ALT) |
| |
361 bstate |= BUTTON_MODIFIER_ALT; |
| |
362 } |
| |
363 } |
| |
364 |
| |
365 if (MOUSE_WHEEL_UP) |
| |
366 bstate |= BUTTON4_PRESSED; |
| |
367 else if (MOUSE_WHEEL_DOWN) |
| |
368 bstate |= BUTTON5_PRESSED; |
| |
369 |
| |
370 /* extra filter pass -- mainly for button modifiers */ |
| |
371 |
| |
372 event->bstate = bstate & SP->_trap_mbe; |
| |
373 |
| |
374 return OK; |
| |
375 } |
| |
376 |
| |
377 int ungetmouse(MEVENT *event) |
| |
378 { |
| |
379 int i; |
| |
380 unsigned long bstate; |
| |
381 |
| |
382 PDC_LOG(("ungetmouse() - called\n")); |
| |
383 |
| |
384 if (!event || ungot) |
| |
385 return ERR; |
| |
386 |
| |
387 ungot = TRUE; |
| |
388 |
| |
389 pdc_mouse_status.x = event->x; |
| |
390 pdc_mouse_status.y = event->y; |
| |
391 |
| |
392 pdc_mouse_status.changes = 0; |
| |
393 bstate = event->bstate; |
| |
394 |
| |
395 for (i = 0; i < 3; i++) |
| |
396 { |
| |
397 int shf = i * 5; |
| |
398 short button = 0; |
| |
399 |
| |
400 if (bstate & ((BUTTON1_RELEASED | BUTTON1_PRESSED | |
| |
401 BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED) << shf)) |
| |
402 { |
| |
403 pdc_mouse_status.changes |= 1 << i; |
| |
404 |
| |
405 if (bstate & (BUTTON1_PRESSED << shf)) |
| |
406 button = BUTTON_PRESSED; |
| |
407 if (bstate & (BUTTON1_CLICKED << shf)) |
| |
408 button = BUTTON_CLICKED; |
| |
409 if (bstate & (BUTTON1_DOUBLE_CLICKED << shf)) |
| |
410 button = BUTTON_DOUBLE_CLICKED; |
| |
411 |
| |
412 if (bstate & BUTTON_MODIFIER_SHIFT) |
| |
413 button |= PDC_BUTTON_SHIFT; |
| |
414 if (bstate & BUTTON_MODIFIER_CONTROL) |
| |
415 button |= PDC_BUTTON_CONTROL; |
| |
416 if (bstate & BUTTON_MODIFIER_ALT) |
| |
417 button |= PDC_BUTTON_ALT; |
| |
418 } |
| |
419 |
| |
420 pdc_mouse_status.button[i] = button; |
| |
421 } |
| |
422 |
| |
423 if (bstate & BUTTON4_PRESSED) |
| |
424 pdc_mouse_status.changes |= PDC_MOUSE_WHEEL_UP; |
| |
425 else if (bstate & BUTTON5_PRESSED) |
| |
426 pdc_mouse_status.changes |= PDC_MOUSE_WHEEL_DOWN; |
| |
427 |
| |
428 return ungetch(KEY_MOUSE); |
| |
429 } |