1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2007 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup wm
22  *
23  * Read-only queries utility functions for the event system.
24  */
25 
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "DNA_listBase.h"
30 #include "DNA_scene_types.h"
31 #include "DNA_screen_types.h"
32 #include "DNA_userdef_types.h"
33 #include "DNA_windowmanager_types.h"
34 
35 #include "BLI_blenlib.h"
36 #include "BLI_math.h"
37 #include "BLI_utildefines.h"
38 
39 #include "BKE_context.h"
40 
41 #include "RNA_access.h"
42 
43 #include "WM_api.h"
44 #include "WM_types.h"
45 
46 #include "wm_event_system.h"
47 #include "wm_event_types.h"
48 
49 #include "RNA_enum_types.h"
50 
51 #include "DEG_depsgraph.h"
52 
53 /* -------------------------------------------------------------------- */
54 /** \name Event Printing
55  * \{ */
56 
57 /* for debugging only, getting inspecting events manually is tedious */
WM_event_print(const wmEvent * event)58 void WM_event_print(const wmEvent *event)
59 {
60   if (event) {
61     const char *unknown = "UNKNOWN";
62     const char *type_id = unknown;
63     const char *val_id = unknown;
64     const char *prev_type_id = unknown;
65     const char *prev_val_id = unknown;
66 
67     RNA_enum_identifier(rna_enum_event_type_items, event->type, &type_id);
68     RNA_enum_identifier(rna_enum_event_value_items, event->val, &val_id);
69 
70     RNA_enum_identifier(rna_enum_event_type_items, event->prevtype, &prev_type_id);
71     RNA_enum_identifier(rna_enum_event_value_items, event->prevval, &prev_val_id);
72 
73     printf(
74         "wmEvent  type:%d / %s, val:%d / %s,\n"
75         "         prev_type:%d / %s, prev_val:%d / %s,\n"
76         "         shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, is_repeat:%d,\n"
77         "         mouse:(%d,%d), ascii:'%c', utf8:'%.*s', pointer:%p\n",
78         event->type,
79         type_id,
80         event->val,
81         val_id,
82         event->prevtype,
83         prev_type_id,
84         event->prevval,
85         prev_val_id,
86         event->shift,
87         event->ctrl,
88         event->alt,
89         event->oskey,
90         event->keymodifier,
91         event->is_repeat,
92         event->x,
93         event->y,
94         event->ascii,
95         BLI_str_utf8_size(event->utf8_buf),
96         event->utf8_buf,
97         (const void *)event);
98 
99 #ifdef WITH_INPUT_NDOF
100     if (ISNDOF(event->type)) {
101       const wmNDOFMotionData *ndof = event->customdata;
102       if (event->type == NDOF_MOTION) {
103         printf("   ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %u\n",
104                UNPACK3(ndof->rvec),
105                UNPACK3(ndof->tvec),
106                ndof->dt,
107                ndof->progress);
108       }
109       else {
110         /* ndof buttons printed already */
111       }
112     }
113 #endif /* WITH_INPUT_NDOF */
114 
115     if (event->tablet.active != EVT_TABLET_NONE) {
116       const wmTabletData *wmtab = &event->tablet;
117       printf(" tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)\n",
118              wmtab->active,
119              wmtab->pressure,
120              wmtab->x_tilt,
121              wmtab->y_tilt);
122     }
123   }
124   else {
125     printf("wmEvent - NULL\n");
126   }
127 }
128 
129 /** \} */
130 
131 /* -------------------------------------------------------------------- */
132 /** \name Event Modifier/Type Queries
133  * \{ */
134 
WM_event_modifier_flag(const wmEvent * event)135 int WM_event_modifier_flag(const wmEvent *event)
136 {
137   int flag = 0;
138   if (event->ctrl) {
139     flag |= KM_CTRL;
140   }
141   if (event->alt) {
142     flag |= KM_ALT;
143   }
144   if (event->shift) {
145     flag |= KM_SHIFT;
146   }
147   if (event->oskey) {
148     flag |= KM_OSKEY;
149   }
150   return flag;
151 }
152 
WM_event_type_mask_test(const int event_type,const enum eEventType_Mask mask)153 bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask mask)
154 {
155   /* Keyboard. */
156   if (mask & EVT_TYPE_MASK_KEYBOARD) {
157     if (ISKEYBOARD(event_type)) {
158       return true;
159     }
160   }
161   else if (mask & EVT_TYPE_MASK_KEYBOARD_MODIFIER) {
162     if (ISKEYMODIFIER(event_type)) {
163       return true;
164     }
165   }
166 
167   /* Mouse. */
168   if (mask & EVT_TYPE_MASK_MOUSE) {
169     if (ISMOUSE(event_type)) {
170       return true;
171     }
172   }
173   else if (mask & EVT_TYPE_MASK_MOUSE_WHEEL) {
174     if (ISMOUSE_WHEEL(event_type)) {
175       return true;
176     }
177   }
178   else if (mask & EVT_TYPE_MASK_MOUSE_GESTURE) {
179     if (ISMOUSE_GESTURE(event_type)) {
180       return true;
181     }
182   }
183 
184   /* Tweak. */
185   if (mask & EVT_TYPE_MASK_TWEAK) {
186     if (ISTWEAK(event_type)) {
187       return true;
188     }
189   }
190 
191   /* Action Zone. */
192   if (mask & EVT_TYPE_MASK_ACTIONZONE) {
193     if (IS_EVENT_ACTIONZONE(event_type)) {
194       return true;
195     }
196   }
197 
198   return false;
199 }
200 
201 /** \} */
202 
203 /* -------------------------------------------------------------------- */
204 /** \name Event Motion Queries
205  * \{ */
206 
207 /* for modal callbacks, check configuration for how to interpret exit with tweaks  */
WM_event_is_modal_tweak_exit(const wmEvent * event,int tweak_event)208 bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event)
209 {
210   /* if the release-confirm userpref setting is enabled,
211    * tweak events can be canceled when mouse is released
212    */
213   if (U.flag & USER_RELEASECONFIRM) {
214     /* option on, so can exit with km-release */
215     if (event->val == KM_RELEASE) {
216       switch (tweak_event) {
217         case EVT_TWEAK_L:
218         case EVT_TWEAK_M:
219         case EVT_TWEAK_R:
220           return 1;
221       }
222     }
223     else {
224       /* if the initial event wasn't a tweak event then
225        * ignore USER_RELEASECONFIRM setting: see T26756. */
226       if (ELEM(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) {
227         return 1;
228       }
229     }
230   }
231   else {
232     /* this is fine as long as not doing km-release, otherwise
233      * some items (i.e. markers) being tweaked may end up getting
234      * dropped all over
235      */
236     if (event->val != KM_RELEASE) {
237       return 1;
238     }
239   }
240 
241   return 0;
242 }
243 
WM_event_is_last_mousemove(const wmEvent * event)244 bool WM_event_is_last_mousemove(const wmEvent *event)
245 {
246   while ((event = event->next)) {
247     if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
248       return false;
249     }
250   }
251   return true;
252 }
253 
254 /** \} */
255 
256 /* -------------------------------------------------------------------- */
257 /** \name Event Click/Drag Checks
258  *
259  * Values under this limit are detected as clicks.
260  *
261  * \{ */
262 
WM_event_drag_threshold(const struct wmEvent * event)263 int WM_event_drag_threshold(const struct wmEvent *event)
264 {
265   int drag_threshold;
266   if (WM_event_is_tablet(event)) {
267     drag_threshold = U.drag_threshold_tablet;
268   }
269   else if (ISMOUSE(event->prevtype)) {
270     drag_threshold = U.drag_threshold_mouse;
271   }
272   else {
273     /* Typically keyboard, could be NDOF button or other less common types. */
274     drag_threshold = U.drag_threshold;
275   }
276   return drag_threshold * U.dpi_fac;
277 }
278 
WM_event_drag_test_with_delta(const wmEvent * event,const int drag_delta[2])279 bool WM_event_drag_test_with_delta(const wmEvent *event, const int drag_delta[2])
280 {
281   const int drag_threshold = WM_event_drag_threshold(event);
282   return abs(drag_delta[0]) > drag_threshold || abs(drag_delta[1]) > drag_threshold;
283 }
284 
WM_event_drag_test(const wmEvent * event,const int prev_xy[2])285 bool WM_event_drag_test(const wmEvent *event, const int prev_xy[2])
286 {
287   const int drag_delta[2] = {
288       prev_xy[0] - event->x,
289       prev_xy[1] - event->y,
290   };
291   return WM_event_drag_test_with_delta(event, drag_delta);
292 }
293 
294 /** \} */
295 
296 /* -------------------------------------------------------------------- */
297 /** \name Event Preference Mapping
298  * \{ */
299 
WM_userdef_event_map(int kmitype)300 int WM_userdef_event_map(int kmitype)
301 {
302   switch (kmitype) {
303     case WHEELOUTMOUSE:
304       return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE;
305     case WHEELINMOUSE:
306       return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE;
307   }
308 
309   return kmitype;
310 }
311 
312 /**
313  * Use so we can check if 'wmEvent.type' is released in modal operators.
314  *
315  * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar.
316  */
WM_userdef_event_type_from_keymap_type(int kmitype)317 int WM_userdef_event_type_from_keymap_type(int kmitype)
318 {
319   switch (kmitype) {
320     case EVT_TWEAK_L:
321       return LEFTMOUSE;
322     case EVT_TWEAK_M:
323       return MIDDLEMOUSE;
324     case EVT_TWEAK_R:
325       return RIGHTMOUSE;
326     case WHEELOUTMOUSE:
327       return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE;
328     case WHEELINMOUSE:
329       return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE;
330   }
331 
332   return kmitype;
333 }
334 
335 /** \} */
336 
337 /* -------------------------------------------------------------------- */
338 /** \name Event NDOF Input Access
339  * \{ */
340 
341 #ifdef WITH_INPUT_NDOF
342 
WM_event_ndof_pan_get(const wmNDOFMotionData * ndof,float r_pan[3],const bool use_zoom)343 void WM_event_ndof_pan_get(const wmNDOFMotionData *ndof, float r_pan[3], const bool use_zoom)
344 {
345   int z_flag = use_zoom ? NDOF_ZOOM_INVERT : NDOF_PANZ_INVERT_AXIS;
346   r_pan[0] = ndof->tvec[0] * ((U.ndof_flag & NDOF_PANX_INVERT_AXIS) ? -1.0f : 1.0f);
347   r_pan[1] = ndof->tvec[1] * ((U.ndof_flag & NDOF_PANY_INVERT_AXIS) ? -1.0f : 1.0f);
348   r_pan[2] = ndof->tvec[2] * ((U.ndof_flag & z_flag) ? -1.0f : 1.0f);
349 }
350 
WM_event_ndof_rotate_get(const wmNDOFMotionData * ndof,float r_rot[3])351 void WM_event_ndof_rotate_get(const wmNDOFMotionData *ndof, float r_rot[3])
352 {
353   r_rot[0] = ndof->rvec[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f);
354   r_rot[1] = ndof->rvec[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f);
355   r_rot[2] = ndof->rvec[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f);
356 }
357 
WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData * ndof,float axis[3])358 float WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3])
359 {
360   float angle;
361   angle = normalize_v3_v3(axis, ndof->rvec);
362 
363   axis[0] = axis[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f);
364   axis[1] = axis[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f);
365   axis[2] = axis[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f);
366 
367   return ndof->dt * angle;
368 }
369 
WM_event_ndof_to_quat(const struct wmNDOFMotionData * ndof,float q[4])370 void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4])
371 {
372   float axis[3];
373   float angle;
374 
375   angle = WM_event_ndof_to_axis_angle(ndof, axis);
376   axis_angle_to_quat(q, axis, angle);
377 }
378 #endif /* WITH_INPUT_NDOF */
379 
380 /** \} */
381 
382 /* -------------------------------------------------------------------- */
383 /** \name Event Tablet Input Access
384  * \{ */
385 
386 /* applies the global tablet pressure correction curve */
wm_pressure_curve(float pressure)387 float wm_pressure_curve(float pressure)
388 {
389   if (U.pressure_threshold_max != 0.0f) {
390     pressure /= U.pressure_threshold_max;
391   }
392 
393   CLAMP(pressure, 0.0f, 1.0f);
394 
395   if (U.pressure_softness != 0.0f) {
396     pressure = powf(pressure, powf(4.0f, -U.pressure_softness));
397   }
398 
399   return pressure;
400 }
401 
402 /* if this is a tablet event, return tablet pressure and set *pen_flip
403  * to 1 if the eraser tool is being used, 0 otherwise */
WM_event_tablet_data(const wmEvent * event,int * pen_flip,float tilt[2])404 float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2])
405 {
406   if (tilt) {
407     tilt[0] = event->tablet.x_tilt;
408     tilt[1] = event->tablet.y_tilt;
409   }
410 
411   if (pen_flip) {
412     (*pen_flip) = (event->tablet.active == EVT_TABLET_ERASER);
413   }
414 
415   return event->tablet.pressure;
416 }
417 
WM_event_is_tablet(const struct wmEvent * event)418 bool WM_event_is_tablet(const struct wmEvent *event)
419 {
420   return (event->tablet.active != EVT_TABLET_NONE);
421 }
422 
423 /** \} */
424 
425 /* -------------------------------------------------------------------- */
426 /** \name Event IME Input Access
427  * \{ */
428 
429 #ifdef WITH_INPUT_IME
430 /* most os using ctrl/oskey + space to switch ime, avoid added space */
WM_event_is_ime_switch(const struct wmEvent * event)431 bool WM_event_is_ime_switch(const struct wmEvent *event)
432 {
433   return event->val == KM_PRESS && event->type == EVT_SPACEKEY &&
434          (event->ctrl || event->oskey || event->shift || event->alt);
435 }
436 #endif
437 
438 /** \} */
439