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