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