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