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