Cleanup: comment line length (windowmanager)
[blender.git] / source / blender / windowmanager / intern / wm_keymap.c
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  * Configurable key-maps - add/remove/find/compare/patch...
24  */
25
26 #include <string.h>
27
28 #include "DNA_object_types.h"
29 #include "DNA_screen_types.h"
30 #include "DNA_space_types.h"
31 #include "DNA_userdef_types.h"
32 #include "DNA_windowmanager_types.h"
33 #include "DNA_workspace_types.h"
34
35 #include "MEM_guardedalloc.h"
36 #include "CLG_log.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_utildefines.h"
40 #include "BLI_math.h"
41
42 #include "BKE_context.h"
43 #include "BKE_idprop.h"
44 #include "BKE_global.h"
45 #include "BKE_main.h"
46 #include "BKE_screen.h"
47 #include "BKE_workspace.h"
48
49 #include "BLT_translation.h"
50
51 #include "RNA_access.h"
52 #include "RNA_enum_types.h"
53
54 #include "WM_api.h"
55 #include "WM_types.h"
56 #include "wm_event_system.h"
57 #include "wm_event_types.h"
58
59 struct wmKeyMapItemFind_Params {
60   bool (*filter_fn)(const wmKeyMap *km, const wmKeyMapItem *kmi, void *user_data);
61   void *user_data;
62 };
63
64 /******************************* Keymap Item **********************************
65  * Item in a keymap, that maps from an event to an operator or modal map item */
66
67 static wmKeyMapItem *wm_keymap_item_copy(wmKeyMapItem *kmi)
68 {
69   wmKeyMapItem *kmin = MEM_dupallocN(kmi);
70
71   kmin->prev = kmin->next = NULL;
72   kmin->flag &= ~KMI_UPDATE;
73
74   if (kmin->properties) {
75     kmin->ptr = MEM_callocN(sizeof(PointerRNA), "UserKeyMapItemPtr");
76     WM_operator_properties_create(kmin->ptr, kmin->idname);
77
78     kmin->properties = IDP_CopyProperty(kmin->properties);
79     kmin->ptr->data = kmin->properties;
80   }
81   else {
82     kmin->properties = NULL;
83     kmin->ptr = NULL;
84   }
85
86   return kmin;
87 }
88
89 static void wm_keymap_item_free(wmKeyMapItem *kmi)
90 {
91   /* not kmi itself */
92   if (kmi->ptr) {
93     WM_operator_properties_free(kmi->ptr);
94     MEM_freeN(kmi->ptr);
95     kmi->ptr = NULL;
96     kmi->properties = NULL;
97   }
98 }
99
100 static void wm_keymap_item_properties_set(wmKeyMapItem *kmi)
101 {
102   WM_operator_properties_alloc(&(kmi->ptr), &(kmi->properties), kmi->idname);
103   WM_operator_properties_sanitize(kmi->ptr, 1);
104 }
105
106 /**
107  * Similar to #wm_keymap_item_properties_set
108  * but checks for the #wmOperatorType having changed, see T38042.
109  */
110 static void wm_keymap_item_properties_update_ot(wmKeyMapItem *kmi)
111 {
112   if (kmi->idname[0] == 0) {
113     BLI_assert(kmi->ptr == NULL);
114     return;
115   }
116
117   if (kmi->ptr == NULL) {
118     wm_keymap_item_properties_set(kmi);
119   }
120   else {
121     wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
122     if (ot) {
123       if (ot->srna != kmi->ptr->type) {
124         /* matches wm_keymap_item_properties_set but doesn't alloc new ptr */
125         WM_operator_properties_create_ptr(kmi->ptr, ot);
126         /* 'kmi->ptr->data' NULL'd above, keep using existing properties.
127          * Note: the operators property types may have changed,
128          * we will need a more comprehensive sanitize function to support this properly.
129          */
130         if (kmi->properties) {
131           kmi->ptr->data = kmi->properties;
132         }
133         WM_operator_properties_sanitize(kmi->ptr, 1);
134       }
135     }
136     else {
137       /* zombie keymap item */
138       wm_keymap_item_free(kmi);
139     }
140   }
141 }
142
143 static void wm_keyconfig_properties_update_ot(ListBase *km_lb)
144 {
145   wmKeyMap *km;
146   wmKeyMapItem *kmi;
147
148   for (km = km_lb->first; km; km = km->next) {
149     wmKeyMapDiffItem *kmdi;
150
151     for (kmi = km->items.first; kmi; kmi = kmi->next) {
152       wm_keymap_item_properties_update_ot(kmi);
153     }
154
155     for (kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) {
156       if (kmdi->add_item) {
157         wm_keymap_item_properties_update_ot(kmdi->add_item);
158       }
159       if (kmdi->remove_item) {
160         wm_keymap_item_properties_update_ot(kmdi->remove_item);
161       }
162     }
163   }
164 }
165
166 static bool wm_keymap_item_equals_result(wmKeyMapItem *a, wmKeyMapItem *b)
167 {
168   return (STREQ(a->idname, b->idname) &&
169           /* We do not really care about which Main we pass here, tbh. */
170           RNA_struct_equals(G_MAIN, a->ptr, b->ptr, RNA_EQ_UNSET_MATCH_NONE) &&
171           (a->flag & KMI_INACTIVE) == (b->flag & KMI_INACTIVE) && a->propvalue == b->propvalue);
172 }
173
174 static bool wm_keymap_item_equals(wmKeyMapItem *a, wmKeyMapItem *b)
175 {
176   return (wm_keymap_item_equals_result(a, b) && a->type == b->type && a->val == b->val &&
177           a->shift == b->shift && a->ctrl == b->ctrl && a->alt == b->alt && a->oskey == b->oskey &&
178           a->keymodifier == b->keymodifier && a->maptype == b->maptype);
179 }
180
181 /* properties can be NULL, otherwise the arg passed is used and ownership is given to the kmi */
182 void WM_keymap_properties_reset(wmKeyMapItem *kmi, struct IDProperty *properties)
183 {
184   if (LIKELY(kmi->ptr)) {
185     WM_operator_properties_free(kmi->ptr);
186     MEM_freeN(kmi->ptr);
187
188     kmi->ptr = NULL;
189   }
190
191   kmi->properties = properties;
192
193   wm_keymap_item_properties_set(kmi);
194 }
195
196 int WM_keymap_map_type_get(wmKeyMapItem *kmi)
197 {
198   if (ISTIMER(kmi->type)) {
199     return KMI_TYPE_TIMER;
200   }
201   if (ISKEYBOARD(kmi->type)) {
202     return KMI_TYPE_KEYBOARD;
203   }
204   if (ISTWEAK(kmi->type)) {
205     return KMI_TYPE_TWEAK;
206   }
207   if (ISMOUSE(kmi->type)) {
208     return KMI_TYPE_MOUSE;
209   }
210   if (ISNDOF(kmi->type)) {
211     return KMI_TYPE_NDOF;
212   }
213   if (kmi->type == KM_TEXTINPUT) {
214     return KMI_TYPE_TEXTINPUT;
215   }
216   if (ELEM(kmi->type, TABLET_STYLUS, TABLET_ERASER)) {
217     return KMI_TYPE_MOUSE;
218   }
219   return KMI_TYPE_KEYBOARD;
220 }
221
222 /**************************** Keymap Diff Item *********************************
223  * Item in a diff keymap, used for saving diff of keymaps in user preferences */
224
225 static wmKeyMapDiffItem *wm_keymap_diff_item_copy(wmKeyMapDiffItem *kmdi)
226 {
227   wmKeyMapDiffItem *kmdin = MEM_dupallocN(kmdi);
228
229   kmdin->next = kmdin->prev = NULL;
230   if (kmdi->add_item) {
231     kmdin->add_item = wm_keymap_item_copy(kmdi->add_item);
232   }
233   if (kmdi->remove_item) {
234     kmdin->remove_item = wm_keymap_item_copy(kmdi->remove_item);
235   }
236
237   return kmdin;
238 }
239
240 static void wm_keymap_diff_item_free(wmKeyMapDiffItem *kmdi)
241 {
242   if (kmdi->remove_item) {
243     wm_keymap_item_free(kmdi->remove_item);
244     MEM_freeN(kmdi->remove_item);
245   }
246   if (kmdi->add_item) {
247     wm_keymap_item_free(kmdi->add_item);
248     MEM_freeN(kmdi->add_item);
249   }
250 }
251
252 /***************************** Key Configuration ******************************
253  * List of keymaps for all editors, modes, ... . There is a builtin default key
254  * configuration, a user key configuration, and other preset configurations. */
255
256 wmKeyConfig *WM_keyconfig_new(wmWindowManager *wm, const char *idname, bool user_defined)
257 {
258   wmKeyConfig *keyconf = BLI_findstring(&wm->keyconfigs, idname, offsetof(wmKeyConfig, idname));
259   if (keyconf) {
260     if (keyconf == wm->defaultconf) {
261       /* For default configuration, we need to keep keymap
262        * modal items and poll functions intact. */
263       for (wmKeyMap *km = keyconf->keymaps.first; km; km = km->next) {
264         WM_keymap_clear(km);
265       }
266     }
267     else {
268       /* For user defined key configuration, clear all keymaps. */
269       WM_keyconfig_clear(keyconf);
270     }
271
272     return keyconf;
273   }
274
275   /* Create new configuration. */
276   keyconf = MEM_callocN(sizeof(wmKeyConfig), "wmKeyConfig");
277   BLI_strncpy(keyconf->idname, idname, sizeof(keyconf->idname));
278   BLI_addtail(&wm->keyconfigs, keyconf);
279
280   if (user_defined) {
281     keyconf->flag |= KEYCONF_USER;
282   }
283
284   return keyconf;
285 }
286
287 wmKeyConfig *WM_keyconfig_new_user(wmWindowManager *wm, const char *idname)
288 {
289   return WM_keyconfig_new(wm, idname, true);
290 }
291
292 bool WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf)
293 {
294   if (BLI_findindex(&wm->keyconfigs, keyconf) != -1) {
295     if (STREQLEN(U.keyconfigstr, keyconf->idname, sizeof(U.keyconfigstr))) {
296       BLI_strncpy(U.keyconfigstr, wm->defaultconf->idname, sizeof(U.keyconfigstr));
297       WM_keyconfig_update_tag(NULL, NULL);
298     }
299
300     BLI_remlink(&wm->keyconfigs, keyconf);
301     WM_keyconfig_free(keyconf);
302
303     return true;
304   }
305   else {
306     return false;
307   }
308 }
309
310 void WM_keyconfig_clear(wmKeyConfig *keyconf)
311 {
312   for (wmKeyMap *km = keyconf->keymaps.first; km; km = km->next) {
313     WM_keymap_clear(km);
314   }
315
316   BLI_freelistN(&keyconf->keymaps);
317 }
318
319 void WM_keyconfig_free(wmKeyConfig *keyconf)
320 {
321   WM_keyconfig_clear(keyconf);
322   MEM_freeN(keyconf);
323 }
324
325 static wmKeyConfig *WM_keyconfig_active(wmWindowManager *wm)
326 {
327   wmKeyConfig *keyconf;
328
329   /* first try from preset */
330   keyconf = BLI_findstring(&wm->keyconfigs, U.keyconfigstr, offsetof(wmKeyConfig, idname));
331   if (keyconf) {
332     return keyconf;
333   }
334
335   /* otherwise use default */
336   return wm->defaultconf;
337 }
338
339 void WM_keyconfig_set_active(wmWindowManager *wm, const char *idname)
340 {
341   /* setting a different key configuration as active: we ensure all is
342    * updated properly before and after making the change */
343
344   WM_keyconfig_update(wm);
345
346   BLI_strncpy(U.keyconfigstr, idname, sizeof(U.keyconfigstr));
347
348   WM_keyconfig_update_tag(NULL, NULL);
349   WM_keyconfig_update(wm);
350 }
351
352 /********************************** Keymap *************************************
353  * List of keymap items for one editor, mode, modal operator, ... */
354
355 static wmKeyMap *wm_keymap_new(const char *idname, int spaceid, int regionid)
356 {
357   wmKeyMap *km = MEM_callocN(sizeof(struct wmKeyMap), "keymap list");
358
359   BLI_strncpy(km->idname, idname, KMAP_MAX_NAME);
360   km->spaceid = spaceid;
361   km->regionid = regionid;
362
363   {
364     const char *owner_id = RNA_struct_state_owner_get();
365     if (owner_id) {
366       BLI_strncpy(km->owner_id, owner_id, sizeof(km->owner_id));
367     }
368   }
369   return km;
370 }
371
372 static wmKeyMap *wm_keymap_copy(wmKeyMap *keymap)
373 {
374   wmKeyMap *keymapn = MEM_dupallocN(keymap);
375   wmKeyMapItem *kmi, *kmin;
376   wmKeyMapDiffItem *kmdi, *kmdin;
377
378   keymapn->modal_items = keymap->modal_items;
379   keymapn->poll = keymap->poll;
380   keymapn->poll_modal_item = keymap->poll_modal_item;
381   BLI_listbase_clear(&keymapn->items);
382   keymapn->flag &= ~(KEYMAP_UPDATE | KEYMAP_EXPANDED);
383
384   for (kmdi = keymap->diff_items.first; kmdi; kmdi = kmdi->next) {
385     kmdin = wm_keymap_diff_item_copy(kmdi);
386     BLI_addtail(&keymapn->items, kmdin);
387   }
388
389   for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
390     kmin = wm_keymap_item_copy(kmi);
391     BLI_addtail(&keymapn->items, kmin);
392   }
393
394   return keymapn;
395 }
396
397 void WM_keymap_clear(wmKeyMap *keymap)
398 {
399   wmKeyMapItem *kmi;
400   wmKeyMapDiffItem *kmdi;
401
402   for (kmdi = keymap->diff_items.first; kmdi; kmdi = kmdi->next) {
403     wm_keymap_diff_item_free(kmdi);
404   }
405
406   for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
407     wm_keymap_item_free(kmi);
408   }
409
410   BLI_freelistN(&keymap->diff_items);
411   BLI_freelistN(&keymap->items);
412 }
413
414 bool WM_keymap_remove(wmKeyConfig *keyconf, wmKeyMap *keymap)
415 {
416   if (BLI_findindex(&keyconf->keymaps, keymap) != -1) {
417
418     WM_keymap_clear(keymap);
419     BLI_remlink(&keyconf->keymaps, keymap);
420     MEM_freeN(keymap);
421
422     return true;
423   }
424   else {
425     return false;
426   }
427 }
428
429 bool WM_keymap_poll(bContext *C, wmKeyMap *keymap)
430 {
431   /* If we're tagged, only use compatible. */
432   if (keymap->owner_id[0] != '\0') {
433     const WorkSpace *workspace = CTX_wm_workspace(C);
434     if (BKE_workspace_owner_id_check(workspace, keymap->owner_id) == false) {
435       return false;
436     }
437   }
438
439   if (UNLIKELY(BLI_listbase_is_empty(&keymap->items))) {
440     /* Empty key-maps may be missing more there may be a typo in the name.
441      * Warn early to avoid loosing time investigating each case. */
442     CLOG_WARN(WM_LOG_KEYMAPS, "empty keymap '%s'", keymap->idname);
443   }
444
445   if (keymap->poll != NULL) {
446     return keymap->poll(C);
447   }
448   return true;
449 }
450
451 static void keymap_event_set(
452     wmKeyMapItem *kmi, short type, short val, int modifier, short keymodifier)
453 {
454   kmi->type = type;
455   kmi->val = val;
456   kmi->keymodifier = keymodifier;
457
458   if (modifier == KM_ANY) {
459     kmi->shift = kmi->ctrl = kmi->alt = kmi->oskey = KM_ANY;
460   }
461   else {
462     kmi->shift = (modifier & KM_SHIFT) ? KM_MOD_FIRST :
463                                          ((modifier & KM_SHIFT2) ? KM_MOD_SECOND : false);
464     kmi->ctrl = (modifier & KM_CTRL) ? KM_MOD_FIRST :
465                                        ((modifier & KM_CTRL2) ? KM_MOD_SECOND : false);
466     kmi->alt = (modifier & KM_ALT) ? KM_MOD_FIRST : ((modifier & KM_ALT2) ? KM_MOD_SECOND : false);
467     kmi->oskey = (modifier & KM_OSKEY) ? KM_MOD_FIRST :
468                                          ((modifier & KM_OSKEY2) ? KM_MOD_SECOND : false);
469   }
470 }
471
472 static void keymap_item_set_id(wmKeyMap *keymap, wmKeyMapItem *kmi)
473 {
474   keymap->kmi_id++;
475   if ((keymap->flag & KEYMAP_USER) == 0) {
476     kmi->id = keymap->kmi_id;
477   }
478   else {
479     kmi->id = -keymap->kmi_id; /* User defined keymap entries have negative ids */
480   }
481 }
482
483 /* if item was added, then bail out */
484 wmKeyMapItem *WM_keymap_verify_item(
485     wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
486 {
487   wmKeyMapItem *kmi;
488
489   for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
490     if (STREQLEN(kmi->idname, idname, OP_MAX_TYPENAME)) {
491       break;
492     }
493   }
494   if (kmi == NULL) {
495     kmi = MEM_callocN(sizeof(wmKeyMapItem), "keymap entry");
496
497     BLI_addtail(&keymap->items, kmi);
498     BLI_strncpy(kmi->idname, idname, OP_MAX_TYPENAME);
499
500     keymap_item_set_id(keymap, kmi);
501
502     keymap_event_set(kmi, type, val, modifier, keymodifier);
503     wm_keymap_item_properties_set(kmi);
504   }
505   return kmi;
506 }
507
508 /* always add item */
509 wmKeyMapItem *WM_keymap_add_item(
510     wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
511 {
512   wmKeyMapItem *kmi = MEM_callocN(sizeof(wmKeyMapItem), "keymap entry");
513
514   BLI_addtail(&keymap->items, kmi);
515   BLI_strncpy(kmi->idname, idname, OP_MAX_TYPENAME);
516
517   keymap_event_set(kmi, type, val, modifier, keymodifier);
518   wm_keymap_item_properties_set(kmi);
519
520   keymap_item_set_id(keymap, kmi);
521
522   WM_keyconfig_update_tag(keymap, kmi);
523
524   return kmi;
525 }
526
527 wmKeyMapItem *WM_keymap_add_item_copy(struct wmKeyMap *keymap, wmKeyMapItem *kmi_src)
528 {
529   wmKeyMapItem *kmi_dst = wm_keymap_item_copy(kmi_src);
530
531   BLI_addtail(&keymap->items, kmi_dst);
532
533   keymap_item_set_id(keymap, kmi_dst);
534
535   WM_keyconfig_update_tag(keymap, kmi_dst);
536
537   return kmi_dst;
538 }
539
540 bool WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi)
541 {
542   if (BLI_findindex(&keymap->items, kmi) != -1) {
543     if (kmi->ptr) {
544       WM_operator_properties_free(kmi->ptr);
545       MEM_freeN(kmi->ptr);
546     }
547     BLI_freelinkN(&keymap->items, kmi);
548
549     WM_keyconfig_update_tag(keymap, NULL);
550     return true;
551   }
552   else {
553     return false;
554   }
555 }
556
557 /************************** Keymap Diff and Patch ****************************
558  * Rather than saving the entire keymap for user preferences, we only save a
559  * diff so that changes in the defaults get synced. This system is not perfect
560  * but works better than overriding the keymap entirely when only few items
561  * are changed. */
562
563 static void wm_keymap_addon_add(wmKeyMap *keymap, wmKeyMap *addonmap)
564 {
565   wmKeyMapItem *kmi, *kmin;
566
567   for (kmi = addonmap->items.first; kmi; kmi = kmi->next) {
568     kmin = wm_keymap_item_copy(kmi);
569     keymap_item_set_id(keymap, kmin);
570     BLI_addhead(&keymap->items, kmin);
571   }
572 }
573
574 static wmKeyMapItem *wm_keymap_find_item_equals(wmKeyMap *km, wmKeyMapItem *needle)
575 {
576   wmKeyMapItem *kmi;
577
578   for (kmi = km->items.first; kmi; kmi = kmi->next) {
579     if (wm_keymap_item_equals(kmi, needle)) {
580       return kmi;
581     }
582   }
583
584   return NULL;
585 }
586
587 static wmKeyMapItem *wm_keymap_find_item_equals_result(wmKeyMap *km, wmKeyMapItem *needle)
588 {
589   wmKeyMapItem *kmi;
590
591   for (kmi = km->items.first; kmi; kmi = kmi->next) {
592     if (wm_keymap_item_equals_result(kmi, needle)) {
593       return kmi;
594     }
595   }
596
597   return NULL;
598 }
599
600 static void wm_keymap_diff(
601     wmKeyMap *diff_km, wmKeyMap *from_km, wmKeyMap *to_km, wmKeyMap *orig_km, wmKeyMap *addon_km)
602 {
603   wmKeyMapItem *kmi, *to_kmi, *orig_kmi;
604   wmKeyMapDiffItem *kmdi;
605
606   for (kmi = from_km->items.first; kmi; kmi = kmi->next) {
607     to_kmi = WM_keymap_item_find_id(to_km, kmi->id);
608
609     if (!to_kmi) {
610       /* remove item */
611       kmdi = MEM_callocN(sizeof(wmKeyMapDiffItem), "wmKeyMapDiffItem");
612       kmdi->remove_item = wm_keymap_item_copy(kmi);
613       BLI_addtail(&diff_km->diff_items, kmdi);
614     }
615     else if (to_kmi && !wm_keymap_item_equals(kmi, to_kmi)) {
616       /* replace item */
617       kmdi = MEM_callocN(sizeof(wmKeyMapDiffItem), "wmKeyMapDiffItem");
618       kmdi->remove_item = wm_keymap_item_copy(kmi);
619       kmdi->add_item = wm_keymap_item_copy(to_kmi);
620       BLI_addtail(&diff_km->diff_items, kmdi);
621     }
622
623     /* sync expanded flag back to original so we don't loose it on repatch */
624     if (to_kmi) {
625       orig_kmi = WM_keymap_item_find_id(orig_km, kmi->id);
626
627       if (!orig_kmi && addon_km) {
628         orig_kmi = wm_keymap_find_item_equals(addon_km, kmi);
629       }
630
631       if (orig_kmi) {
632         orig_kmi->flag &= ~KMI_EXPANDED;
633         orig_kmi->flag |= (to_kmi->flag & KMI_EXPANDED);
634       }
635     }
636   }
637
638   for (kmi = to_km->items.first; kmi; kmi = kmi->next) {
639     if (kmi->id < 0) {
640       /* add item */
641       kmdi = MEM_callocN(sizeof(wmKeyMapDiffItem), "wmKeyMapDiffItem");
642       kmdi->add_item = wm_keymap_item_copy(kmi);
643       BLI_addtail(&diff_km->diff_items, kmdi);
644     }
645   }
646 }
647
648 static void wm_keymap_patch(wmKeyMap *km, wmKeyMap *diff_km)
649 {
650   wmKeyMapDiffItem *kmdi;
651   wmKeyMapItem *kmi_remove, *kmi_add;
652
653   for (kmdi = diff_km->diff_items.first; kmdi; kmdi = kmdi->next) {
654     /* find item to remove */
655     kmi_remove = NULL;
656     if (kmdi->remove_item) {
657       kmi_remove = wm_keymap_find_item_equals(km, kmdi->remove_item);
658       if (!kmi_remove) {
659         kmi_remove = wm_keymap_find_item_equals_result(km, kmdi->remove_item);
660       }
661     }
662
663     /* add item */
664     if (kmdi->add_item) {
665       /* Do not re-add an already existing keymap item! See T42088. */
666       /* We seek only for exact copy here! See T42137. */
667       kmi_add = wm_keymap_find_item_equals(km, kmdi->add_item);
668
669       /** If kmi_add is same as kmi_remove (can happen in some cases,
670        * typically when we got kmi_remove from #wm_keymap_find_item_equals_result()),
671        * no need to add or remove anything, see T45579. */
672
673       /**
674        * \note This typically happens when we apply user-defined keymap diff to a base one that
675        * was exported with that customized keymap already. In that case:
676        *
677        * - wm_keymap_find_item_equals(km, kmdi->remove_item) finds nothing
678        *   (because actual shortcut of current base does not match kmdi->remove_item any more).
679        * - wm_keymap_find_item_equals_result(km, kmdi->remove_item) finds the current kmi from
680        *   base keymap (because it does exactly the same thing).
681        * - wm_keymap_find_item_equals(km, kmdi->add_item) finds the same kmi,
682        *   since base keymap was exported with that user-defined shortcut already!
683        *
684        *       Maybe we should rather keep user-defined keymaps specific to a given base one? */
685       if (kmi_add != NULL && kmi_add == kmi_remove) {
686         kmi_remove = NULL;
687       }
688       /* only if nothing to remove or item to remove found */
689       else if (!kmi_add && (!kmdi->remove_item || kmi_remove)) {
690         kmi_add = wm_keymap_item_copy(kmdi->add_item);
691         kmi_add->flag |= KMI_USER_MODIFIED;
692
693         if (kmi_remove) {
694           kmi_add->flag &= ~KMI_EXPANDED;
695           kmi_add->flag |= (kmi_remove->flag & KMI_EXPANDED);
696           kmi_add->id = kmi_remove->id;
697           BLI_insertlinkbefore(&km->items, kmi_remove, kmi_add);
698         }
699         else {
700           keymap_item_set_id(km, kmi_add);
701           BLI_addtail(&km->items, kmi_add);
702         }
703       }
704     }
705
706     /* remove item */
707     if (kmi_remove) {
708       wm_keymap_item_free(kmi_remove);
709       BLI_freelinkN(&km->items, kmi_remove);
710     }
711   }
712 }
713
714 static wmKeyMap *wm_keymap_patch_update(ListBase *lb,
715                                         wmKeyMap *defaultmap,
716                                         wmKeyMap *addonmap,
717                                         wmKeyMap *usermap)
718 {
719   wmKeyMap *km;
720   int expanded = 0;
721
722   /* remove previous keymap in list, we will replace it */
723   km = WM_keymap_list_find(lb, defaultmap->idname, defaultmap->spaceid, defaultmap->regionid);
724   if (km) {
725     expanded = (km->flag & (KEYMAP_EXPANDED | KEYMAP_CHILDREN_EXPANDED));
726     WM_keymap_clear(km);
727     BLI_freelinkN(lb, km);
728   }
729
730   /* copy new keymap from an existing one */
731   if (usermap && !(usermap->flag & KEYMAP_DIFF)) {
732     /* for compatibility with old user preferences with non-diff
733      * keymaps we override the original entirely */
734     wmKeyMapItem *kmi, *orig_kmi;
735
736     km = wm_keymap_copy(usermap);
737
738     /* try to find corresponding id's for items */
739     for (kmi = km->items.first; kmi; kmi = kmi->next) {
740       orig_kmi = wm_keymap_find_item_equals(defaultmap, kmi);
741       if (!orig_kmi) {
742         orig_kmi = wm_keymap_find_item_equals_result(defaultmap, kmi);
743       }
744
745       if (orig_kmi) {
746         kmi->id = orig_kmi->id;
747       }
748       else {
749         kmi->id = -(km->kmi_id++);
750       }
751     }
752
753     km->flag |= KEYMAP_UPDATE; /* update again to create diff */
754   }
755   else {
756     km = wm_keymap_copy(defaultmap);
757   }
758
759   /* add addon keymap items */
760   if (addonmap) {
761     wm_keymap_addon_add(km, addonmap);
762   }
763
764   /* tag as being user edited */
765   if (usermap) {
766     km->flag |= KEYMAP_USER_MODIFIED;
767   }
768   km->flag |= KEYMAP_USER | expanded;
769
770   /* apply user changes of diff keymap */
771   if (usermap && (usermap->flag & KEYMAP_DIFF)) {
772     wm_keymap_patch(km, usermap);
773   }
774
775   /* add to list */
776   BLI_addtail(lb, km);
777
778   return km;
779 }
780
781 static void wm_keymap_diff_update(ListBase *lb,
782                                   wmKeyMap *defaultmap,
783                                   wmKeyMap *addonmap,
784                                   wmKeyMap *km)
785 {
786   wmKeyMap *diffmap, *prevmap, *origmap;
787
788   /* create temporary default + addon keymap for diff */
789   origmap = defaultmap;
790
791   if (addonmap) {
792     defaultmap = wm_keymap_copy(defaultmap);
793     wm_keymap_addon_add(defaultmap, addonmap);
794   }
795
796   /* remove previous diff keymap in list, we will replace it */
797   prevmap = WM_keymap_list_find(lb, km->idname, km->spaceid, km->regionid);
798   if (prevmap) {
799     WM_keymap_clear(prevmap);
800     BLI_freelinkN(lb, prevmap);
801   }
802
803   /* create diff keymap */
804   diffmap = wm_keymap_new(km->idname, km->spaceid, km->regionid);
805   diffmap->flag |= KEYMAP_DIFF;
806   if (defaultmap->flag & KEYMAP_MODAL) {
807     diffmap->flag |= KEYMAP_MODAL;
808   }
809   wm_keymap_diff(diffmap, defaultmap, km, origmap, addonmap);
810
811   /* add to list if not empty */
812   if (diffmap->diff_items.first) {
813     BLI_addtail(lb, diffmap);
814   }
815   else {
816     WM_keymap_clear(diffmap);
817     MEM_freeN(diffmap);
818   }
819
820   /* free temporary default map */
821   if (addonmap) {
822     WM_keymap_clear(defaultmap);
823     MEM_freeN(defaultmap);
824   }
825 }
826
827 /* ****************** storage in WM ************ */
828
829 /* name id's are for storing general or multiple keymaps,
830  * space/region ids are same as DNA_space_types.h */
831 /* gets freed in wm.c */
832
833 wmKeyMap *WM_keymap_list_find(ListBase *lb, const char *idname, int spaceid, int regionid)
834 {
835   wmKeyMap *km;
836
837   for (km = lb->first; km; km = km->next) {
838     if (km->spaceid == spaceid && km->regionid == regionid) {
839       if (STREQLEN(idname, km->idname, KMAP_MAX_NAME)) {
840         return km;
841       }
842     }
843   }
844
845   return NULL;
846 }
847
848 wmKeyMap *WM_keymap_list_find_spaceid_or_empty(ListBase *lb,
849                                                const char *idname,
850                                                int spaceid,
851                                                int regionid)
852 {
853   wmKeyMap *km;
854
855   for (km = lb->first; km; km = km->next) {
856     if (ELEM(km->spaceid, spaceid, SPACE_EMPTY) && km->regionid == regionid) {
857       if (STREQLEN(idname, km->idname, KMAP_MAX_NAME)) {
858         return km;
859       }
860     }
861   }
862
863   return NULL;
864 }
865
866 wmKeyMap *WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
867 {
868   wmKeyMap *km = WM_keymap_list_find(&keyconf->keymaps, idname, spaceid, regionid);
869
870   if (km == NULL) {
871     km = wm_keymap_new(idname, spaceid, regionid);
872     BLI_addtail(&keyconf->keymaps, km);
873
874     WM_keyconfig_update_tag(km, NULL);
875   }
876
877   return km;
878 }
879
880 wmKeyMap *WM_keymap_find_all(const bContext *C, const char *idname, int spaceid, int regionid)
881 {
882   wmWindowManager *wm = CTX_wm_manager(C);
883
884   return WM_keymap_list_find(&wm->userconf->keymaps, idname, spaceid, regionid);
885 }
886
887 wmKeyMap *WM_keymap_find_all_spaceid_or_empty(const bContext *C,
888                                               const char *idname,
889                                               int spaceid,
890                                               int regionid)
891 {
892   wmWindowManager *wm = CTX_wm_manager(C);
893
894   return WM_keymap_list_find_spaceid_or_empty(&wm->userconf->keymaps, idname, spaceid, regionid);
895 }
896
897 /* ****************** modal keymaps ************ */
898
899 /* Modal key-maps get linked to a running operator,
900  * and filter the keys before sending to modal() callback. */
901
902 wmKeyMap *WM_modalkeymap_add(wmKeyConfig *keyconf,
903                              const char *idname,
904                              const EnumPropertyItem *items)
905 {
906   wmKeyMap *km = WM_keymap_ensure(keyconf, idname, 0, 0);
907   km->flag |= KEYMAP_MODAL;
908
909   /* init modal items from default config */
910   wmWindowManager *wm = G_MAIN->wm.first;
911   if (wm->defaultconf && wm->defaultconf != keyconf) {
912     wmKeyMap *defaultkm = WM_keymap_list_find(&wm->defaultconf->keymaps, km->idname, 0, 0);
913
914     if (defaultkm) {
915       km->modal_items = defaultkm->modal_items;
916       km->poll = defaultkm->poll;
917       km->poll_modal_item = defaultkm->poll_modal_item;
918     }
919   }
920
921   if (items) {
922     km->modal_items = items;
923   }
924
925   return km;
926 }
927
928 wmKeyMap *WM_modalkeymap_get(wmKeyConfig *keyconf, const char *idname)
929 {
930   wmKeyMap *km;
931
932   for (km = keyconf->keymaps.first; km; km = km->next) {
933     if (km->flag & KEYMAP_MODAL) {
934       if (STREQLEN(idname, km->idname, KMAP_MAX_NAME)) {
935         break;
936       }
937     }
938   }
939
940   return km;
941 }
942
943 wmKeyMapItem *WM_modalkeymap_add_item(
944     wmKeyMap *km, int type, int val, int modifier, int keymodifier, int value)
945 {
946   wmKeyMapItem *kmi = MEM_callocN(sizeof(wmKeyMapItem), "keymap entry");
947
948   BLI_addtail(&km->items, kmi);
949   kmi->propvalue = value;
950
951   keymap_event_set(kmi, type, val, modifier, keymodifier);
952
953   keymap_item_set_id(km, kmi);
954
955   WM_keyconfig_update_tag(km, kmi);
956
957   return kmi;
958 }
959
960 wmKeyMapItem *WM_modalkeymap_add_item_str(
961     wmKeyMap *km, int type, int val, int modifier, int keymodifier, const char *value)
962 {
963   wmKeyMapItem *kmi = MEM_callocN(sizeof(wmKeyMapItem), "keymap entry");
964
965   BLI_addtail(&km->items, kmi);
966   BLI_strncpy(kmi->propvalue_str, value, sizeof(kmi->propvalue_str));
967
968   keymap_event_set(kmi, type, val, modifier, keymodifier);
969
970   keymap_item_set_id(km, kmi);
971
972   WM_keyconfig_update_tag(km, kmi);
973
974   return kmi;
975 }
976
977 static wmKeyMapItem *wm_modalkeymap_find_propvalue_iter(wmKeyMap *km,
978                                                         wmKeyMapItem *kmi,
979                                                         const int propvalue)
980 {
981   if (km->flag & KEYMAP_MODAL) {
982     kmi = kmi ? kmi->next : km->items.first;
983     for (; kmi; kmi = kmi->next) {
984       if (kmi->propvalue == propvalue) {
985         return kmi;
986       }
987     }
988   }
989   else {
990     BLI_assert(!"called with non modal keymap");
991   }
992
993   return NULL;
994 }
995
996 wmKeyMapItem *WM_modalkeymap_find_propvalue(wmKeyMap *km, const int propvalue)
997 {
998   return wm_modalkeymap_find_propvalue_iter(km, NULL, propvalue);
999 }
1000
1001 void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
1002 {
1003   wmOperatorType *ot = WM_operatortype_find(opname, 0);
1004
1005   if (ot) {
1006     ot->modalkeymap = km;
1007   }
1008   else {
1009     CLOG_ERROR(WM_LOG_KEYMAPS, "unknown operator '%s'", opname);
1010   }
1011 }
1012
1013 static void wm_user_modal_keymap_set_items(wmWindowManager *wm, wmKeyMap *km)
1014 {
1015   /* here we convert propvalue string values delayed, due to python keymaps
1016    * being created before the actual modal keymaps, so no modal_items */
1017   wmKeyMap *defaultkm;
1018   wmKeyMapItem *kmi;
1019   int propvalue;
1020
1021   if (km && (km->flag & KEYMAP_MODAL) && !km->modal_items) {
1022     if (wm->defaultconf == NULL) {
1023       return;
1024     }
1025
1026     defaultkm = WM_keymap_list_find(&wm->defaultconf->keymaps, km->idname, 0, 0);
1027
1028     if (!defaultkm) {
1029       return;
1030     }
1031
1032     km->modal_items = defaultkm->modal_items;
1033     km->poll = defaultkm->poll;
1034     km->poll_modal_item = defaultkm->poll_modal_item;
1035
1036     if (km->modal_items) {
1037       for (kmi = km->items.first; kmi; kmi = kmi->next) {
1038         if (kmi->propvalue_str[0]) {
1039           if (RNA_enum_value_from_id(km->modal_items, kmi->propvalue_str, &propvalue)) {
1040             kmi->propvalue = propvalue;
1041           }
1042           kmi->propvalue_str[0] = '\0';
1043         }
1044       }
1045     }
1046   }
1047 }
1048
1049 /* ***************** get string from key events **************** */
1050
1051 const char *WM_key_event_string(const short type, const bool compact)
1052 {
1053   const EnumPropertyItem *it;
1054   const int i = RNA_enum_from_value(rna_enum_event_type_items, (int)type);
1055
1056   if (i == -1) {
1057     return "";
1058   }
1059   it = &rna_enum_event_type_items[i];
1060
1061   /* We first try enum items' description (abused as shortname here),
1062    * and fall back to usual name if empty. */
1063   if (compact && it->description[0]) {
1064     /* XXX No context for enum descriptions... In practice shall not be an issue though. */
1065     return IFACE_(it->description);
1066   }
1067
1068   return CTX_IFACE_(BLT_I18NCONTEXT_UI_EVENTS, it->name);
1069 }
1070
1071 /* TODO: also support (some) value, like e.g. double-click? */
1072 int WM_keymap_item_raw_to_string(const short shift,
1073                                  const short ctrl,
1074                                  const short alt,
1075                                  const short oskey,
1076                                  const short keymodifier,
1077                                  const short val,
1078                                  const short type,
1079                                  const bool compact,
1080                                  char *result,
1081                                  const int result_len)
1082 {
1083 #define ADD_SEP \
1084   if (p != buf) \
1085     *p++ = ' '; \
1086   (void)0
1087
1088   char buf[128];
1089   char *p = buf;
1090
1091   buf[0] = '\0';
1092
1093   /* TODO: support order (KM_SHIFT vs. KM_SHIFT2) ? */
1094   if (shift == KM_ANY && ctrl == KM_ANY && alt == KM_ANY && oskey == KM_ANY) {
1095     /* Don't show anything for any mapping. */
1096   }
1097   else {
1098     if (shift) {
1099       ADD_SEP;
1100       p += BLI_strcpy_rlen(p, IFACE_("Shift"));
1101     }
1102
1103     if (ctrl) {
1104       ADD_SEP;
1105       p += BLI_strcpy_rlen(p, IFACE_("Ctrl"));
1106     }
1107
1108     if (alt) {
1109       ADD_SEP;
1110       p += BLI_strcpy_rlen(p, IFACE_("Alt"));
1111     }
1112
1113     if (oskey) {
1114       ADD_SEP;
1115       p += BLI_strcpy_rlen(p, IFACE_("Cmd"));
1116     }
1117   }
1118
1119   if (keymodifier) {
1120     ADD_SEP;
1121     p += BLI_strcpy_rlen(p, WM_key_event_string(keymodifier, compact));
1122   }
1123
1124   if (type) {
1125     ADD_SEP;
1126     if (val == KM_DBL_CLICK) {
1127       p += BLI_strcpy_rlen(p, IFACE_("dbl-"));
1128     }
1129     p += BLI_strcpy_rlen(p, WM_key_event_string(type, compact));
1130   }
1131
1132   /* We assume size of buf is enough to always store any possible shortcut,
1133    * but let's add a debug check about it! */
1134   BLI_assert(p - buf < sizeof(buf));
1135
1136   /* We need utf8 here, otherwise we may 'cut' some unicode chars like arrows... */
1137   return BLI_strncpy_utf8_rlen(result, buf, result_len);
1138
1139 #undef ADD_SEP
1140 }
1141
1142 int WM_keymap_item_to_string(wmKeyMapItem *kmi,
1143                              const bool compact,
1144                              char *result,
1145                              const int result_len)
1146 {
1147   return WM_keymap_item_raw_to_string(kmi->shift,
1148                                       kmi->ctrl,
1149                                       kmi->alt,
1150                                       kmi->oskey,
1151                                       kmi->keymodifier,
1152                                       kmi->val,
1153                                       kmi->type,
1154                                       compact,
1155                                       result,
1156                                       result_len);
1157 }
1158
1159 int WM_modalkeymap_items_to_string(
1160     wmKeyMap *km, const int propvalue, const bool compact, char *result, const int result_len)
1161 {
1162   int totlen = 0;
1163   bool add_sep = false;
1164
1165   if (km) {
1166     wmKeyMapItem *kmi;
1167
1168     /* Find all shortcuts related to that propvalue! */
1169     for (kmi = WM_modalkeymap_find_propvalue(km, propvalue); kmi && totlen < (result_len - 2);
1170          kmi = wm_modalkeymap_find_propvalue_iter(km, kmi, propvalue)) {
1171       if (add_sep) {
1172         result[totlen++] = '/';
1173         result[totlen] = '\0';
1174       }
1175       else {
1176         add_sep = true;
1177       }
1178       totlen += WM_keymap_item_to_string(kmi, compact, &result[totlen], result_len - totlen);
1179     }
1180   }
1181
1182   return totlen;
1183 }
1184
1185 int WM_modalkeymap_operator_items_to_string(wmOperatorType *ot,
1186                                             const int propvalue,
1187                                             const bool compact,
1188                                             char *result,
1189                                             const int result_len)
1190 {
1191   return WM_modalkeymap_items_to_string(ot->modalkeymap, propvalue, compact, result, result_len);
1192 }
1193
1194 char *WM_modalkeymap_operator_items_to_string_buf(wmOperatorType *ot,
1195                                                   const int propvalue,
1196                                                   const bool compact,
1197                                                   const int max_len,
1198                                                   int *r_available_len,
1199                                                   char **r_result)
1200 {
1201   char *ret = *r_result;
1202
1203   if (*r_available_len > 1) {
1204     int used_len = WM_modalkeymap_operator_items_to_string(
1205                        ot, propvalue, compact, ret, min_ii(*r_available_len, max_len)) +
1206                    1;
1207
1208     *r_available_len -= used_len;
1209     *r_result += used_len;
1210     if (*r_available_len == 0) {
1211       (*r_result)--; /* So that *result keeps pointing on a valid char, we'll stay on it anyway. */
1212     }
1213   }
1214   else {
1215     *ret = '\0';
1216   }
1217
1218   return ret;
1219 }
1220
1221 static wmKeyMapItem *wm_keymap_item_find_in_keymap(wmKeyMap *keymap,
1222                                                    const char *opname,
1223                                                    IDProperty *properties,
1224                                                    const bool is_strict,
1225                                                    const struct wmKeyMapItemFind_Params *params)
1226 {
1227   for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
1228     /* skip disabled keymap items [T38447] */
1229     if (kmi->flag & KMI_INACTIVE) {
1230       continue;
1231     }
1232
1233     bool kmi_match = false;
1234
1235     if (STREQ(kmi->idname, opname)) {
1236       if (properties) {
1237         /* example of debugging keymaps */
1238 #if 0
1239         if (kmi->ptr) {
1240           if (STREQ("MESH_OT_rip_move", opname)) {
1241             printf("OPERATOR\n");
1242             IDP_print(properties);
1243             printf("KEYMAP\n");
1244             IDP_print(kmi->ptr->data);
1245           }
1246         }
1247 #endif
1248
1249         if (kmi->ptr && IDP_EqualsProperties_ex(properties, kmi->ptr->data, is_strict)) {
1250           kmi_match = true;
1251         }
1252         /* Debug only, helps spotting mismatches between menu entries and shortcuts! */
1253         else if (G.debug & G_DEBUG_WM) {
1254           if (is_strict && kmi->ptr) {
1255             wmOperatorType *ot = WM_operatortype_find(opname, true);
1256             if (ot) {
1257               /* make a copy of the properties and set unset ones to their default values. */
1258               PointerRNA opptr;
1259               IDProperty *properties_default = IDP_CopyProperty(kmi->ptr->data);
1260
1261               RNA_pointer_create(NULL, ot->srna, properties_default, &opptr);
1262               WM_operator_properties_default(&opptr, true);
1263
1264               if (IDP_EqualsProperties_ex(properties, properties_default, is_strict)) {
1265                 char kmi_str[128];
1266                 WM_keymap_item_to_string(kmi, false, kmi_str, sizeof(kmi_str));
1267                 /* Note gievn properties could come from other things than menu entry... */
1268                 printf(
1269                     "%s: Some set values in menu entry match default op values, "
1270                     "this might not be desired!\n",
1271                     opname);
1272                 printf("\tkm: '%s', kmi: '%s'\n", keymap->idname, kmi_str);
1273 #ifndef NDEBUG
1274 #  ifdef WITH_PYTHON
1275                 printf("OPERATOR\n");
1276                 IDP_print(properties);
1277                 printf("KEYMAP\n");
1278                 IDP_print(kmi->ptr->data);
1279 #  endif
1280 #endif
1281                 printf("\n");
1282               }
1283
1284               IDP_FreeProperty(properties_default);
1285               MEM_freeN(properties_default);
1286             }
1287           }
1288         }
1289       }
1290       else {
1291         kmi_match = true;
1292       }
1293
1294       if (kmi_match) {
1295         if ((params == NULL) || params->filter_fn(keymap, kmi, params->user_data)) {
1296           return kmi;
1297         }
1298       }
1299     }
1300   }
1301   return NULL;
1302 }
1303
1304 static wmKeyMapItem *wm_keymap_item_find_handlers(const bContext *C,
1305                                                   ListBase *handlers,
1306                                                   const char *opname,
1307                                                   int UNUSED(opcontext),
1308                                                   IDProperty *properties,
1309                                                   const bool is_strict,
1310                                                   const struct wmKeyMapItemFind_Params *params,
1311                                                   wmKeyMap **r_keymap)
1312 {
1313   wmWindowManager *wm = CTX_wm_manager(C);
1314
1315   /* find keymap item in handlers */
1316   LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
1317     if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
1318       wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
1319       wmKeyMap *keymap = WM_event_get_keymap_from_handler(wm, handler);
1320       if (keymap && WM_keymap_poll((bContext *)C, keymap)) {
1321         wmKeyMapItem *kmi = wm_keymap_item_find_in_keymap(
1322             keymap, opname, properties, is_strict, params);
1323         if (kmi != NULL) {
1324           if (r_keymap) {
1325             *r_keymap = keymap;
1326           }
1327           return kmi;
1328         }
1329       }
1330     }
1331   }
1332   /* ensure un-initialized keymap is never used */
1333   if (r_keymap) {
1334     *r_keymap = NULL;
1335   }
1336   return NULL;
1337 }
1338
1339 static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C,
1340                                                const char *opname,
1341                                                int opcontext,
1342                                                IDProperty *properties,
1343                                                const bool is_strict,
1344                                                const struct wmKeyMapItemFind_Params *params,
1345                                                wmKeyMap **r_keymap)
1346 {
1347   wmWindow *win = CTX_wm_window(C);
1348   ScrArea *sa = CTX_wm_area(C);
1349   ARegion *ar = CTX_wm_region(C);
1350   wmKeyMapItem *found = NULL;
1351
1352   /* look into multiple handler lists to find the item */
1353   if (win) {
1354     found = wm_keymap_item_find_handlers(
1355         C, &win->modalhandlers, opname, opcontext, properties, is_strict, params, r_keymap);
1356     if (found == NULL) {
1357       found = wm_keymap_item_find_handlers(
1358           C, &win->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
1359     }
1360   }
1361
1362   if (sa && found == NULL) {
1363     found = wm_keymap_item_find_handlers(
1364         C, &sa->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
1365   }
1366
1367   if (found == NULL) {
1368     if (ELEM(opcontext, WM_OP_EXEC_REGION_WIN, WM_OP_INVOKE_REGION_WIN)) {
1369       if (sa) {
1370         if (!(ar && ar->regiontype == RGN_TYPE_WINDOW)) {
1371           ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
1372         }
1373
1374         if (ar) {
1375           found = wm_keymap_item_find_handlers(
1376               C, &ar->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
1377         }
1378       }
1379     }
1380     else if (ELEM(opcontext, WM_OP_EXEC_REGION_CHANNELS, WM_OP_INVOKE_REGION_CHANNELS)) {
1381       if (!(ar && ar->regiontype == RGN_TYPE_CHANNELS)) {
1382         ar = BKE_area_find_region_type(sa, RGN_TYPE_CHANNELS);
1383       }
1384
1385       if (ar) {
1386         found = wm_keymap_item_find_handlers(
1387             C, &ar->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
1388       }
1389     }
1390     else if (ELEM(opcontext, WM_OP_EXEC_REGION_PREVIEW, WM_OP_INVOKE_REGION_PREVIEW)) {
1391       if (!(ar && ar->regiontype == RGN_TYPE_PREVIEW)) {
1392         ar = BKE_area_find_region_type(sa, RGN_TYPE_PREVIEW);
1393       }
1394
1395       if (ar) {
1396         found = wm_keymap_item_find_handlers(
1397             C, &ar->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
1398       }
1399     }
1400     else {
1401       if (ar) {
1402         found = wm_keymap_item_find_handlers(
1403             C, &ar->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
1404       }
1405     }
1406   }
1407
1408   return found;
1409 }
1410
1411 static wmKeyMapItem *wm_keymap_item_find(const bContext *C,
1412                                          const char *opname,
1413                                          int opcontext,
1414                                          IDProperty *properties,
1415                                          bool is_strict,
1416                                          const struct wmKeyMapItemFind_Params *params,
1417                                          wmKeyMap **r_keymap)
1418 {
1419   wmKeyMapItem *found;
1420
1421   /* XXX Hack! Macro operators in menu entry have their whole props defined,
1422    * which is not the case for relevant keymap entries.
1423    * Could be good to check and harmonize this,
1424    * but for now always compare non-strict in this case. */
1425   wmOperatorType *ot = WM_operatortype_find(opname, true);
1426   if (ot) {
1427     is_strict = is_strict && ((ot->flag & OPTYPE_MACRO) == 0);
1428   }
1429
1430   found = wm_keymap_item_find_props(C, opname, opcontext, properties, is_strict, params, r_keymap);
1431
1432   /* This block is *only* useful in one case: when op uses an enum menu in its prop member
1433    * (then, we want to rerun a comparison with that 'prop' unset). Note this remains brittle,
1434    * since now any enum prop may be used in UI (specified by name), ot->prop is not so much used...
1435    * Otherwise:
1436    *     * If non-strict, unset properties always match set ones in IDP_EqualsProperties_ex.
1437    *     * If strict, unset properties never match set ones in IDP_EqualsProperties_ex,
1438    *       and we do not want that to change (else we get things like T41757)!
1439    * ...so in either case, re-running a comparison with unset props set to default is useless.
1440    */
1441   if (!found && properties) {
1442     if (ot && ot->prop) { /* XXX Shall we also check ot->prop is actually an enum? */
1443       /* make a copy of the properties and unset the 'ot->prop' one if set. */
1444       PointerRNA opptr;
1445       IDProperty *properties_temp = IDP_CopyProperty(properties);
1446
1447       RNA_pointer_create(NULL, ot->srna, properties_temp, &opptr);
1448
1449       if (RNA_property_is_set(&opptr, ot->prop)) {
1450         /* For operator that has enum menu,
1451          * unset it so its value does not affect comparison result. */
1452         RNA_property_unset(&opptr, ot->prop);
1453
1454         found = wm_keymap_item_find_props(
1455             C, opname, opcontext, properties_temp, is_strict, params, r_keymap);
1456       }
1457
1458       IDP_FreeProperty(properties_temp);
1459       MEM_freeN(properties_temp);
1460     }
1461   }
1462
1463   /* Debug only, helps spotting mismatches between menu entries and shortcuts! */
1464   if (G.debug & G_DEBUG_WM) {
1465     if (!found && is_strict && properties) {
1466       wmKeyMap *km;
1467       wmKeyMapItem *kmi;
1468       if (ot) {
1469         /* make a copy of the properties and set unset ones to their default values. */
1470         PointerRNA opptr;
1471         IDProperty *properties_default = IDP_CopyProperty(properties);
1472
1473         RNA_pointer_create(NULL, ot->srna, properties_default, &opptr);
1474         WM_operator_properties_default(&opptr, true);
1475
1476         kmi = wm_keymap_item_find_props(
1477             C, opname, opcontext, properties_default, is_strict, params, &km);
1478         if (kmi) {
1479           char kmi_str[128];
1480           WM_keymap_item_to_string(kmi, false, kmi_str, sizeof(kmi_str));
1481           printf(
1482               "%s: Some set values in keymap entry match default op values, "
1483               "this might not be desired!\n",
1484               opname);
1485           printf("\tkm: '%s', kmi: '%s'\n", km->idname, kmi_str);
1486 #ifndef NDEBUG
1487 #  ifdef WITH_PYTHON
1488           printf("OPERATOR\n");
1489           IDP_print(properties);
1490           printf("KEYMAP\n");
1491           IDP_print(kmi->ptr->data);
1492 #  endif
1493 #endif
1494           printf("\n");
1495         }
1496
1497         IDP_FreeProperty(properties_default);
1498         MEM_freeN(properties_default);
1499       }
1500     }
1501   }
1502
1503   return found;
1504 }
1505
1506 static bool kmi_filter_is_visible(const wmKeyMap *UNUSED(km),
1507                                   const wmKeyMapItem *kmi,
1508                                   void *UNUSED(user_data))
1509 {
1510   return ((WM_key_event_string(kmi->type, false)[0] != '\0') &&
1511           (IS_EVENT_ACTIONZONE(kmi->type) == false));
1512 }
1513
1514 char *WM_key_event_operator_string(const bContext *C,
1515                                    const char *opname,
1516                                    int opcontext,
1517                                    IDProperty *properties,
1518                                    const bool is_strict,
1519                                    char *result,
1520                                    const int result_len)
1521 {
1522   wmKeyMapItem *kmi = wm_keymap_item_find(C,
1523                                           opname,
1524                                           opcontext,
1525                                           properties,
1526                                           is_strict,
1527                                           &(struct wmKeyMapItemFind_Params){
1528                                               .filter_fn = kmi_filter_is_visible,
1529                                               .user_data = NULL,
1530                                           },
1531                                           NULL);
1532   if (kmi) {
1533     WM_keymap_item_to_string(kmi, false, result, result_len);
1534     return result;
1535   }
1536
1537   return NULL;
1538 }
1539
1540 static bool kmi_filter_is_visible_type_mask(const wmKeyMap *km,
1541                                             const wmKeyMapItem *kmi,
1542                                             void *user_data)
1543 {
1544   short *mask_pair = user_data;
1545   return ((WM_event_type_mask_test(kmi->type, mask_pair[0]) == true) &&
1546           (WM_event_type_mask_test(kmi->type, mask_pair[1]) == false) &&
1547           kmi_filter_is_visible(km, kmi, user_data));
1548 }
1549
1550 /**
1551  * \param include_mask, exclude_mask:
1552  * Event types to include/exclude when looking up keys (#eEventType_Mask).
1553  */
1554 wmKeyMapItem *WM_key_event_operator(const bContext *C,
1555                                     const char *opname,
1556                                     int opcontext,
1557                                     IDProperty *properties,
1558                                     const short include_mask,
1559                                     const short exclude_mask,
1560                                     wmKeyMap **r_keymap)
1561 {
1562   short user_data_mask[2] = {include_mask, exclude_mask};
1563   bool use_mask = (include_mask != EVT_TYPE_MASK_ALL) || (exclude_mask != 0);
1564   return wm_keymap_item_find(
1565       C,
1566       opname,
1567       opcontext,
1568       properties,
1569       true,
1570       &(struct wmKeyMapItemFind_Params){
1571           .filter_fn = use_mask ? kmi_filter_is_visible_type_mask : kmi_filter_is_visible,
1572           .user_data = use_mask ? user_data_mask : NULL,
1573       },
1574       r_keymap);
1575 }
1576
1577 wmKeyMapItem *WM_key_event_operator_from_keymap(wmKeyMap *keymap,
1578                                                 const char *opname,
1579                                                 IDProperty *properties,
1580                                                 const short include_mask,
1581                                                 const short exclude_mask)
1582 {
1583   short user_data_mask[2] = {include_mask, exclude_mask};
1584   bool use_mask = (include_mask != EVT_TYPE_MASK_ALL) || (exclude_mask != 0);
1585   return wm_keymap_item_find_in_keymap(
1586       keymap,
1587       opname,
1588       properties,
1589       true,
1590       &(struct wmKeyMapItemFind_Params){
1591           .filter_fn = use_mask ? kmi_filter_is_visible_type_mask : kmi_filter_is_visible,
1592           .user_data = use_mask ? user_data_mask : NULL,
1593       });
1594 }
1595
1596 bool WM_keymap_item_compare(wmKeyMapItem *k1, wmKeyMapItem *k2)
1597 {
1598   int k1type, k2type;
1599
1600   if (k1->flag & KMI_INACTIVE || k2->flag & KMI_INACTIVE) {
1601     return 0;
1602   }
1603
1604   /* take event mapping into account */
1605   k1type = WM_userdef_event_map(k1->type);
1606   k2type = WM_userdef_event_map(k2->type);
1607
1608   if (k1type != KM_ANY && k2type != KM_ANY && k1type != k2type) {
1609     return 0;
1610   }
1611
1612   if (k1->val != KM_ANY && k2->val != KM_ANY) {
1613     /* take click, press, release conflict into account */
1614     if (k1->val == KM_CLICK && ELEM(k2->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0) {
1615       return 0;
1616     }
1617     if (k2->val == KM_CLICK && ELEM(k1->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0) {
1618       return 0;
1619     }
1620     if (k1->val != k2->val) {
1621       return 0;
1622     }
1623   }
1624
1625   if (k1->shift != KM_ANY && k2->shift != KM_ANY && k1->shift != k2->shift) {
1626     return 0;
1627   }
1628
1629   if (k1->ctrl != KM_ANY && k2->ctrl != KM_ANY && k1->ctrl != k2->ctrl) {
1630     return 0;
1631   }
1632
1633   if (k1->alt != KM_ANY && k2->alt != KM_ANY && k1->alt != k2->alt) {
1634     return 0;
1635   }
1636
1637   if (k1->oskey != KM_ANY && k2->oskey != KM_ANY && k1->oskey != k2->oskey) {
1638     return 0;
1639   }
1640
1641   if (k1->keymodifier != k2->keymodifier) {
1642     return 0;
1643   }
1644
1645   return 1;
1646 }
1647
1648 /************************* Update Final Configuration *************************
1649  * On load or other changes, the final user key configuration is rebuilt from
1650  * the preset, addon and user preferences keymaps. We also test if the final
1651  * configuration changed and write the changes to the user preferences. */
1652
1653 /* so operator removal can trigger update */
1654 enum {
1655   WM_KEYMAP_UPDATE_RECONFIGURE = (1 << 0),
1656
1657   /* ensure all wmKeyMap have their operator types validated after removing an operator */
1658   WM_KEYMAP_UPDATE_OPERATORTYPE = (1 << 1),
1659 };
1660
1661 static char wm_keymap_update_flag = 0;
1662
1663 void WM_keyconfig_update_tag(wmKeyMap *km, wmKeyMapItem *kmi)
1664 {
1665   /* quick tag to do delayed keymap updates */
1666   wm_keymap_update_flag |= WM_KEYMAP_UPDATE_RECONFIGURE;
1667
1668   if (km) {
1669     km->flag |= KEYMAP_UPDATE;
1670   }
1671   if (kmi) {
1672     kmi->flag |= KMI_UPDATE;
1673   }
1674 }
1675
1676 void WM_keyconfig_update_operatortype(void)
1677 {
1678   wm_keymap_update_flag |= WM_KEYMAP_UPDATE_OPERATORTYPE;
1679 }
1680
1681 static bool wm_keymap_test_and_clear_update(wmKeyMap *km)
1682 {
1683   wmKeyMapItem *kmi;
1684   int update;
1685
1686   update = (km->flag & KEYMAP_UPDATE);
1687   km->flag &= ~KEYMAP_UPDATE;
1688
1689   for (kmi = km->items.first; kmi; kmi = kmi->next) {
1690     update = update || (kmi->flag & KMI_UPDATE);
1691     kmi->flag &= ~KMI_UPDATE;
1692   }
1693
1694   return (update != 0);
1695 }
1696
1697 static wmKeyMap *wm_keymap_preset(wmWindowManager *wm, wmKeyMap *km)
1698 {
1699   wmKeyConfig *keyconf = WM_keyconfig_active(wm);
1700   wmKeyMap *keymap;
1701
1702   keymap = WM_keymap_list_find(&keyconf->keymaps, km->idname, km->spaceid, km->regionid);
1703   if (!keymap && wm->defaultconf) {
1704     keymap = WM_keymap_list_find(&wm->defaultconf->keymaps, km->idname, km->spaceid, km->regionid);
1705   }
1706
1707   return keymap;
1708 }
1709
1710 void WM_keyconfig_update(wmWindowManager *wm)
1711 {
1712   wmKeyMap *km, *defaultmap, *addonmap, *usermap, *kmn;
1713   wmKeyMapItem *kmi;
1714   wmKeyMapDiffItem *kmdi;
1715   bool compat_update = false;
1716
1717   if (G.background) {
1718     return;
1719   }
1720
1721   if (wm_keymap_update_flag == 0) {
1722     return;
1723   }
1724
1725   if (wm_keymap_update_flag & WM_KEYMAP_UPDATE_OPERATORTYPE) {
1726     /* an operatortype has been removed, this wont happen often
1727      * but when it does we have to check _every_ keymap item */
1728     wmKeyConfig *kc;
1729
1730     ListBase *keymaps_lb[] = {
1731         &U.user_keymaps,
1732         &wm->userconf->keymaps,
1733         &wm->defaultconf->keymaps,
1734         &wm->addonconf->keymaps,
1735         NULL,
1736     };
1737
1738     int i;
1739
1740     for (i = 0; keymaps_lb[i]; i++) {
1741       wm_keyconfig_properties_update_ot(keymaps_lb[i]);
1742     }
1743
1744     for (kc = wm->keyconfigs.first; kc; kc = kc->next) {
1745       wm_keyconfig_properties_update_ot(&kc->keymaps);
1746     }
1747
1748     wm_keymap_update_flag &= ~WM_KEYMAP_UPDATE_OPERATORTYPE;
1749   }
1750
1751   if (wm_keymap_update_flag == 0) {
1752     return;
1753   }
1754
1755   /* update operator properties for non-modal user keymaps */
1756   for (km = U.user_keymaps.first; km; km = km->next) {
1757     if ((km->flag & KEYMAP_MODAL) == 0) {
1758       for (kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) {
1759         if (kmdi->add_item) {
1760           wm_keymap_item_properties_set(kmdi->add_item);
1761         }
1762         if (kmdi->remove_item) {
1763           wm_keymap_item_properties_set(kmdi->remove_item);
1764         }
1765       }
1766
1767       for (kmi = km->items.first; kmi; kmi = kmi->next) {
1768         wm_keymap_item_properties_set(kmi);
1769       }
1770     }
1771   }
1772
1773   /* update U.user_keymaps with user key configuration changes */
1774   for (km = wm->userconf->keymaps.first; km; km = km->next) {
1775     /* only diff if the user keymap was modified */
1776     if (wm_keymap_test_and_clear_update(km)) {
1777       /* find keymaps */
1778       defaultmap = wm_keymap_preset(wm, km);
1779       addonmap = WM_keymap_list_find(
1780           &wm->addonconf->keymaps, km->idname, km->spaceid, km->regionid);
1781
1782       /* diff */
1783       if (defaultmap) {
1784         wm_keymap_diff_update(&U.user_keymaps, defaultmap, addonmap, km);
1785       }
1786     }
1787   }
1788
1789   /* create user key configuration from preset + addon + user preferences */
1790   for (km = wm->defaultconf->keymaps.first; km; km = km->next) {
1791     /* find keymaps */
1792     defaultmap = wm_keymap_preset(wm, km);
1793     addonmap = WM_keymap_list_find(&wm->addonconf->keymaps, km->idname, km->spaceid, km->regionid);
1794     usermap = WM_keymap_list_find(&U.user_keymaps, km->idname, km->spaceid, km->regionid);
1795
1796     wm_user_modal_keymap_set_items(wm, defaultmap);
1797
1798     /* add */
1799     kmn = wm_keymap_patch_update(&wm->userconf->keymaps, defaultmap, addonmap, usermap);
1800
1801     if (kmn) {
1802       kmn->modal_items = km->modal_items;
1803       kmn->poll = km->poll;
1804       kmn->poll_modal_item = km->poll_modal_item;
1805     }
1806
1807     /* in case of old non-diff keymaps, force extra update to create diffs */
1808     compat_update = compat_update || (usermap && !(usermap->flag & KEYMAP_DIFF));
1809   }
1810
1811   wm_keymap_update_flag &= ~WM_KEYMAP_UPDATE_RECONFIGURE;
1812
1813   BLI_assert(wm_keymap_update_flag == 0);
1814
1815   if (compat_update) {
1816     WM_keyconfig_update_tag(NULL, NULL);
1817     WM_keyconfig_update(wm);
1818   }
1819 }
1820
1821 /********************************* Event Handling *****************************
1822  * Handlers have pointers to the keymap in the default configuration. During
1823  * event handling this function is called to get the keymap from the final
1824  * configuration. */
1825
1826 wmKeyMap *WM_keymap_active(wmWindowManager *wm, wmKeyMap *keymap)
1827 {
1828   wmKeyMap *km;
1829
1830   if (!keymap) {
1831     return NULL;
1832   }
1833
1834   /* first user defined keymaps */
1835   km = WM_keymap_list_find(
1836       &wm->userconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
1837
1838   if (km) {
1839     return km;
1840   }
1841
1842   return keymap;
1843 }
1844
1845 /******************************* Keymap Editor ********************************
1846  * In the keymap editor the user key configuration is edited. */
1847
1848 void WM_keymap_restore_item_to_default(bContext *C, wmKeyMap *keymap, wmKeyMapItem *kmi)
1849 {
1850   wmWindowManager *wm = CTX_wm_manager(C);
1851   wmKeyMap *defaultmap, *addonmap;
1852   wmKeyMapItem *orig;
1853
1854   if (!keymap) {
1855     return;
1856   }
1857
1858   /* construct default keymap from preset + addons */
1859   defaultmap = wm_keymap_preset(wm, keymap);
1860   addonmap = WM_keymap_list_find(
1861       &wm->addonconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
1862
1863   if (addonmap) {
1864     defaultmap = wm_keymap_copy(defaultmap);
1865     wm_keymap_addon_add(defaultmap, addonmap);
1866   }
1867
1868   /* find original item */
1869   orig = WM_keymap_item_find_id(defaultmap, kmi->id);
1870
1871   if (orig) {
1872     /* restore to original */
1873     if (!STREQ(orig->idname, kmi->idname)) {
1874       BLI_strncpy(kmi->idname, orig->idname, sizeof(kmi->idname));
1875       WM_keymap_properties_reset(kmi, NULL);
1876     }
1877
1878     if (orig->properties) {
1879       if (kmi->properties) {
1880         IDP_FreeProperty(kmi->properties);
1881         MEM_freeN(kmi->properties);
1882         kmi->properties = NULL;
1883       }
1884
1885       kmi->properties = IDP_CopyProperty(orig->properties);
1886       kmi->ptr->data = kmi->properties;
1887     }
1888
1889     kmi->propvalue = orig->propvalue;
1890     kmi->type = orig->type;
1891     kmi->val = orig->val;
1892     kmi->shift = orig->shift;
1893     kmi->ctrl = orig->ctrl;
1894     kmi->alt = orig->alt;
1895     kmi->oskey = orig->oskey;
1896     kmi->keymodifier = orig->keymodifier;
1897     kmi->maptype = orig->maptype;
1898
1899     WM_keyconfig_update_tag(keymap, kmi);
1900   }
1901
1902   /* free temporary keymap */
1903   if (addonmap) {
1904     WM_keymap_clear(defaultmap);
1905     MEM_freeN(defaultmap);
1906   }
1907 }
1908
1909 void WM_keymap_restore_to_default(wmKeyMap *keymap, bContext *C)
1910 {
1911   wmWindowManager *wm = CTX_wm_manager(C);
1912   wmKeyMap *usermap;
1913
1914   /* remove keymap from U.user_keymaps and update */
1915   usermap = WM_keymap_list_find(
1916       &U.user_keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
1917
1918   if (usermap) {
1919     WM_keymap_clear(usermap);
1920     BLI_freelinkN(&U.user_keymaps, usermap);
1921
1922     WM_keyconfig_update_tag(NULL, NULL);
1923     WM_keyconfig_update(wm);
1924   }
1925 }
1926
1927 wmKeyMapItem *WM_keymap_item_find_id(wmKeyMap *keymap, int id)
1928 {
1929   wmKeyMapItem *kmi;
1930
1931   for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
1932     if (kmi->id == id) {
1933       return kmi;
1934     }
1935   }
1936
1937   return NULL;
1938 }
1939
1940 const char *WM_bool_as_string(bool test)
1941 {
1942   return test ? IFACE_("ON") : IFACE_("OFF");
1943 }