pdcurses/mouse.c

changeset 97
2d43f05b284c
equal deleted inserted replaced
96:5314ebdcb38d 97:2d43f05b284c
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 }

mercurial