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