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